---
id: 2026-10-authlib-jws-empty-signatures-verification-bypass-cve-2026-96760-fixed-1-9-0
title: "Authlib through 1.8.0 accepts a JWS JSON object with no signatures as verified (CVE-2026-96760, 9.1); fixed 1.9.0"
date_disclosed: 2026-09-28
last_updated: 2026-10-27
severity: critical
status: patched
ecosystems: [pypi, python, auth, fastapi, flask, oauth]
tools_affected: ["authlib (PyPI) <= 1.8.0; any FastAPI, Flask, Django or Starlette service that calls JsonWebSignature.deserialize_json() or deserialize() on tokens it did not mint"]
tags: [cve, authentication-bypass, jws, jwt, signature-verification, oauth, oidc, python, fail-open, silent-fix, version-range-drift]
---

## TL;DR
Authlib's `JsonWebSignature.deserialize_json()` returned the payload of a JWS JSON Serialization object as verified when its `signatures` array was empty, so a relying party that fed it untrusted tokens accepted attacker-written claims with no key involved (CVE-2026-96760; CISA-ADP 9.8, GitHub 9.1). The CERT/CC record from 2026-09-28 says "1.7.2 and below", but 1.8.0 (PyPI 2026-08-30) was also vulnerable; the fix is PR #938 in **1.9.0** (PyPI 2026-10-14), whose release notes carry no security wording. Upgrade to 1.9.0 or later and check whether any token your service accepts is parsed through the JSON-serialization path.

## What happened

- **2026-08-21.** CERT/CC notified the vendor (VU#762428, "Vendor Notified" field). The note says no statement was received and the vendor could not be reached to coordinate.
- **2026-08-30.** Authlib 1.8.0 reached PyPI, still carrying the bug.
- **2026-09-28.** CERT/CC published VU#762428 and CVE-2026-96760 as the CNA: `JsonWebSignature.deserialize_json()` accepts a JWS object whose `signatures` list is empty and "returns the payload as successfully verified without checking for a signature and without requiring a cryptographic key"; the `deserialize()` wrapper reaches the same code. Affected "up to and including 1.7.2"; fixed version "None". CISA's ADP added CVSS 3.1 9.8. The GitHub Advisory Database mirrored it the same day as GHSA-6m87-8wg6-hh8w with `< 1.9.0` and no patched version.
- **2026-10-05.** Per the advisory now on the vendor repository, the only fix at that date was the unmerged pull request #938, and the GitHub record had no machine-readable range, so OSV-based scanners reported 1.8.0 as clean.
- **2026-10-14.** GHSA-6v38-4h7w-rj9h was published on `authlib/authlib` (Critical, CVSS 3.1 9.1, `AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N`, CWE-347) under the title "Signature verification bypass (CVE-2026-96760) is live in the current release 1.8.0, which every published record excludes". Its text: "This is already public. What is new is the version range." Root cause as stated there: the validity flag starts true and is only set false inside the loop over `signatures`, so an empty array never fails. Credits: zer0d4y5, uziii2208, nguyenminhtuan28. The same day Authlib 1.9.0 and 1.9.1 reached PyPI; the 1.9.0 release notes list "Fix empty signatures validation in JWS JSON deserialization" (PR #938) beside four OAuth validation fixes, with no CVE and no security label.
- **2026-10-27.** The database reviewed GHSA-6v38-4h7w-rj9h (affected `<= 1.8.0`, patched 1.9.0) and withdrew GHSA-6m87-8wg6-hh8w as a duplicate. The row appeared on the reviewed-critical pip listing that morning.

**Three affected ranges exist, and only one is right for an installed app.** The CNA says 1.7.2 and below; the withdrawn mirror said below 1.9.0; the live vendor-repository advisory says 1.8.0 and below with 1.9.0 patched. The registry settles it: 1.8.0 was published nine days after vendor notification and before the fix, so a scanner keyed to the CNA range misses it. Treat anything below 1.9.0 as affected.

**What a reader is exposed to.** The compact serialization (`a.b.c` tokens, the common OAuth and OIDC path) is not the path the records describe; the bypass is in the JSON Serialization (RFC 7515 section 7.2) parser. A service that accepts JSON-form JWS from clients, partners or a microservice peer, or that passes untrusted input into `deserialize()` without knowing which form arrives, can be handed a payload with forged `sub`, roles or scopes. CERT/CC lists authentication bypass, forged inter-service messages and forged permissions as the consequences.

## Am I affected?

```bash
pip show authlib 2>/dev/null | grep -i ^version      # below 1.9.0 is affected
grep -rn "deserialize_json\|JsonWebSignature\|\.deserialize(" --include=*.py . | grep -v site-packages
```

- A version at or below 1.8.0 is affected. The CNA's "1.7.2 and below" undercounts by one release.
- The grep tells you whether the JSON-serialization parser is reachable from input you do not control. If every token you verify is compact-form and comes from `jwt.decode()` with a key, the records describe a path you may not be using; upgrade anyway, because the 1.9.0 notes also tighten OAuth key, scope, audience, nonce and JAR validation.

## If you are affected

1. Upgrade to `authlib>=1.9.0` and redeploy; the fix is in the parser, not in configuration.
2. If untrusted JSON-form JWS reached a vulnerable version, audit the identities those tokens asserted against your own records for the window since the service first accepted them. [Auditing a vibe-coded repo](../playbooks/auditing-a-vibe-coded-repo.md) and [if your webapp was compromised](../playbooks/if-your-webapp-was-compromised.md).

## Prevention

- Pin and audit auth libraries separately from the rest of the tree, because a fix release here carried no security wording and an aggregator range excluded a vulnerable version for six weeks. [Package vetting checklist](../prevention/package-vetting-checklist.md).
- Verify tokens with an explicit key and algorithm allowlist and reject any JWS whose signature list is empty before handing it to a library.

## Sources
- [CERT/CC VU#762428 — Authlib library contains a signature-verification bypass vulnerability](https://kb.cert.org/vuls/id/762428) — fetched 2026-10-27: published 2026-09-28, vendor notified 2026-08-21, affected "up to and including 1.7.2", fixed version "None", vendor status unknown, the impact list, acknowledgements.
- [CVE Services — CVE-2026-96760](https://cveawg.mitre.org/api/cve/CVE-2026-96760) — queried 2026-10-27: CNA certcc, published 2026-09-28, affected 1.7.2, CISA-ADP CVSS 3.1 9.8, references to the repository and the VU note.
- [authlib/authlib — GHSA-6v38-4h7w-rj9h](https://github.com/authlib/authlib/security/advisories/GHSA-6v38-4h7w-rj9h) — fetched 2026-10-27: published 2026-10-14 by azmeuk, Critical 9.1, the vector, `<= 1.8.0` affected, 1.9.0 patched, the "already public, new is the version range" text, the flag-in-loop root cause, PR #938, credits.
- [GitHub Advisory Database — GHSA-6v38-4h7w-rj9h](https://github.com/advisories/GHSA-6v38-4h7w-rj9h) — fetched 2026-10-27: reviewed 2026-10-27, affected `<= 1.8.0`, patched 1.9.0, references to PR #938, commit 6c11a02 and the v1.9.0 release.
- [GitHub Advisory Database — GHSA-6m87-8wg6-hh8w](https://github.com/advisories/GHSA-6m87-8wg6-hh8w) — fetched 2026-10-27: published 2026-09-28, withdrawn 2026-10-27 as a duplicate, `< 1.9.0`, no patched version, CVSS 9.8.
- [authlib/authlib — release v1.9.0](https://github.com/authlib/authlib/releases/tag/v1.9.0) — fetched 2026-10-27: dated 14 Oct, "Fix empty signatures validation in JWS JSON deserialization" (PR #938) and the four OAuth validation fixes; no CVE, no "security".
- PyPI `authlib` release metadata, queried 2026-10-27: 1.7.2 on 2026-05-06, 1.8.0 on 2026-08-30, 1.9.0 and 1.9.1 on 2026-10-14; latest 1.9.1.
