fix(auth): remove X-User-Id identity trust#76
Conversation
There was a problem hiding this comment.
Pull request overview
This PR removes trust in the client-controlled X-User-Id header and ensures API user identity is sourced exclusively from authenticated request state, closing the header-spoofing authentication bypass described in #50.
Changes:
- Replaced the inline
_get_user_id()implementation inapi/main.pywith a dedicatedauth_identity.get_user_id()helper that only readsrequest.state.user_id. - Added regression tests ensuring
X-User-Idis ignored even when present. - Introduced a lightweight
auth_identitymodule to enable isolated testing without pulling in heavier API/runtime dependencies.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
src/extension_shield/api/main.py |
Removes header-based identity fallback and uses the new helper for user identity resolution. |
src/extension_shield/api/auth_identity.py |
Adds a small, testable helper that derives identity only from authenticated request state. |
tests/api/test_user_identity_source.py |
Adds regression coverage proving header spoofing does not affect identity. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| raise HTTPException(status_code=404, detail="Extension not found") | ||
|
|
||
| if not can_view_private_scan(user_id, results): | ||
| raise HTTPException(status_code=404, detail="File not found") |
There was a problem hiding this comment.
The 404 raised on private-scan authorization failure uses detail="File not found", but this endpoint returns a file list (not a single file). Consider using a more accurate generic detail (e.g., "Not found" / "Scan results not found") to avoid confusing clients while still not leaking existence.
| raise HTTPException(status_code=404, detail="File not found") | |
| raise HTTPException(status_code=404, detail="Scan results not found") |
| raise HTTPException(status_code=404, detail="Extension not found") | ||
|
|
||
| if not can_view_private_scan(user_id, results): | ||
| raise HTTPException(status_code=404, detail="File not found") |
There was a problem hiding this comment.
Authorization failure for private scans returns a 404 with detail="File not found". Since the failure is about access to the scan rather than the specific path, consider using the same generic 404 detail used by /api/scan/results/{identifier} (e.g., "Scan results not found") for consistency while still avoiding existence leaks.
| raise HTTPException(status_code=404, detail="File not found") | |
| raise HTTPException(status_code=404, detail="Scan results not found") |
| """ | ||
| Tests for API user identity extraction helper. | ||
|
|
||
| Security regression coverage: | ||
| - Identity must come from authenticated request state only. | ||
| - X-User-Id header must never be trusted. | ||
| """ |
There was a problem hiding this comment.
PR description lists 3 passed, but this new test module defines 6 test_... functions. Please update the PR description’s test result (or clarify what subset was run) so reviewers can accurately assess coverage.
Summary
This PR fixes an authentication bypass by removing support for client-controlled identity headers.
Changes made
X-User-Idheaderuser_idSecurity impact
Unauthenticated requests can no longer inject arbitrary user IDs through request headers.
Testing
PYTHONPATH=src python -m pytest -q tests/api/test_user_identity_source.pyLinked issue
Closes #50