
CVE-2026-29000 PoC: bypass de autenticación pac4j-jwt PlainJWT-in-JWE.
Prueba de concepto para CVE-2026-29000. Afecta a versiones de pac4j-jwt anteriores a 4.5.9, 5.7.9 y 6.3.3.
La vulnerabilidad es sencilla: la librería acepta un PlainJWT (sin firmar, alg=none) siempre que esté envuelto dentro de un JWE válido. Dado que el servidor expone su clave pública RSA a través de un endpoint JWKS, cualquiera puede cifrar un JWT arbitrario sin firmar dentro de un JWE que el servidor confiará, incluido uno con ROLE_ADMIN.
alg=none) con los claims que quierasEl servidor lo descifra, confía en los claims internos y nunca verifica que el JWT interno no esté firmado.
Python 3.13+ con uv, o instala las dependencias manualmente:
pip install jwcrypto requests
[uv run / python3] CVE-2026-29000.py --url <base_url> --jwks <jwks_path> [opciones]
Obligatorios:
| flag | descripción |
|---|---|
--url | URL base del objetivo, p. ej. http://10.10.11.x:8080 |
--jwks | ruta o URL completa del endpoint JWKS |
Opcionales:
Ejemplos:
python3 exploit.py --url http://10.10.11.x:8080 --jwks /api/auth/jwks
python3 exploit.py --url http://10.10.11.x:8080 --jwks /api/auth/jwks --user john --role ROLE_ADMIN
python3 exploit.py --url http://10.10.11.x:8080 --jwks /.well-known/jwks.json --enc A128GCM
No siempre es obvio. Buenos lugares para buscar:
/robots.txt — a menudo lista rutas restringidas o internas/api/auth/jwks/.well-known/jwks.json/.well-known/openid-configurationSi el token es rechazado, la aplicación podría esperar un algoritmo de cifrado específico. Revisa /static/js/app.js para algo como:
const JWE_ALG = "RSA-OAEP-256";
const JWE_ENC = "A128GCM";
Luego vuelve a ejecutar con --enc A128GCM.
El método de almacenamiento del token también suele estar ahí:
class TokenManager {
static getToken() {
return sessionStorage.getItem('auth_token');
}
}
Si es sessionStorage, intercambia el token directamente en DevTools bajo Application > Session Storage.
Corregido en 4.5.9, 5.7.9 y 6.3.3.
| flag | predeterminado | descripción |
|---|
--user | admin | valor para el claim sub |
--role | ROLE_ADMIN | rol a falsificar (ROLE_ADMIN, ROLE_MANAGER, ROLE_USER) |
--issuer | principal-platform | valor para el claim iss |
--enc | A256GCM | cifrado de contenido JWE (A256GCM o A128GCM) |