Repository navigation
security(backend-auth): password-epoch revocation check fails open when Redis errors (backend equivalent of #16387) #16411
Description
Activity
Decision needed (owner). This is the backend counterpart of #16387, where the SLM now fails closed.
autobot_shared/user_management/password_epoch.pyis shared, and the backend'sauth_middlewareget_current_usercalls it with no exception handling of its own. The #16387 PR therefore leaves this path alone: changing the shared module would silently change backend authentication.Option Gain Loss 1. Fail closed (recommended) A revoked token is never honoured, the same rule as the SLM (#16387) and the same for humans and agents A Redis outage takes backend login down, and the main UI with it 2. Fail open, with an alert on every fail-open Login survives an outage Revoked tokens work during the outage; the risk is only made visible 3. Bounded fail-open (tokens issued before the outage, for N minutes) Limits the exposure window The most complex option; revoked tokens still work within the window Recommendation: option 1. The backend already depends on Redis for sessions and chat, so an outage degrades it anyway. Honouring a revoked credential is the worse failure, and one rule for both services is simpler to reason about.
- addedneeds-decisionBlocked on an owner decision; options and a recommendation are on the issueBlocked on an owner decision; options and a recommendation are on the issue
on Sep 11, 2026 Owner decision, 2026-09-12: fail closed, the same rule as the SLM (#16387, #16413). When the backend's password-epoch revocation check can't run because Redis errors, the token is denied with 401. A Redis outage therefore takes backend login down, and that's the accepted trade-off. The shared
autobot_shared/user_management/password_epoch.pyhelper becomes fail-closed for both callers, andauth_middlewareturns that failure into a normal 401.- removedneeds-decisionBlocked on an owner decision; options and a recommendation are on the issueBlocked on an owner decision; options and a recommendation are on the issue
on Sep 12, 2026 - added a commit that references this issue
on Sep 12, 2026 - added 7 commits that reference this issue
on Sep 12, 2026 Closure evidence (merged by #16433, 9caa367)
AC evidence (origin/main) The chosen behaviour is implemented for auth_middleware.py's use ofis_token_revoked_by_password_change, with a test for a Redis errorautobot-backend/auth_middleware.py:905-906if user_data.get("auth_method") == "jwt": await reject_if_revoked_by_password_change(user_data).autobot-backend/auth_revocation.py:33-41catchesRevocationCheckUnavailableand raisesHTTP_401_UNAUTHORIZED. The shared helper raises on a store error atautobot_shared/user_management/password_epoch.py:153-154. Test:autobot-backend/tests/test_password_revocation_fail_closed_16411.py:47-54test_a_redis_error_denies_the_tokenis parametrised withRedisError("down"),ConnectionError, andTimeoutError. Each error is raised by the client thatget_async_redis_clientreturns, and the test assertsstatus_code == 401.:58covers a missing client, which also gets a 401. The controls at:67and:86admit the token.The decision and rationale are recorded in THREAT_MODEL.md§4, next to #16387's entrydocs/developer/THREAT_MODEL.md:126-127, below #16387's entry at:120: "The shared password-epoch helper fails CLOSED in both services (#16411, #16422, owner decisions) … anexceptreading it as "not revoked" is a fail-open."- added a commit that references this issue
on Sep 24, 2026
Problem
#16387made the SLM's password-epoch revocation check fail CLOSED inautobot-slm-backend/services/auth.py(decode_token_async). That check(
is_token_revoked_by_password_change/get_password_epoch, in the sharedautobot_shared/user_management/password_epoch.py) has a second, livecaller in
autobot-backend/auth_middleware.py'sget_current_user(around the
#12924block), with no exception handling of its own aroundthe call.
#16387's fix deliberately did NOT touchpassword_epoch.py's internals,because doing so would silently change this backend call site's behaviour
too (
get_current_userhas no try/except there today, so it inheritswhatever
get_password_epochdoes on a Redis error) — out of scope for anSLM-only issue, per that issue's own instructions.
Today,
get_password_epochstill catchesExceptionaround its Redis calland returns
None(→ "not revoked") on failure — i.e. it fails open forthis backend caller. A revoked token (password changed after a leak) is
still honoured by the backend while Redis is erroring.
Decision needed (owner)
Whether the backend's
get_current_usershould adopt the same fail-closedpolicy
#16387chose for the SLM (a Redis outage denies backend login too),or a different one — and if fail-closed, how to implement it without
changing
password_epoch.py's shared contract in a way that also needs SLMfollow-up (or, if the module's contract does change, updating both callers
in the same PR).
Acceptance criteria
autobot-backend/auth_middleware.py's use ofis_token_revoked_by_password_change, with a test for a Redis error.docs/developer/THREAT_MODEL.md§4, next to#16387's entry.Refs #16387, #12924