0036. Key-compromise emergency response
Context
ADR-0023 specifies planned key rotation — overlap, then retire, so no in-flight token is
orphaned. But a leaked signing key is the opposite situation: every token under that
kid must die immediately, not after the overlap window. The §12.8 review flagged that
the emergency path (distinct from planned rotation) was undecided. A signing-key leak is the
most severe identity incident, so the mechanism is fixed here.
Decision
-
Emergency
kidrevocation. A compromised signing key is revoked wholesale: itskidis removed from the published JWKS (ADR-0023) at once, and every token signed by it is invalidated via akid-scoped revocation on the status list (ADR-0005) — not waiting for the rotation overlap. The wire form is the status list's dedicated key-revocation section (ADR-0043): a per-token bitstring cannot express "every token under thiskid", so the list carries a revoked-kidset alongside it. -
Forced re-issue. Active sessions (ADR-0016) re-mint tokens under a fresh key; tokens bearing the compromised
kidfail verification at the edge once the JWKS no longer carries it (and the status list reflects the revocation). This is the publish-before-sign discipline (ADR-0023) run in reverse — unpublish-then-the-kid-is-dead. -
Fail closed for the dropped
kid(ADR-0010): a token whosekidis no longer in the JWKS cannot verify — the absence of the key is itself the kill switch, independent of the status list. -
Mechanism + runbook. The mechanism (kid-scoped revocation + JWKS removal + forced re-issue) is specified here; the operational runbook (detect → revoke → re-issue → post-incident review feeding ADR-0027) accompanies it.
Consequences
- A key leak is contained in minutes (the edge JWKS-cache refresh bound) — a bound that is registered and gate-validated in the budget system (ADR-0039), not merely hoped for — rather than the rotation-overlap window: the blast-radius reduction a leaked signing key demands.
- Two independent kill mechanisms (JWKS removal and status-list revocation) mean a token
under a compromised
kiddies even if one path lags. Both kill paths are themselves replay-protected: the JWKS and the status list carry the counter + max-age freshness discipline and are signed by the distribution key, not a token-signing key (ADR-0043) — otherwise a stale-JWKS replay would re-animate the removedkid, and the compromised key could forge a "clean" list defeating its own revocation. - Per-tenant/realm key separation (ADR-0023) bounds the scope: only the affected tenant's tokens are forced to re-issue.
- Distinct from, and composes with, planned rotation (ADR-0023), the status list (ADR-0005), and the incident loop (ADR-0027). Closes the §12.8 key-compromise gap.