Follow-up split out of #2024 (documentation), at the design reviewer's suggestion.
Summary
kirocrew logout is documented in several places as ending all dashboard
sessions. It revokes access sessions only — refresh chains are a separate
mechanism and survive it, so a browser still holding a valid mc_refresh_<port>
cookie can obtain a fresh access cookie afterwards. Restarting the gateway does
not end them either, because the refresh cookie is self-contained and signed with
the persistent token_signing.key.
There is also no global refresh-chain revocation path: revoke_chain is
per-chain, and its only caller is POST /api/auth/logout, which requires the
target browser's own cookie. An operator has no server-side way to terminate a
chain they do not hold.
Why this matters beyond wording
docs/guides/remote-and-mobile.md recommends exposing the loopback dashboard
through a tunnel for phone access, and notes that token IP-pinning is ineffective
there (the pin binds to the tunnel process, which connects from loopback). With
pinning ineffective and rotation extending sessions to a 30-day sliding window,
kirocrew logout was the main remaining server-side control an operator had.
docs/guides/slack-setup.md had this in a token-exposure playbook ("run
kirocrew logout ... if a token is exposed"), so the incident path pointed at a
control that does not do what the reader expects.
Scope of this issue
Docs are already corrected in #2024 — that PR fixes remote-and-mobile.md,
slack-setup.md, dashboard-token-auth.md and cli.md to describe the actual
behaviour and point operators at what does work (revoke at the tunnel/proxy auth
layer, or sign out in that browser). This issue tracks the code change.
Per SECURITY.md this issue deliberately contains no reproduction steps; the
security-relevant detail and impact analysis were sent privately to
kiro-crew-security-support@amazon.com.
Candidate fixes
Two approaches, both small:
- Have
revoke_all_sessions() also revoke refresh chains. Requires enumerating
and marking every known chain, and cannot cover a chain absent from the
persisted state.
- Preferred: include the revocation generation as a claim in the refresh
token payload and reject stale generations during validation. This makes the
existing generation counter authoritative over both cookie types at once,
needs no chain enumeration, reuses an already-persisted value, and fails
closed for chains the state file has never seen.
Either way, kirocrew logout's help text and the doc passages corrected in #2024
should be revisited to match whichever semantics land — three passages in that PR
describe the current limitation and should be simplified once it no longer exists.
Follow-up split out of #2024 (documentation), at the design reviewer's suggestion.
Summary
kirocrew logoutis documented in several places as ending all dashboardsessions. It revokes access sessions only — refresh chains are a separate
mechanism and survive it, so a browser still holding a valid
mc_refresh_<port>cookie can obtain a fresh access cookie afterwards. Restarting the gateway does
not end them either, because the refresh cookie is self-contained and signed with
the persistent
token_signing.key.There is also no global refresh-chain revocation path:
revoke_chainisper-chain, and its only caller is
POST /api/auth/logout, which requires thetarget browser's own cookie. An operator has no server-side way to terminate a
chain they do not hold.
Why this matters beyond wording
docs/guides/remote-and-mobile.mdrecommends exposing the loopback dashboardthrough a tunnel for phone access, and notes that token IP-pinning is ineffective
there (the pin binds to the tunnel process, which connects from loopback). With
pinning ineffective and rotation extending sessions to a 30-day sliding window,
kirocrew logoutwas the main remaining server-side control an operator had.docs/guides/slack-setup.mdhad this in a token-exposure playbook ("runkirocrew logout... if a token is exposed"), so the incident path pointed at acontrol that does not do what the reader expects.
Scope of this issue
Docs are already corrected in #2024 — that PR fixes
remote-and-mobile.md,slack-setup.md,dashboard-token-auth.mdandcli.mdto describe the actualbehaviour and point operators at what does work (revoke at the tunnel/proxy auth
layer, or sign out in that browser). This issue tracks the code change.
Per
SECURITY.mdthis issue deliberately contains no reproduction steps; thesecurity-relevant detail and impact analysis were sent privately to
kiro-crew-security-support@amazon.com.Candidate fixes
Two approaches, both small:
revoke_all_sessions()also revoke refresh chains. Requires enumeratingand marking every known chain, and cannot cover a chain absent from the
persisted state.
token payload and reject stale generations during validation. This makes the
existing generation counter authoritative over both cookie types at once,
needs no chain enumeration, reuses an already-persisted value, and fails
closed for chains the state file has never seen.
Either way,
kirocrew logout's help text and the doc passages corrected in #2024should be revisited to match whichever semantics land — three passages in that PR
describe the current limitation and should be simplified once it no longer exists.