fix(security): Remove Dead Auth Guard in Challenge Check & Hint Endpoints#515
Conversation
…ints Fixes GenAI-Security-Project#514 ## Problem POST /api/v1/challenges/{id}/check and POST /api/v1/challenges/{id}/hint both used get_session_context + a manual 'if not session_context: raise 401' guard. Because get_session_context NEVER returns None (it always returns request.state.session_context set by SessionMiddleware), the guard was dead code — always False. Temporary/anonymous sessions passed through freely. Impact: - Any visitor could spam POST /check → inflated attempt counters in DB - Any visitor could spam POST /hint → full hint text revealed without auth ## Fix - Add get_authenticated_session_context to the import in challenges.py - Swap check_challenge and use_hint to Depends(get_authenticated_session_context) - Remove the now-redundant dead 'if not session_context' guards - get_authenticated_session_context raises HTTP 401 automatically when session_context.is_temporary is True (caller hasn't bound an email) GET /api/v1/challenges and GET /api/v1/challenges/{id} are unchanged — they intentionally remain publicly browsable. ## Tests New file: tests/unit/apps/ctf/test_challenge_auth.py (9 tests, all passing) BUG-514-001: temp session rejected on check_challenge PASS BUG-514-002: temp session rejected on use_hint PASS BUG-514-003: auth session not blocked (happy path) PASS BUG-514-004: check_challenge dependency introspection PASS BUG-514-005: use_hint dependency introspection PASS BUG-514-006: dead guard removed from check_challenge source PASS BUG-514-007: dead guard removed from use_hint source PASS BUG-514-008: end-to-end POST /check → HTTP 401 PASS BUG-514-009: end-to-end POST /hint → HTTP 401 PASS
|
Hey @saikishu @e2hln , |
|
Sai, do we want unauthenticated users to be able to get hints? |
Hey @joshlochner , i think there should be a difference between auth and unauth users.. |
fix(security): Remove Dead Auth Guard in Challenge Check & Hint Endpoints
Fixes #514
What's the Problem?
Two endpoints in
finbot/apps/ctf/routes/challenges.pycontain an authenticationguard that can never fire:
The guard reads
if not session_context, butsession_contextis injected viaget_session_contextwhich is defined as:The
SessionMiddlewaresetsrequest.state.session_contextfor every request :including anonymous visitors with no email bound (temporary sessions). So the value
is always a truthy
SessionContextobject. Theif not session_contextconditionevaluates to
False100% of the time, and theHTTPException(401)is never raised.Result: Temporary/unauthenticated sessions bypass the guard on both:
POST /api/v1/challenges/{challenge_id}/check- attempt counters get inflated by throwaway sessionsPOST /api/v1/challenges/{challenge_id}/hint- full hint text is leaked to anyone with a browser cookie, no registration requiredThis is the same class of bug as #511 (sidecar endpoint), but with a different root
cause: a dead
if not Xcheck instead of using the wrong dependency directly.What This PR Does
1. Code Fix :
finbot/apps/ctf/routes/challenges.pySwap the weak
get_session_contextdependency toget_authenticated_session_contexton both write endpoints, and remove the now-redundant dead code guards.
get_authenticated_session_contextraisesHTTP 401 Unauthorizedautomatically whensession_context.is_temporaryisTrue- exactly what the dead guard was supposedto do but never could.
check_challengeendpointuse_hintendpoint@router.post("/challenges/{challenge_id}/hint", response_model=HintResponse) def use_hint( challenge_id: str, - session_context: SessionContext = Depends(get_session_context), + session_context: SessionContext = Depends(get_authenticated_session_context), db: Session = Depends(get_db), ): - if not session_context: - raise HTTPException(status_code=401, detail="Authentication required") ...2. New Test File :
tests/unit/apps/ctf/test_challenge_auth.pyA dedicated unit test file following the exact same pattern as
test_sidecar_auth.py(from PR #512).Approach
@pytest.mark.unit_StubSessionstubget_session_contextif not session_contextlines are gonefastapi.testclient.TestClientFiles Changed
finbot/apps/ctf/routes/challenges.pytests/unit/apps/ctf/test_challenge_auth.pyTotal: 2 files, ~206 lines net change.
Before vs After
POST /api/v1/challenges/{id}/checkPOST /api/v1/challenges/{id}/hintPOST /api/v1/challenges/{id}/checkPOST /api/v1/challenges/{id}/hintRoot Cause vs. Issue #511
get_session_contextinstead ofget_authenticated_session_context)if not session_contextwhich is alwaysFalse)How to Test
Checklist
get_session_context→get_authenticated_session_contextinchallenges.pyif not session_context: raise HTTPException(401)deleted from both functionstest_challenge_auth.pycreated with 9 testsGET /api/v1/challengesandGET /api/v1/challenges/{id}are unchanged (still publicly browsable)Closes #514