Skip to main content
VulnerabilityPublished Updated

CVE-2026-28490: Safety · Authlib Vulnerable to JWE RSA1_5 Bleichenbacher Padding Oracle

Affects safetySource GCVE Database

0
Compare

Not known to be exploited · CVSS 8.3 High : upgrade to 3.7.0_6 soon.

Data as of 30 Oct 2026, 07:30 UTC

CVSS 4.0 base score
8.3High
How severe the flaw is on the 0–10 CVSS scale.
Patch
Available – fixed in 3.7.0_6
CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:L/VA:N/SC:N/SI:N/SA:N

Exploitation evidence

  1. Disclosed: evidence found.

    CVE published 13 Aug 2026

  2. Detectable: no evidence on record.

    No public nuclei template indexed

  3. Weaponized: no evidence on record.

    No public exploit code indexed in Metasploit or Exploit-DB

  4. Exploited in the wild: no evidence on record.

    Not in CISA KEV and no source reports exploitation

  5. Observed by OffSeq Mirage: no evidence on record.

    No attack traffic recorded by OffSeq Mirage sensors

A missing step is not evidence of safety. Sources: cve.org (opens in a new tab), the Metasploit, Exploit-DB and nuclei-templates index as of 29 Oct 2026.

What to do

Upgrade safety to 3.7.0_6.

Affected software

ProductAffectedFixed in
Homebrewsafetypkg:brew/safetyOther threatsAffected
  • >=3.2.4 <3.7.0_6
Fixed in
  • 3.7.0_6

Check your own hosts for these packages with threat-finder (opens in a new tab), our free open-source scanner.

Description

## 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_5` key management algorithm. Authlib registers `RSA1_5` in its default algorithm registry without requiring explicit opt-in, and actively destroys the constant-time Bleichenbacher mitigation that the underlying `cryptography` library implements correctly. When `cryptography` encounters an invalid PKCS#1 v1.5 padding, it returns a randomized byte 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')` immediately after decryption, before reaching AES-GCM tag validation. This creates a clean, reliable **Exception Oracle**: - **Invalid padding** → `cryptography` returns random bytes → Authlib length check fails → `ValueError: Invalid "cek" length` - **Valid padding, wrong MAC** → decryption succeeds → length check passes → AES-GCM fails → `InvalidTag` **This 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:** ``` [PADDING INVALIDO] ValueError: Invalid "cek" length [PADDING VALIDO/MAC] InvalidTag ``` --- ## 2. Technical Details & Root Cause ### 2.1 Vulnerable Code **File:** `authlib/jose/rfc7518/jwe_algs.py` ```python def unwrap(self, enc_alg, ek, headers, key): op_key = key.get_op_key("unwrapKey") # cryptography implements Bleichenbacher mitigation here: # on invalid padding it returns random bytes instead of raising. # Empirically confirmed: returns 84 bytes for a 2048-bit key. cek = op_key.decrypt(ek, self.padding) # VULNERABILITY: This length check destroys the mitigation. # cryptography returned 84 random bytes. len(84) * 8 = 672 != 128 (A128GCM CEK_SIZE). # Authlib raises a distinct ValueError before AES-GCM is ever reached. if len(cek) * 8 != enc_alg.CEK_SIZE: raise ValueError('Invalid "cek" length') # <- ORACLE TRIGGER return cek ``` ### 2.2 Root Cause — Active Mitigation Destruction `cryptography` 46.0.5 implements the Bleichenbacher mitigation correctly at the library level. 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: ``` Path A — invalid PKCS#1 v1.5 padding: op_key.decrypt() -> 84 random bytes (cryptography mitigation active) len(84) * 8 = 672 != 128 (CEK_SIZE for A128GCM) raise ValueError('Invalid "cek" length') <- specific exception, fast path Path B — valid padding, wrong symmetric key: op_key.decrypt() -> 16 correct bytes len(16) * 8 = 128 == 128 -> length check passes AES-GCM tag validation -> mismatch raise InvalidTag <- different exception class, slow path ``` 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`):** ``` TEST 1 - cryptography behavior on invalid padding: cryptography retorno bytes: len=84 NOTA: esta version implementa mitigacion de random bytes TEST 2 - Exception Oracle: [ORACLE] Caso A (padding invalido): ValueError: Invalid "cek" length [OK] Caso B (padding valido/MAC malo): InvalidTag TEST 3 - Timing (50 iterations): Padding invalido (ValueError) mean=1.500ms stdev=1.111ms Padding valido (InvalidTag) mean=1.787ms stdev=0.978ms Delta: 0.287ms TEST 4 - RSA1_5 in default registry: [ORACLE] RSA1_5 activo por defecto (no opt-in required) TEST 5 - Fix validation: [OK] Both paths return correct-length CEK after patch [OK] Exception type identical in both paths -> oracle eliminated ``` **Note on timing:** The 0.287ms delta is within the noise margin (stdev ~1ms across 50 iterati

References

Community reviews

Loading reviews…