Enforce broker replay protection (iat expiry window + jti cache) #494
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Split out from the Host control server PRD (#468, PR #486) — replay protection was judged too heavy for the MVP of that work and belongs on its own track.
Gap
sign_requestalready emitsjtiandiat;verify_requestreads neither — no expiry window, nojticache (broker.py:88). Harmless in-process (a fresh token persubmit), but once the broker contract runs over a wire a captured launch token replays indefinitely.Proposed enforcement
Have
verify_requeststart reading both claims, fail-closed:iatis outside a small window (proposed ±60s, one constant) — bounds how long a captured token is useful and how much clock skew is tolerated.jticache. Keep a set of seenjtis for at least the expiry window; reject a repeat. The cache only needs to remember tokens still within their window, so it self-trims byiat— no unbounded growth, no persistence needed (a token older than the window is already rejected by the expiry check, so a cache lost on restart cannot admit a replay).A missing or malformed
jti/iatis a rejection, not a pass — both are additions to the existingBrokerAuthErrorpath.Notes
jticache is sufficient; if lifecycle ever fans out, the cache and the expiry window need to be co-located with the single verifier.Low priority given this is all currently traffic on a trusted host device.