Update dependency Authlib to v1.6.9 [SECURITY]#14
Open
renovate[bot] wants to merge 1 commit into
Open
Conversation
d114f32 to
d3c62d0
Compare
91fe2d3 to
bab6579
Compare
bab6579 to
1714262
Compare
1714262 to
3818ccc
Compare
3818ccc to
dcae1c9
Compare
dcae1c9 to
69efa5a
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR contains the following updates:
==1.2.1→==1.6.9Authlib has algorithm confusion with asymmetric public keys
CVE-2024-37568 / GHSA-5357-c2jx-v7qh
More information
Details
lepture Authlib before 1.3.1 has algorithm confusion with asymmetric public keys. Unless an algorithm is specified in a jwt.decode call, HMAC verification is allowed with any asymmetric public key. (This is similar to CVE-2022-29217 and CVE-2024-33663.)
Severity
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:NReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
Authlib: JWS/JWT accepts unknown crit headers (RFC violation → possible authz bypass)
CVE-2025-59420 / GHSA-9ggr-2464-2j32
More information
Details
Summary
Authlib’s JWS verification accepts tokens that declare unknown critical header parameters (
crit), violating RFC 7515 “must‑understand” semantics. An attacker can craft a signed token with a critical header (for example,borkorcnf) that strict verifiers reject but Authlib accepts. In mixed‑language fleets, this enables split‑brain verification and can lead to policy bypass, replay, or privilege escalation.Affected Component and Versions
authlib.jose.JsonWebSignature.deserialize_compact(...)critDetails
RFC 7515 (JWS) §4.1.11 defines
critas a “must‑understand” list: recipients MUST understand and enforce every header parameter listed incrit, otherwise they MUST reject the token. Security‑sensitive semantics such as token binding (e.g.,cnffrom RFC 7800) are often conveyed viacrit.Observed behavior with Authlib 1.6.3:
crit: ["cnf"]and acnfobject, orcrit: ["bork"]with an unknown parameter, Authlib verifies the signature and returns the payload without rejecting the token or enforcing semantics of the critical parameter.josev5 both reject such tokens by default whencritlists unknown names.Impact in heterogeneous fleets:
critcarries binding or policy information.Proof of Concept (PoC)
This repository provides a multi‑runtime PoC demonstrating the issue across Python (Authlib), Node (
josev5), and Java (Nimbus).Prerequisites
Setup
Enter the directory authlib-crit-bypass-poc & run following commands.
Tokens minted
tokens/unknown_crit.jwtwith protected header:{ "alg": "HS256", "crit": ["bork"], "bork": "x" }tokens/cnf_header.jwtwith protected header:{ "alg": "HS256", "crit": ["cnf"], "cnf": {"jkt": "thumb-42"} }Reproduction
Run the cross‑runtime demo:
Expected output for each token (strict verifiers reject; Authlib accepts):
For
tokens/unknown_crit.jwt:For
tokens/cnf_header.jwt:Environment notes:
1.6.3(from PyPI)joseversion:^59.37.x0123456789abcdef0123456789abcdefImpact
crit“must‑understand” semantics; specification non‑compliance leading to authentication/authorization policy bypass.critto carry mandatory security semantics (e.g., token binding viacnf) or operates in a heterogeneous fleet with strict verifiers elsewhere.References
critcnf)Severity
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:NReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
Authlib is vulnerable to Denial of Service via Oversized JOSE Segments
CVE-2025-61920 / GHSA-pq5p-34cr-23v9
More information
Details
Summary
Authlib’s JOSE implementation accepts unbounded JWS/JWT header and signature segments. A remote attacker can craft a token whose base64url‑encoded header or signature spans hundreds of megabytes. During verification, Authlib decodes and parses the full input before it is rejected, driving CPU and memory consumption to hostile levels and enabling denial of service.
Impact
Attack vector: unauthenticated network attacker submits a malicious JWS/JWT.
Effect: base64 decode + JSON/crypto processing of huge buffers pegs CPU and allocates large amounts of RAM; a single request can exhaust service capacity.
Observed behaviour: on a test host, the legacy code verified a 500 MB header, consuming ~4 GB RSS and ~9 s CPU before failing.
Severity: High. CVSS v3.1: AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H (7.5).
Affected Versions
Authlib ≤ 1.6.3 (and earlier) when verifying JWS/JWT tokens. Later snapshots with 256 KB header/signature limits are not affected.
Proof of concept
Local demo (do not run against third-party systems):
Download jws_segment_dos_demo.py the PoC in direcotry authlib/
Run following Command
Environment: Python 3.13.6, Authlib 1.6.4, Linux x86_64, CPUs=8

Sample output: Refined
The compilation script prints separate “[ATTACKER]” (token construction) and “[SERVER]” (Authlib verification) RSS deltas so defenders can distinguish client-side preparation from server-side amplification. Regression tests authlib/tests/dos/test_jose_dos.py further capture the issue; the saved original_util.py/original_jws.py reproductions still accept the malicious payload.
Remediation
Apply the upstream patch that introduces decoded size limits:
MAX_HEADER_SEGMENT_BYTES = 256 KB
MAX_SIGNATURE_SEGMENT_BYTES = 256 KB
Enforce Limits in authlib/jose/util.extract_segment and _extract_signature.
Deploy the patched release immediately.
For additional defence in depth, reject JWS/JWT inputs above a few kilobytes at the proxy or WAF layer, and rate-limit verification endpoints.
Workarounds (temporary)
Enforce input size limits before handing tokens to Authlib.
Use application-level throttling to reduce amplification risk.
Resources
Demo script: jws_segment_dos_demo.py
Tests: authlib/tests/dos/test_jose_dos.py
OWASP JWT Cheat Sheet (DoS guidance)
Severity
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:HReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
Authlib : JWE zip=DEF decompression bomb enables DoS
CVE-2025-62706 / GHSA-g7f3-828f-7h7m
More information
Details
Summary
Authlib’s JWE
zip=DEFpath performs unbounded DEFLATE decompression. A very small ciphertext can expand into tens or hundreds of megabytes on decrypt, allowing an attacker who can supply decryptable tokens to exhaust memory and CPU and cause denial of service.Details
zip=DEF(DEFLATE) support.authlib/authlib/jose/rfc7518/jwe_zips.py,DeflateZipAlgorithm.decompresscallszlib.decompress(s, -zlib.MAX_WBITS)without a maximum output limit. This permits unbounded expansion of compressed payloads.authlib/authlib/jose/rfc7516/jwe.py), when the protected header contains"zip": "DEF", the library routes the decrypted ciphertext into thedecompressmethod and assigns the fully decompressed bytes to the plaintext field before returning it. No streaming limit or quota is applied.zip=DEFciphertext that inflates to a very large plaintext during decrypt, spiking RSS and CPU. Repeated requests can starve the process or host.Code references (from this repository version):
authlib/authlib/jose/rfc7518/jwe_zips.py–DeflateZipAlgorithm.decompressuses unboundedzlib.decompress.authlib/authlib/jose/rfc7516/jwe.py– JWE decode path applieszip_.decompress(msg)whenzip=DEFis present in the header.Contrast: The
joserfcproject guardszip=DEFdecompression with a fixed maximum (256 KB) and raisesExceededSizeErrorif output would exceed this limit, preventing the bomb. Authlib lacks such a guard in this codebase snapshot.PoC
Environment: Python 3.10+ inside a venv; Authlib installed editable from this repository so source changes are visible. The PoC script demonstrates both a benign and a compressible-bomb payload and prints wall/CPU time, RSS, and size ratios.
Set current directory to /authlib
Download jwe_deflate_dos_demo.py in /authlib
Sample output (abridged):
The second case shows the decompression spike: a few KB of ciphertext forces allocation and processing of ~50 MB during decrypt. Repeated requests can quickly exhaust available memory and CPU.
Reproduction notes:
alg=dir,enc=A256GCM, header includes{ "zip": "DEF" }."A" * N).--sizeto stress memory; the--max-rss-mbflag helps avoid destabilizing the host during testing.Impact
zip=DEFtokens.zip=DEFand where an attacker can submit tokens that will be successfully decrypted (e.g., shareddirkey, token reflection, or compromised/abused issuers).Severity (CVSS v3.1)
Base vector (typical shared‑secret scenario where the attacker must produce a decryptable token):
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H→ 6.5 (MEDIUM)Rationale:
alg=dirand shared keys across services.If arbitrary unprivileged parties can submit JWEs that will be decrypted (PR:N), the base vector becomes:
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H→ 7.5 (HIGH)Mitigations / Workarounds
zip=DEFfor inbound JWEs at the application boundary until a fix is available.zlib.decompress(..., max_length)viadecompressobj().decompress(data, MAX_SIZE)), returning an error when output exceeds a safe limit.Remediation Guidance (for maintainers)
joserfc’s approach: add a conservative maximum output size (e.g., 256 KB by default) and raise a specific error when exceeded; document a controlled way to raise this ceiling for trusted environments.References
authlib/authlib/jose/rfc7518/jwe_zips.py,authlib/authlib/jose/rfc7516/jwe.pySeverity
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:HReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
Authlib JWS JWK Header Injection: Signature Verification Bypass
CVE-2026-27962 / GHSA-wvwj-cvrp-7pv5
More information
Details
Description
Summary
A JWK Header Injection vulnerability in
authlib's JWS implementation allows an unauthenticatedattacker to forge arbitrary JWT tokens that pass signature verification. When
key=Noneis passedto any JWS deserialization function, the library extracts and uses the cryptographic key embedded
in the attacker-controlled JWT
jwkheader field. An attacker can sign a token with their ownprivate 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.pyVulnerable method:
JsonWebSignature._prepare_algorithm_key()Lines: 272–273
When
key=Noneis passed tojws.deserialize_compact(),jws.deserialize_json(), orjws.deserialize(), the library checks the JWT header for ajwkfield. If present, it extractsthat value — which is fully attacker-controlled — and uses it as the verification key.
RFC 7515 violations:
jwkheader parameter is "NOT RECOMMENDED" because keysembedded by the token submitter cannot be trusted as a verification anchor.
context, not from the token itself. There is no step in the RFC that permits falling back to
the
jwkheader 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:
When an attacker submits a token with an unknown
kid, the callable legitimately returnsNone.The library then silently falls through to
key = header["jwk"], trusting the attacker's embeddedkey. The developer never wrote
key=None— the library's fallback logic introduced it. The resultlooks like a verified token with no exception raised, making the substitution invisible.
Attack steps:
{"role": "admin"}).jwkheader field.kidto cause the key resolver to returnNone.header["jwk"]for verification — signature passes.PoC
Tested against authlib 1.6.6 (HEAD
a9e4cfee, Python 3.11).Requirements:
Exploit script:
Expected output:
Docker (self-contained reproduction):
Impact
This is an authentication and authorization bypass vulnerability. Any application using authlib's
JWS deserialization is affected when:
key=Noneis passed directly, orNonefor unknown/rotatedkidvalues (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
jwkheader 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:Recommended safe replacement — raise explicitly when no key is resolved:
Severity
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:NReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
Authlib Vulnerable to JWE RSA1_5 Bleichenbacher Padding Oracle
CVE-2026-28490 / GHSA-7432-952r-cw78
More information
Details
1. Executive Summary
A cryptographic padding oracle vulnerability was identified in the Authlib Python library
concerning the implementation of the JSON Web Encryption (JWE)
RSA1_5key managementalgorithm. Authlib registers
RSA1_5in its default algorithm registry without requiringexplicit opt-in, and actively destroys the constant-time Bleichenbacher mitigation that
the underlying
cryptographylibrary implements correctly.When
cryptographyencounters an invalid PKCS#1 v1.5 padding, it returns a randomizedbyte string instead of raising an exception — the correct behavior per RFC 3218 §2.3.2.
Authlib ignores this contract and raises
ValueError('Invalid "cek" length')immediatelyafter decryption, before reaching AES-GCM tag validation. This creates a clean, reliable
Exception Oracle:
cryptographyreturns random bytes → Authlib length check fails→
ValueError: Invalid "cek" lengthfails →
InvalidTagThis oracle is active by default in every Authlib installation without any special
configuration by the developer or the attacker. The three most widely used Python web
frameworks — Flask, Django, and FastAPI — all expose distinguishable HTTP responses for
these two exception classes in their default configurations, requiring no additional
setup to exploit.
Empirically confirmed on authlib 1.6.8 + cryptography 46.0.5:
2. Technical Details & Root Cause
2.1 Vulnerable Code
File:
authlib/jose/rfc7518/jwe_algs.py2.2 Root Cause — Active Mitigation Destruction
cryptography46.0.5 implements the Bleichenbacher mitigation correctly at the librarylevel. When PKCS#1 v1.5 padding validation fails, it does not raise an exception.
Instead it returns a randomized byte string (empirically observed: 84 bytes for a
2048-bit RSA key). The caller is expected to pass this fake key to the symmetric
decryptor, where MAC/tag validation will fail in constant time — producing an error
indistinguishable from a MAC failure on a valid padding.
Authlib does not honor this contract. The length check on the following line detects
that 84 bytes != 16 bytes (128-bit CEK for A128GCM) and raises
ValueError('Invalid "cek" length')immediately. This exception propagates before AES-GCM is ever reached,creating two execution paths with observable differences:
The single line
raise ValueError('Invalid "cek" length')is the complete root cause.Removing the raise and replacing it with a silent random CEK fallback eliminates both
the exception oracle and any residual timing difference.
2.3 Empirical Confirmation
All results obtained on authlib 1.6.8 / cryptography 46.0.5 / Linux x86_64
running the attached PoC (
poc_bleichenbacher.py):Note on timing: The 0.287ms delta is within the noise margin (stdev ~1ms across
50 iterations) and is not claimed as a reliable standalone timing oracle. The exception
oracle is the primary exploitable vector and does not require timing measurement.
3. Default Framework Behavior — Why This Is Exploitable Out of the Box
A potential objection to this report is that middleware or custom error handlers could
normalize exceptions to a single HTTP response, eliminating the observable discrepancy.
This section addresses that objection directly.
The oracle is active in default configurations of all major Python web frameworks.
No special server misconfiguration is required. The following demonstrates the default
behavior for Flask, Django, and FastAPI — the three most widely deployed Python web
frameworks — when an unhandled exception propagates from a route handler:
Flask (default configuration)
Flask's default error handler returns the exception message in the response body for
debug mode, and an empty 500 for production. However, even in production, the response
body content differs between
ValueError(which has a message) andInvalidTag(which has no message), leaking the oracle through response body length.
FastAPI (default configuration)
FastAPI normalizes both to HTTP 500 in production. However, FastAPI's default
RequestValidationErrorandHTTPExceptionhandlers do not catch arbitrary exceptions,so the distinguishable stack trace is logged — and in many deployments, error monitoring
tools (Sentry, Datadog, etc.) expose the exception class to operators, enabling oracle
exploitation by an insider or via log exfiltration.
Django REST Framework (default configuration)
Summary: Even in cases where HTTP status codes are normalized, the oracle persists
through response body differences, response timing, or error monitoring infrastructure.
The RFC 3218 §2.3.2 requirement exists precisely because any observable difference —
regardless of channel — is sufficient for a Bleichenbacher attack. The library is
responsible for eliminating the discrepancy at the source, not delegating that
responsibility to application developers.
This is a library-level vulnerability. Requiring every application developer to
implement custom exception normalization to compensate for a cryptographic flaw in
the library violates the principle of secure defaults. The fix must be in Authlib.
4. Specification Violations
RFC 3218 — Preventing the Million Message Attack on CMS
Section 2.3.2 (Mitigation):
This is an absolute requirement with no exceptions for "application-level mitigations."
Authlib violates this by raising a different exception class for padding failures than
for MAC failures. The
cryptographylibrary already implements the correct mitigationfor this exact scenario — Authlib destroys it with a single length check.
RFC 7516 — JSON Web Encryption
Section 9 (Security Considerations):
Authlib enables exactly this scenario. Two structurally different encrypted keys
(one with invalid padding, one with valid padding but wrong CEK) produce two different
exception classes. This is the exact condition RFC 7516 §9 warns against.
5. Attack Scenario
The attacker identifies an Authlib-powered endpoint that decrypts JWE tokens.
Because
RSA1_5is in the default registry, no special server configurationis required.
The attacker obtains the server RSA public key — typically available via the
JWKS endpoint (
/.well-known/jwks.json), which is standard in OIDC deployments.The attacker crafts JWE tokens with the
RSA1_5algorithm and submits a streamof requests to the endpoint, manipulating the
ekcomponent per Bleichenbacher'salgorithm.
The server responds with observable differences between the two paths:
ValueErrorpath → distinguishable response (exception message, timing, orerror monitoring artifact)
InvalidTagpath → different distinguishable responseBy observing these oracle responses across thousands of requests, the attacker
geometrically narrows the PKCS#1 v1.5 plaintext boundaries until the CEK is
fully recovered.
With the CEK recovered:
Prerequisites:
RSA1_5(active by default)(present by default in Flask, Django, FastAPI without custom error handling)
duration but does not prevent it)
6. Remediation
6.1 Immediate — Remove RSA1_5 from Default Registry
Remove
RSA1_5from the defaultJWE_ALG_ALGORITHMSregistry. Users requiringlegacy RSA1_5 support should explicitly opt-in with a documented security warning.
This eliminates the attack surface for all users not requiring this algorithm.
6.2 Code Fix — Restore Constant-Time Behavior
The
unwrapmethod must never raise an exception that distinguishes padding failurefrom MAC failure. The length check must be replaced with a silent random CEK fallback,
preserving the mitigation that
cryptographyimplements.Suggested Patch (
authlib/jose/rfc7518/jwe_algs.py):Result: Both paths return a CEK of the correct length. AES-GCM tag validation
fails for both, producing
InvalidTagin both cases. The exception oracle iseliminated. Empirically validated via TEST 5 of the attached PoC.
7. Proof of Concept
Setup:
See attached
poc_bleichenbacher.py. All 5 tests run against the real installedauthlib module without mocks.
Confirmed Output (authlib 1.6.8 / cryptography 46.0.5 / Linux x86_64):
Code
Output
Severity
CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:L/VA:N/SC:N/SI:N/SA:NReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
Authlib: Fail-Open Cryptographic Verification in OIDC Hash Binding
CVE-2026-28498 / GHSA-m344-f55w-2m6j
More information
Details
1. Executive Summary
A critical library-level vulnerability was identified in the Authlib Python library concerning the validation of OpenID Connect (OIDC) ID Tokens. Specifically, the internal hash verification logic (
_verify_hash) responsible for validating theat_hash(Access Token Hash) andc_hash(Authorization Code Hash) claims exhibits a fail-open behavior when encountering an unsupported or unknown cryptographic algorithm.This flaw allows an attacker to bypass mandatory integrity protections by supplying a forged ID Token with a deliberately unrecognized
algheader parameter. The library intercepts the unsupported state and silently returnsTrue(validation passed), inherently violating fundamental cryptographic design principles and direct OIDC specifications.2. Technical Details & Root Cause
The vulnerability resides within the
_verify_hash(signature, s, alg)function inauthlib/oidc/core/claims.py:When an unsupported algorithm string (e.g.,
"XX999") is processed by the helper functioncreate_half_hashinauthlib/oidc/core/util.py, the internalgetattr(hashlib, hash_type, None)call fails, and the function correctly returnsNone.However, instead of triggering a
Fail-Closedcryptographic state (raising an exception or returningFalse), the_verify_hashfunction misinterprets theNonereturn value and explicitly returnsTrue.Because developers rely on the s