Skip to content

fix(security): timing-safe internal-API-key comparison across auth paths (#11006) - #11007

Merged
mrveiss merged 1 commit into
Dev_new_guifrom
issue-11006
Jul 6, 2026
Merged

mrveiss merged 1 commit into
Dev_new_guifrom
issue-11006

Conversation

@mrveiss

@mrveiss mrveiss commented Jul 6, 2026

Copy link
Copy Markdown
Owner

Thinking Path

Automated security review of the merged #10989 fix flagged two items in api/task_workspace_ws.py. On verification against the actual code:

  • Memory-privacy IDOR (flagged HIGH) — false positive. check_admin_permission(request) (auth_middleware.py) is self-contained: it resolves the caller via get_user_from_request(request) with no nested Depends(), so the direct call in _resolve_target_user correctly enforces admin (a non-admin hits raise_auth_error(...403) → denied). No bypass exists.
  • Internal-API-key comparison — real, low-severity hardening. The X-Internal-API-Key path is an intentional, codebase-wide internal-service auth mechanism (Issue fix(personality): save/create fails in SLM admin - JWT mismatch + add new personalities #1145), not a spoofable-field bypass. But the secret was compared with == at 4 sites, a timing side-channel.
  • _validate_ws_origin boolean — correct but confusing. not os.environ.get(...) == "1" is functionally fail-closed but relies on operator precedence.

What Changed

  • New verify_internal_api_key(provided) helper in auth_middleware.py using secrets.compare_digest with None/empty guards (a missing header can never match, and an unset expected key rejects everything — fail-closed).
  • Routed all 4 internal-key checks through the helper (DRY, consistent, constant-time):
    • auth_middleware.py — get_current_user + check_admin_permission
    • api/envelope_secrets.py — service-principal auth
    • api/task_workspace_ws.py — _authenticate_ws_admin
  • Rewrote the WS-origin guard to explicit != "1" for clarity (behaviourally identical, still fail-closed in production).
  • Removed now-unused ssot_config/_ssot imports in the two API modules.

No behavioural change for valid keys or non-admins; only the comparison becomes constant-time.

Verification

  • python -m py_compile — clean on all 3 files.
  • black --check + isort --check-only — clean.
  • flake8 --select=F — 0 (no unused imports / redefinitions after removing the locals).
  • A dedicated unit test isn't feasible: the repo-wide conftest.py stubs auth_middleware as a MagicMock (its real import pulls the full config/Redis chain), so importing the real helper yields a mock in CI too. Behaviour is covered by existing app-level auth/WS smoke tests; the stub gap is tracked under ci: backend unit tests not enforced — stale assertion merged via #10623 undetected #10691.

Model Used

Opus 4.8

Closes #11006. Follow-up hardening to #10989.

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

✅ SSOT Configuration Compliance: Passing

🎉 No hardcoded values detected that have SSOT config equivalents!

@mrveiss
mrveiss merged commit adca476 into Dev_new_gui Jul 6, 2026
30 of 33 checks passed
@mrveiss
mrveiss deleted the issue-11006 branch July 6, 2026 14:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant