Skip to content

2.4.0-rc.23

Pre-release
Pre-release

Choose a tag to compare

@lakhansamani lakhansamani released this 17 Aug 14:00
0206e7f

Release candidate for 2.4.0.

Since 2.4.0-rc.22

Security

  • A logged-out subject can no longer seed new delegations (#776) — token exchange verified a subject_token's signature, issuer and type and nothing else. The resulting delegated token is bound to a third-party resource and validated by that server, which has no view of this session store, so after a logout the user's agent kept minting fresh, externally valid credentials until the subject token expired. Exchange now checks the subject session's liveness when the token carries a sid. Service-account subjects stay exempt — a client_credentials token has no browser session. Same opaque invalid_grant as the invalid-subject path, so the endpoint is not a sign-in oracle. Ships with audit + metrics on all fourteen previously-silent exchange refusal paths (token.exchange_failed, authorizer_auth_events_total{event=token_exchange}, token_exchange_rejected), plus meters for the agent scope ceiling and delegated-token validation refusals.
  • Revocation is now visible at /oauth/introspect and /oauth/revoke (#774) — the session entry is this codebase's only revocation record, and neither token endpoint consulted it. Introspection answered active:true for tokens ValidateAccessToken already rejected, disclosing sub, scope and aud with it (RFC 7662 §2.2); any resource server trusting the endpoint accepted a logged-out token for the rest of its TTL. /oauth/revoke advertised token_type_hint=access_token but only ever looked up refresh tokens, returning the mandated 200 having revoked nothing — the hint now orders the lookup rather than restricting it (RFC 7009 §2.1). id_token is carved out by type; it is never registered in the store.
  • Two reachable IANA special-purpose ranges added to the SSRF block list (#781) — 198.18.0.0/15 and 192.88.99.0/24. The former is the one with real exposure: not being globally routable is exactly why organisations use it internally, so an SSRF there reaches a live internal service through an address that reads as public to every "is this private?" check, including this one. Found while testing the JWKS-fetch path: a container on a 198.18.0.0/24 docker network was fetched successfully through the unmodified guard.
  • Spec-defined outbound fetches refuse redirects (#775) — backchannel logout and client-metadata retrieval must reach the resource AT the URL named. Webhook delivery and the admin test-endpoint probe deliberately still follow redirects; those URLs are the operator's own. Also fixes cacheTTL parsing, where fmt.Sscanf accepted max-age=600junk as 600 (the clamp made every outcome safe, so no live defect).

Added

  • /mcp accepts RFC 8693 delegated tokens (#773) — an agent could not ask Authorizer about its own delegated authority: check_permissions was unreachable with the very token that proves the delegation, so agent delegation over MCP stayed a stdio-only story. The fallback is gated on the act claim and goes through a separate entry point, so audience matching stays exact in both directions: a token bound to the bare server URL is still refused at /mcp, and an MCP-bound one is still refused everywhere else.

Fixed

  • Workload identity: issuer enums are allow-listed, SPIFFE labelled preview (#777).
  • Correct false comments, remove dead code, wire missing telemetry (#779).

Tests

  • Kubernetes workload identity pinned against a real cluster (#778) and e2e coverage of workload identity against a real JWKS fetch (#782).

Upgrading from 2.3.x

--url is required — the server refuses to start without it. It is not --allowed-origins: --url is this server's own address, --allowed-origins is the apps it may redirect to. See Trusted base URL.

--encryption-key is required for RS*/ES* deployments.

Full detail in CHANGELOG.md.