CVE regression matrix
When a CVE is published against another OIDC / OAuth / JOSE implementation, the question for this library is "could the same defect reach us, and if not, why not?". The honest answer needs more than a code review — it needs a test that fails the build if a future refactor reintroduces the bypass.
This page is the public ledger of those tests. Every CVE listed here has at least one unit / fuzz test that exercises the surface and pins the rejection. The test references are stable — if a row points at a file or test name, it lives in the repository.
Reading the table
- CVE — the original disclosure, against another implementation. We do not maintain CVE entries against this library; the field tells you what class of defect the test is meant to keep out.
- Class — the underlying defect (alg confusion, redirect-uri matching, PKCE downgrade, ...).
- RFC anchor — the spec section the test pins behaviour against.
- Test — the regression test that fails if the surface regresses.
JOSE / JWT verification
| CVE | Class | RFC anchor | Test |
|---|---|---|---|
| CVE-2015-9235 (jsonwebtoken) | alg=none accepted | RFC 8725 §3.1 | internal/jose.FuzzJOSEParse (alg=none seed)internal/tokens.TestVerify_AlgConfusion_HSUsingECPublicKeyBytesAsSecret |
| CVE-2016-10555 (jwt-simple) | alg=HS256 accepted, treats public key as HMAC secret | RFC 8725 §2.1 | internal/tokens.TestVerify_AlgConfusion_HSUsingECPublicKeyBytesAsSecret |
| CVE-2015-2951 (jose4j) | alg=none accepted | RFC 8725 §3.1 | internal/jose.FuzzJOSEParse |
| CVE-2024-54150 (cjwt) | algorithm confusion | RFC 8725 §2.1 | internal/tokens.TestVerify_AlgConfusion_HSUsingECPublicKeyBytesAsSecret |
| CVE-2026-22817 / CVE-2026-27804 / CVE-2026-23552 (Hono JWT 2026 cluster) | case-variant alg=NONE bypass of deny-list | RFC 8725 §3.1 | internal/jose.TestParseAlgorithm_CaseVariantsRejectedinternal/jose.FuzzJOSEParse (case-variant seeds) |
| CVE-2026-33322 (MinIO OIDC) | algorithm confusion | RFC 8725 §2.1 | internal/tokens.TestVerify_AlgConfusion_HSUsingECPublicKeyBytesAsSecret |
| CVE-2018-0114 (Cisco / node-jose) | trusted jwk header — verifier used key from JWS itself | RFC 8725 §3.1–3.5 | internal/jose.TestParseSigned_HeaderInjection_NeverFetchesinternal/jose.FuzzJOSEParse (jku seed) |
| CVE-2018-1000531 (inversoft prime-jwt) | alg header downgrade + trusted jwk | RFC 8725 §3.1 | internal/jose.TestParseSigned_HeaderInjection_NeverFetches |
| CVE-2017-11424 (python-jose-style) | jku resolved from header | RFC 8725 §3.1 | internal/jose.TestParseSigned_HeaderInjection_NeverFetches |
| CVE-2019-7644 (Auth0 jsonwebtoken-koa) | trusted jwk header | RFC 8725 §3.1 | internal/jose.TestParseSigned_HeaderInjection_NeverFetches |
| CVE-2026-34240 / GHSA-vm9r-h74p-hg97 (Dart jose) | trusted jwk header — verifier treated attacker-supplied key material as a candidate verification key | RFC 8725 §3.1–3.5 | internal/jose.TestParseSigned_HeaderInjection_NeverFetches |
| CVE-2025-59420 (Authlib) | crit extension list ignored | RFC 7515 §4.1.11 / RFC 8725 §3.5 | internal/jose.TestParseSigned_CritHeaderRejectedAtVerify |
| CVE-2026-32597 (PyJWT) | same crit-ignored defect | RFC 8725 §3.5 | internal/jose.TestParseSigned_CritHeaderRejectedAtVerify |
| CVE-2026-28498 (Authlib) | hash-binding verifier fail-opened when handed an unknown / unsupported alg | RFC 8725 §3.1 | internal/jose.TestParseSigned_RejectsUnsupportedRegisteredAlg_NoFailOpen |
| CVE-2024-29371 (jose4j JWE decompression bomb) | resource exhaustion via crafted JWE | RFC 8725 §3.11 | internal/jose.FuzzJOSEParse (oversize seed)internal/parendpoint.FuzzPARFormBodyinternal/introspectendpoint.FuzzIntrospectFormBodyinternal/revokeendpoint.FuzzRevokeFormBody |
Authorize / redirect_uri
| CVE | Class | RFC anchor | Test |
|---|---|---|---|
| CVE-2024-10318 (NGINX OIDC reference) | front-channel id_token issued without nonce binding → session fixation | OIDC Core §15.5.2 / RFC 9700 §2.1.2 | internal/authorize.TestRequest_Validate_RejectsImplicitAndHybridResponseTypes (response_type=code only)internal/backchannel.TestSignLogoutToken_EmitsRequiredClaims (logout_token typ discrimination) |
| CVE-2024-8883 (Keycloak) | wildcard / suffix bypass of an earlier redirect_uri patch | RFC 6749 §3.1.2.3 / RFC 9700 §4.1 | internal/authorize.TestRequest_Validate_RedirectURIAttackVariants |
| CVE-2020-15234 (ory/fosite) | case-variant redirect_uri matched a case-different registration | RFC 6749 §3.1.2.3 | internal/authorize.TestRequest_Validate_RedirectURIAttackVariants |
| GHSA-rfq3-w54c-f9q5 (ory/fosite) | loopback redirect rule allowed host / query override; fix narrows runtime variation to the port only — exact-string match here is even stricter | RFC 6749 §3.1.2.3 / RFC 9700 §4.1 | internal/authorize.TestRequest_Validate_RedirectURIAttackVariants |
| CVE-2026-7571 (Keycloak) | disabled implicit-flow control bypass; front-channel access-token disclosure via a forged client state | RFC 9700 §2.1.2 | internal/authorize.TestRequest_Validate_RejectsImplicitAndHybridResponseTypes |
| CVE-2026-3872 (Keycloak) | wildcard redirect_uri path traversal using ..;/ | RFC 6749 §3.1.2.3 / RFC 9700 §4.1 | internal/authorize.TestRequest_Validate_RedirectURIAttackVariants |
| CVE-2026-7504 (Keycloak) | wildcard redirect_uri parser confusion through multiple @ bytes in the authority / userinfo segment | RFC 6749 §3.1.2.3 / RFC 9700 §4.1 | internal/authorize.TestRequest_Validate_RedirectURIAttackVariants |
PKCE / code exchange
| CVE | Class | RFC anchor | Test |
|---|---|---|---|
| CVE-2024-23647 (authentik ≤2023.10.6, CVSS 6.1) | /token accepted code_verifier on codes minted without a code_challenge — PKCE downgrade | RFC 9700 §4.8 / RFC 7636 §4.6 | internal/grants/authcode.TestExchange_NoPKCE_RejectsSmuggledVerifier |
| CVE-2025-4144 (Cloudflare workers-oauth-provider <0.0.5, CVSS 8.1) | same downgrade variant in a different ecosystem | RFC 9700 §4.8 | internal/grants/authcode.TestExchange_NoPKCE_RejectsSmuggledVerifier |
Authorization code interception (cross-client retrieval)
| CVE | Class | RFC anchor | Test |
|---|---|---|---|
| GHSA-vh7g-p26c-j2cw (dexidp/dex, 2024) | back-channel ID-token retrieval after authorization-code interception — redeeming the code under a different client_id returned tokens minted for the victim. Structural mitigation: the (code, client_id, redirect_uri[, code_verifier]) tuple must match at exchange | RFC 6749 §4.1.3 / OIDC Core §3.1.3.4 | internal/grants/authcode.TestExchange_RejectsClientMismatch |
Client authentication / private_key_jwt
| CVE | Class | RFC anchor | Test |
|---|---|---|---|
| CVE-2025-27370 (OIDF coordinated, OIDC) | private_key_jwt aud confusion: malicious AS could relay a key reused across ASs and impersonate the client | RFC 7523bis / FAPI 2.0 §5.2.2 | internal/clientauth.TestPrivateKeyJWTVerifier_AudIssuer_AcceptedViaAuxAudiences |
| CVE-2025-27371 (IETF coordinated, OAuth 2.0) | same defect, OAuth profile lineage | RFC 7523bis | internal/clientauth.TestPrivateKeyJWTVerifier_AudIssuer_AcceptedViaAuxAudiences |
| CVE-2020-15222 (ory/fosite < 0.31.0, GHSA-mh3m-8c74-74xh) | private_key_jwt jti uniqueness not enforced — assertion replay | RFC 7523 §3 / CWE-345 | internal/clientauth.TestPrivateKeyJWTVerifier_JTIReplay_Rejected |
| GHSA-v3q9-2p3m-7g43 (ory/fosite, 2020 cluster) | same jti-replay defect class re-disclosed under a separate GHSA — structural mitigation is identical (per-jti single-use within the assertion's exp window) | RFC 7523 §3 / CWE-345 | internal/clientauth.TestPrivateKeyJWTVerifier_JTIReplay_Rejected |
| CVE-2026-1180 (Keycloak) | jwks_uri SSRF during dynamic-client private_key_jwt key resolution | RFC 7591 §2 / RFC 7523 §3 | internal/securefetch.TestPolicy_SSRFContract |
Token introspection
| CVE | Class | RFC anchor | Test |
|---|---|---|---|
| CVE-2026-37979 (Keycloak) | token introspection audience bypass — a confidential client could retrieve claims for another resource server's token | RFC 7662 §2.2 | internal/introspectendpoint.TestHandler_JWTAccessToken_DifferentClientinternal/introspectendpoint.TestHandler_OpaqueAccessToken_DifferentClient |
Refresh token rotation
| CVE | Class | RFC anchor | Test |
|---|---|---|---|
| CVE-2026-1035 (Keycloak) | refresh-token reuse bypass via TOCTOU race in rotation enforcement | RFC 9700 §2.2.2 / RFC 6749 §6 | op/storeadapter/inmem.TestConsumeRefresh_Race |
Session lifecycle (fixation / rotation)
| CVE | Class | RFC anchor | Test |
|---|---|---|---|
| GHSA-xhpr-465j-7p9q (Keycloak, 2024) | first-login phishing via email verification (CWE-384 session fixation) — a session that pre-existed the trust transition continued to be authoritative after verification, letting an attacker who planted the cookie ride the post-verification trust. Structural mitigation: rotate session ID on the trust boundary, but preserve CreatedAt so an attacker cannot extend lifetime by triggering rotation | OIDC Core §3.1.2.7 | internal/sessions.TestManager_Rotate_IssuesFreshIDPreservingChooserGroupinternal/sessions.TestManager_Rotate_PreservesCreatedAt |
| CVE-2026-7507 (Keycloak) | OIDC-login session fixation → account takeover; a pre-seeded session ID survived fresh authentication. Structural mitigation: rotate the cookie-bound session ID when a fresh authn factor completes at the authorize / interaction boundary, and delete the old session record | OIDC Core §3.1.2.7 | internal/authorizeendpoint.TestInteractionPost_RotatesSessionIDAfterFreshAuthn |
Multi-factor authentication (TOTP / step-up)
| CVE | Class | RFC anchor | Test |
|---|---|---|---|
| GHSA-9r3w-4j8q-pw98 (cal.com) | providing a TOTP code skipped the password check entirely — TOTP step ran without primary-factor proof | RFC 6238 / OIDC Core §2 (acr semantics) | internal/authn.TestLoginFlowTOTPRequiresPrimary (orchestrator gate)internal/authn/totp.TestAuthenticator_BeginRequiresSubjectinternal/authn/totp.TestAuthenticator_ContinueRequiresSubject (adapter gate) |
| GHSA-5jfq-x6xp-7rw2 (Keycloak) | second-factor bypass — same structural class, covered by the same two-layer mitigation (orchestrator step ordering + adapter Subject-required gate) | RFC 6238 / OIDC Core §2 | (same tests as above) |
JARM / response signing
| CVE | Class | RFC anchor | Test |
|---|---|---|---|
| CVE-2023-6927 (Keycloak) | response_mode=form_post.jwt bypass of CVE-2023-6134 — JARM added without the same alg restrictions as the bearer flow | FAPI 2.0 Message Signing §5.4 / RFC 8725 §3.1 | internal/jarm.TestSigner_AlgIsES256_Structural |
| CVE-2023-6134 (Keycloak, parent) | original form-post downgrade; tracked via 6927 | RFC 8725 §3.1 | internal/jarm.TestSigner_AlgIsES256_Structural |
Error response surfaces (redirect / form_post)
The authorize endpoint emits errors over two surfaces — a redirect with query parameters and an auto-submitting form_post HTML page. Both must escape RP-supplied bytes so a hostile redirect_uri or error_description cannot inject markup or open-redirect chains.
| CVE | Class | RFC anchor | Test |
|---|---|---|---|
| GHSA-27gc-wj6x-9w55 (Keycloak, 2024) | error_description reflected into HTML error pages without escaping (CWE-79 / CWE-601) — phishing / open-redirect chains. Two-layer mitigation: (1) error_description is a closed catalogue of hardcoded sentinels — RP bytes never reach the field directly; (2) on the wire, url.Values.Encode percent-encodes the redirect surface and html.EscapeString escapes both action= and value= on the form_post surface | RFC 6749 §4.1.2.1 / RFC 9700 §4.10 | internal/jarm.TestWriteFormPost_EscapesRedirectAndJWTinternal/authorizeendpoint.TestBuildRedirectError_EncodesHostileBytes_NoXSSinternal/authorizeendpoint.TestBuildRedirectError_StripsControlBytes |
Operator observability (silent failure on revoke)
| CVE | Class | RFC anchor | Test |
|---|---|---|---|
| GHSA-7mqr-2v3q-v2wm (ory/fosite) | /revoke silently swallowed storage errors — RFC 7009 §2.2 still requires a wire 200, but operators had no observable signal that revocation actually failed. The library keeps the wire 200 and additionally emits token.revoke_failed on every non-NotFound store fault so SOC tooling can detect the silent-failure class | RFC 7009 §2.2 | internal/revokeendpoint.TestHandler_RefreshToken_StoreFault_EmitsAudit |
DoS / parsing safety
Fuzz harnesses across the JOSE / endpoint surface keep parsing panic-free against crafted inputs:
| Surface | Fuzzer | CVE class kept out |
|---|---|---|
| JOSE parse | internal/jose.FuzzJOSEParse | RFC 8725 §3.11 / CVE-2024-29371 (decompression bomb), 2015 alg=none cluster |
| PAR endpoint body | internal/parendpoint.FuzzPARFormBody | CVE-2024-29371 (CVSS 7.5; jose4j JWE decompression bomb) |
| Introspection endpoint body | internal/introspectendpoint.FuzzIntrospectFormBody | CVE-2024-29371 |
| Revocation endpoint body | internal/revokeendpoint.FuzzRevokeFormBody | RFC 8725 §3.11 / CVE-2024-29371 (panic immunity) |
The same FuzzJOSEParse no-panic + JWS-only contract additionally class-covers a cluster of dependency-side advisories that exercise input shapes the OP never accepts (compact JWS only, JWE / compression paths absent, CBC-mode JWE algs not in the allowlist):
| Advisory | Source | Class-coverage |
|---|---|---|
| GHSA-78h2-9frx-2jm8 | go-jose | JWE decryption panic — ParseSigned is JWS-only and never enters the JWE decrypt path |
| GHSA-c6gw-w398-hv78 | go-jose | parse DoS on pathological JSON — covered by the no-panic fuzz contract |
| GHSA-c5q2-7r4c-mv6g | go-jose | compression amplification (CVE-2024-29371 cluster) — compact JWS only, no compression path |
| GHSA-pvcr-v8j8-j5q3 | lestrrat-go/jwx | JSON-form parse panic — compact-only rejection |
| GHSA-hj3v-m684-v259 | lestrrat-go/jwx | JWE compression DoS — same compact-only contract |
| GHSA-7f9x-gw85-8grf | lestrrat-go/jwx | malicious JWE-params DoS — same compact-only contract |
| GHSA-rm8v-mxj3-5rmq | lestrrat-go/jwx | CBC-mode JWE padding-oracle possibility — JWS-only allowlist (RS256 / PS256 / ES256 / EdDSA) excludes every CBC-mode JWE alg |
What this list deliberately does not include
- CVEs against this library. The library is pre-v1.0 and has no published CVE record yet; if one is filed, it goes in
SECURITY.mdand through the disclosure flow on Reporting a security issue, not here. - Dependency defects whose trigger inputs the OP's input contract does NOT structurally reject. Those are tracked through
govulncheckin CI and resolved by version bump. Where the OP's compact-JWS-only / JWS-only-allowlist contract structurally rejects the trigger inputs (e.g. JWE-side panics, CBC padding oracles), the advisory IS listed in the table above with a "class-covered" pointer to the fuzz harness. - TLS / transport defects (e.g.
GHSA-gr79-9v6v-gc9r,GHSA-q8hq-4h99-fj7x). The library does not own its HTTP server; TLS configuration is the embedder's responsibility. See Library posture. - SAML defects (e.g.
GHSA-m9hp-7r99-94h5). SAML is not implemented; this is an OP only. - Tracked but not yet covered advisories. The source repository's advisory queue may contain entries marked
trackingwhile the matching regression test is still being designed (for example, classes under DCR redirect allow-listing, introspection revocation windows, or custom-grant confused-deputy checks). Those stay out of this public matrix until a concrete test pins the contract. - Theoretical attacks without a published CVE. A test motivated purely by a spec section (e.g. RFC 8725 §3.x) is still in the codebase, but won't appear here unless a CVE pins the class to a named defect somewhere in the ecosystem.
Reading the bigger picture
The CVE-driven tests sit alongside three other layers of regression material:
- Spec scenarios —
tests/scenarios/(in the repo) catalogues OIDC / OAuth / FAPI behaviours from the spec text directly, regardless of whether a CVE exists. - OFCS conformance harness — see OFCS conformance status. The OpenID Foundation's certified test suite drives the public surface end-to-end against the FAPI 2.0 plans.
- Fuzz harnesses — listed above, run on every PR.
If you find a CVE class this library should pin and doesn't, please open an issue or follow the disclosure flow for anything that would itself be a vulnerability to discuss in public.