Nobody has started this yet — be first.
Business impact
Any authenticated user -- a free account, a trial signup, anyone who can create an account at all -- can forcibly log out ANY other user's device at will, with no relationship to that account required, just knowledge of a family_id. At minimum this is a denial-of-service tool against specific targets; combined with any way to learn or enumerate family_id values it becomes a targeted account-disruption vector. This is a textbook IDOR (insecure direct object reference) -- the class of vulnerability where an object identifier alone, with no ownership check, is treated as sufficient authorization.
Problem
revoke_session(family_id) checks only that some refresh token exists with this family_id -- RefreshToken.query.filter_by(family_id=family_id).first() is not None -- not that it belongs to g.current_user. Any logged-in caller who supplies a valid family_id belonging to anyone passes this check and gets token_lib.revoke_family() executed against it.
Current behavior
A completely unrelated authenticated user's DELETE /auth/sessions/<victim_family_id> request returns 200 and actually revokes the victim's session.
Expected behavior
DELETE /auth/sessions/<family_id> only succeeds if family_id belongs to the authenticated caller. Otherwise: 404 (not 403 -- consistent with this codebase's convention that GET /auth/sessions never reveals other users' sessions either, making someone else's resource indistinguishable from a nonexistent one).
Steps to reproduce
Why this matters
This is the highest-priority bug in this batch precisely because nothing about its symptom looks alarming in isolation -- the endpoint still returns a normal-looking 200, the request is "valid" by every surface-level measure, and the only way to notice is to specifically check whose session actually got revoked.
Suggested approach
Compare this query against GET /auth/sessions (list_active_sessions) and DELETE /auth/sessions (revoke_all_sessions_for_user) -- both already correctly scope everything to g.current_user.id. The fix is the same shape as the query this function used to have.
Acceptance criteria
Verification
pytest practice_tickets/tests/test_ticket_11.py -v
Hints (0/2)
Try it without hints first — the reading is the exercise.
Working on this ticket
Work on a branch named for the ticket — that's what you'll submit.
Branch off your fork
Sign in to create it automatically, or do it yourself:
$git checkout -b fix/session-revoke-idorFix it and commit
Meet every acceptance criterion, and add a test that would have caught this.
Push the branch
$git push -u origin fix/session-revoke-idorSubmit it below
Paste your fork URL and the branch name, with a short write-up of the root cause.
Questions
Ask about anything unclear in the ticket — the maintainer and anyone who has solved it can answer. Please don't post full solutions.
Sign in to ask a question or reply.
Sign inhttp://localhost:5000make seedpyotpmake docker-prod-upYou do not need Docker running at all to work the tickets -- the test suite uses an in-memory SQLite database (via StaticPool, an isolated DB per test function) and fakeredis (TestingConfig.USE_FAKE_REDIS), so everything runs against a plain virtualenv:
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
pytest practice_tickets/tests/test_ticket_01.py -v # a single ticket
./practice_tickets/run_tickets.sh # all 15, clean pass/fail summary
All 15 tests fail at the start; as you fix each ticket in app/, its test (and only its test) should flip to passing. make test (pytest -q) runs the project's own main suite -- as of writing it shows 9 pre-existing failures caused by ticket bugs 02, 03, 07, 11, and 15; fixing those tickets fixes those failures too, not a separate task. Do not look at git diff / version control history to find the bugs if this repo is ever put under source control -- the point is to find them the way you would find a real bug: from a failing test and a description of broken behavior, not a diff.
Level 1
Fix a bug
Read existing behaviour, correct it.