Authlib will hand back a JWS that carries no signature at all as though it had been verified. CERT/CC published the advisory on 28 September 2026 and JPCERT/CC reissued it as JVNVU#99151548 on 29 September. The identifier is CVE-2026-96760.
An attacker needs neither a key nor a signature to push through a payload of their choosing as verified. CERT/CC lists authentication bypass through forged identity claims, privilege escalation, injection of signed messages between microservices, and forgery of authorization claims such as scopes and roles.
As of 29 September 2026 there is no fixed release. CERT/CC gives the reason: "The vendor could not be reached to coordinate this vulnerability and an official patch has not been made available at the time of this writing." And, as covered below, while the CVE records the affected range as 1.7.2 and below, the relevant code has not changed at all in the newer 1.8.0.
The reachable surface is narrow, though. Only code that accepts the JWS JSON Serialization is affected, and Authlib's JWT `decode()` is not. Work out which one you are before anything else.
What the flaw does
Quoting the NVD description directly:
"Authlib (v1.7.2 and below) contains a signature verification bypass vulnerability. The JsonWebSignature.deserialize_json() method accepts a JSON Serialization JWS object and returns the payload as successfully verified without checking for a signature and without requiring a cryptographic key."
CERT/CC is more specific: the function accepts a JWS object with an empty "signatures" array and treats the payload as successfully verified.
The code makes it obvious
I read the file on GitHub rather than taking this on trust. The tail of `deserialize_json()` in `authlib/jose/rfc7515/jws.py` reads:
headers = []
is_valid = True
for header_obj in obj["signatures"]:
jws_header, valid = self._validate_json_jws(
payload_segment, payload, header_obj, key
)
headers.append(jws_header)
if not valid:
is_valid = False
rv = JWSObject(headers, payload, "json")
if is_valid:
return rv
raise BadSignatureError(rv)`is_valid` starts as `True`, and the loop over `signatures` comes afterwards.
If `signatures` is an empty array the loop never runs, `_validate_json_jws()` is never called, and `is_valid` is still `True` when execution reaches `return rv`. No signature is checked and no key is ever demanded.
1.8.0 does not fix it
Both the CVE and CERT/CC give the affected range as 1.7.2 and below. That is too narrow. Here is what I checked.
I fetched `authlib/jose/rfc7515/jws.py` at v1.7.2, v1.8.0 and master. All three files are identical, with matching SHA-256 hashes. So 1.8.0 is not a fix for this.
The GitHub release list agrees: the newest release is v1.8.0 from 30 August 2026, and nothing has shipped since the CERT/CC advisory of 28 September. That is consistent with CERT/CC's statement that no patch is available.
Do not read "1.7.2 and below" as meaning 1.8.0 is safe. What I verified is that the code is identical — I did not go on to demonstrate a working attack against 1.8.0. Even so, there is no reason to count unchanged code as fixed.
Working out whether this reaches you
Having Authlib installed does not by itself put you at risk. Check in this order.
- ✓Look for direct calls to `JsonWebSignature.deserialize_json()`. If you have any, you are affected
- ✓Look for `JsonWebSignature.deserialize()` being handed a string that comes from outside. CERT/CC says both ways of loading a JWS in Authlib are affected, listing `deserialize_json(...)` and `deserialize('{"payload":"...","signatures":[]}', key=None)` side by side. That function routes to `deserialize_json()` whenever the value is a `dict`, or a string that starts with `{` and ends with `}`. The format is therefore chosen by the sender. You may believe you are handling compact JWS and still be routed into the vulnerable path
- ✓If you only ever call `deserialize_compact()`, this path is not reachable
- ✓If you only use Authlib's JWT through `jwt.decode()`, you are not affected. The JWT implementation calls `deserialize_compact()` and never `deserialize_json()`
What you can do before a patch exists
With no fixed release, the fix has to be in your own code. The following are not vendor-supplied workarounds — they are derived from the behaviour of the code quoted above. Verify the effect in your own environment before relying on them.
- ✓Stop calling `deserialize()` and call `deserialize_compact()` explicitly. Removing the format sniffing removes the attacker’s ability to select JSON Serialization
- ✓If you genuinely must accept JSON Serialization, check yourself that `signatures` is non-empty before verifying. Reject an empty array, and reject input where the key is missing entirely
- ✓Check that you are not calling it without a key. The docstring for `deserialize_json()` already states that if no key is provided it returns a dict without signature verification. That is separate from this vulnerability, and dangerous if used unintentionally
- ✓Watch the GitHub release list and upgrade when a fix ships. That is also what CERT/CC currently recommends
There is no CVSS score yet
This article gives no CVSS score, because none exists. Here is what the sources return.
The CVE.org record, assigned by CERT/CC, carries no CVSS `metrics` member at all, and NVD returns an empty `metrics` object and `vulnStatus: Received`, meaning it has been taken in but not yet analysed. The CVE record itself is published (`state: PUBLISHED`; the ID was reserved on 23 September 2026 and the record published on 28 September), so this is not a case of a missing identifier.
Do not read the absence of a number as mildness. It only means the assessment has not been done.
`authlib.jose` is deprecated in any case
One more thing I came across while tracing the surface.
`authlib/jose/__init__.py` raises a deprecation warning on import: "authlib.jose module is deprecated, please use joserfc instead.", followed by "It will be compatible before version 2.0.0." That says compatibility is kept up to 2.0.0; it does not say the module is removed at 2.0.0. (`authlib/deprecate.py` builds that sentence from the `version` argument.)
This vulnerability sits inside that deprecated module. Separately from the immediate response, the fact that a successor is officially named is worth weighing.
Three lines to pass on
- ▸Authlib returns an unsigned JWS as verified (CVE-2026-96760). No key, no signature, and authorization claims can be forged
- ▸No fixed release as of 29 September 2026. The CVE says 1.7.2 and below, but the file is identical in 1.8.0, so it is not fixed there
- ▸Only the JWS JSON Serialization path is affected. `jwt.decode()` is not. `deserialize()` lets the sender pick the format, so call `deserialize_compact()` explicitly
Sources
- JVNVU#99151548: signature verification bypass in the Authlib library (published 29 September 2026)↗
- CERT/CC VU#762428: Authlib library contains a signature-verification bypass vulnerability (empty signatures array, no patch available, disclosure timeline)↗
- NVD: CVE-2026-96760 (description; vulnStatus is Received, with no score assigned)↗
- CVE.org: CVE-2026-96760 (assigned by CERT/CC; no CVSS metrics member)↗
- GitHub: authlib/jose/rfc7515/jws.py at v1.8.0 — the deserialize_json() code quoted above↗
- GitHub: Authlib releases (newest is v1.8.0, 30 August 2026)↗
- PyPI: Authlib (release dates for each version)↗
