Problem
When a user pastes a bootstrap PAT on first session, the app immediately mints a controlled short-lived token via _rotate_once(). The bootstrap PAT is then unused but never revoked — it sits as a valid token until it expires naturally.
From app.py:922-924:
# Immediately mint a controlled short-lived token from the user-pasted PAT.
# This gives us a token ID we own — all future rotations can revoke the old one.
# The user-pasted PAT becomes unused after this (expires per its own lifetime).
Expected
After the first successful rotation, actively revoke the bootstrap PAT so there's no accidental token sitting around.
Approach
- Before calling
_rotate_once() in the PAT submission handler, snapshot all existing token IDs via GET /api/2.0/token/list
- After
_rotate_once() succeeds (we now have pat_rotator._current_token_id), revoke all tokens from the snapshot (these are all pre-rotation tokens, including the bootstrap PAT)
- Log clearly what was revoked
This is safe because:
- The snapshot only contains tokens that existed before our fresh mint
- The newly minted token is not in the snapshot
- The app is single-user, so these pre-existing tokens are the user's bootstrap PAT (and possibly stale tokens from previous app runs)
Problem
When a user pastes a bootstrap PAT on first session, the app immediately mints a controlled short-lived token via
_rotate_once(). The bootstrap PAT is then unused but never revoked — it sits as a valid token until it expires naturally.From
app.py:922-924:Expected
After the first successful rotation, actively revoke the bootstrap PAT so there's no accidental token sitting around.
Approach
_rotate_once()in the PAT submission handler, snapshot all existing token IDs viaGET /api/2.0/token/list_rotate_once()succeeds (we now havepat_rotator._current_token_id), revoke all tokens from the snapshot (these are all pre-rotation tokens, including the bootstrap PAT)This is safe because: