Skip to content
IBMGHSA-hxq2-5h3j-jqjv

Session auth-context reuse ignores JWT exp — expired JWT replayable within session_auth_reuse_ttl

MediumPublished Aug 25, 2026

### Summary When session auth-context reuse is enabled, a stored auth context's expiry is computed solely from a fixed config TTL (`now + session_auth_reuse_ttl`). It does **not** consider the JWT's own `exp` claim, so a JWT that has passed its `exp` can still be reused (replayed) for the remainder of the reuse window — per-request JWT expiry enforcement is skipped on a reuse hit. ### Affected - Rust runtime `crates/mcp_runtime` (`src/lib.rs`), when session auth-context reuse is active (`session_auth_reuse_ttl_seconds` > 0) with public ingress. - Version `1.0.2` and current `main`. ### Detail - `InternalAuthContext` carries no JWT `exp` / expiry field. - On store, the reuse expiry is set as `auth_context_expires_at_epoch_ms = unix_epoch_millis() + session_auth_reuse_ttl` — no clamping to the JWT `exp`. - `can_reuse_session_auth` only checks `unix_epoch_millis() >= auth_context_expires_at_epoch_ms` (the TTL-based value). - Net effect: an expired credential remains accepted for up to `session_auth_reuse_ttl` after its `exp`, because the reuse path returns the cached auth context instead of re-validating the (now expired) JWT. ### Impact Authentication-lifetime bypass, bounded by t...

GitHub advisory

Affected versions

PackageAffectedFixed in
mcp-contextforge-gateway
PyPI
< v1.0.5v1.0.5
Details and references

### Summary When session auth-context reuse is enabled, a stored auth context's expiry is computed solely from a fixed config TTL (`now + session_auth_reuse_ttl`). It does **not** consider the JWT's own `exp` claim, so a JWT that has passed its `exp` can still be reused (replayed) for the remainder of the reuse window — per-request JWT expiry enforcement is skipped on a reuse hit. ### Affected - Rust runtime `crates/mcp_runtime` (`src/lib.rs`), when session auth-context reuse is active (`session_auth_reuse_ttl_seconds` > 0) with public ingress. - Version `1.0.2` and current `main`. ### Detail - `InternalAuthContext` carries no JWT `exp` / expiry field. - On store, the reuse expiry is set as `auth_context_expires_at_epoch_ms = unix_epoch_millis() + session_auth_reuse_ttl` — no clamping to the JWT `exp`. - `can_reuse_session_auth` only checks `unix_epoch_millis() >= auth_context_expires_at_epoch_ms` (the TTL-based value). - Net effect: an expired credential remains accepted for up to `session_auth_reuse_ttl` after its `exp`, because the reuse path returns the cached auth context instead of re-validating the (now expired) JWT. ### Impact Authentication-lifetime bypass, bounded by the reuse TTL. Requires the reuse feature enabled and a matching binding fingerprint. Default configuration may have reuse disabled (please confirm on your side). ### Suggested fix - Add the JWT `exp` to the stored auth context and cap reuse expiry at `min(now + session_auth_reuse_ttl, jwt_exp)`. - Ensure the auth layer that produces the context forwards `exp` so the runtime can clamp. ### Notes Reported via private vulnerability disclosure per `SECURITY.md`. Happy to provide a minimal reproduction or test against a patch.

Severity from
GitHub (reviewed advisory)

More IBM advisories

All IBM

Critical advisories by email

Wednesdays: the week’s critical and high advisories in the AI and data stack, with the fixed versions. Only in weeks that have some.

Double opt-in. Unsubscribe any time.