CVE-2025-61152 Overview
CVE-2025-61152 affects the python-jose library through version 3.3.0. The library accepts JSON Web Tokens (JWTs) with the alg=none header and decodes them without cryptographic signature verification. An attacker can craft a forged token containing arbitrary claims, such as is_admin=true, and submit it to applications that rely on python-jose for token validation. The behavior can lead to authentication bypass and privilege escalation in downstream applications ([CWE-269]).
All parties involved agree the issue is only reachable when developers explicitly configure verify_signature: False, and therefore the report is contested as not being a library defect. The advisory remains published to inform integrators reviewing their JWT validation logic.
Critical Impact
Applications passing verify_signature=False to python-jose may accept alg=none tokens with attacker-controlled claims, enabling unauthorized access or privilege escalation.
Affected Products
- python-jose versions through 3.3.0
- Python applications using python-jose for JWT decoding with verify_signature=False
- Downstream services depending on python-jose for authentication token validation
Discovery Timeline
- 2025-10-10 - CVE-2025-61152 published to the National Vulnerability Database
- 2026-06-17 - Last updated in NVD database
Technical Details for CVE-2025-61152
Vulnerability Analysis
JSON Web Tokens carry a header field named alg that specifies the signing algorithm. The none algorithm value indicates an unsigned token and was defined in the original JWT specification. Libraries that honor alg=none without checking application intent risk accepting tokens that were never cryptographically signed.
In python-jose through 3.3.0, the jwt.decode function honors alg=none when the caller disables signature verification with verify_signature=False. The library does not enforce a separate check that rejects unsigned tokens in this state. An attacker who can submit a token to such an endpoint controls every claim in the payload, including identity, roles, and expiration.
The issue is categorized as improper privilege management ([CWE-269]) because forged claims can grant elevated permissions inside applications that trust decoded token contents.
Root Cause
The root cause is a library design choice that treats alg=none as a valid decoding path when the caller opts out of signature verification. The library relies on the developer to reject alg=none explicitly rather than blocking the algorithm by default when verification is disabled. Applications that decode tokens for inspection but then trust the resulting claims for authorization decisions fall directly into the failure mode.
Attack Vector
An attacker constructs a JWT with the header {"alg":"none","typ":"JWT"}, sets the payload to arbitrary claims, and appends an empty signature segment. The attacker submits the token to any endpoint that decodes it using python-jose with verify_signature=False. The application then reads attacker-controlled claims as if they were authenticated. No credentials, user interaction, or prior access are required.
A sanitized description of the exploitation flow appears in the public advisory referenced below. See the GitHub CVE-2025-61152 Advisory for the proof-of-concept details.
Detection Methods for CVE-2025-61152
Indicators of Compromise
- Inbound JWTs whose header decodes to {"alg":"none"} reaching authentication or authorization endpoints
- Requests bearing JWTs with an empty third segment following the final . separator
- Application logs showing successful authentication events that lack a corresponding signature verification log entry
- Sudden appearance of privileged claims such as is_admin=true or elevated role values from unexpected source addresses
Detection Strategies
- Grep application source and dependencies for verify_signature=False, options={"verify_signature": False}, and calls to jwt.get_unverified_claims used for authorization
- Inventory Python projects that pin python-jose<=3.3.0 in requirements.txt, poetry.lock, or Pipfile.lock
- Add web application firewall or API gateway rules that decode the JWT header and block tokens where alg equals none
Monitoring Recommendations
- Log the alg value of every JWT accepted by authentication middleware and alert on any non-approved algorithm
- Correlate authentication events with downstream privilege changes to detect claim tampering
- Track dependency inventories via software composition analysis (SCA) tools and flag any deployment of python-jose at or below 3.3.0
How to Mitigate CVE-2025-61152
Immediate Actions Required
- Audit all uses of python-jose and remove any call that passes verify_signature=False when the decoded claims are used for authorization
- Enforce an allow-list of signing algorithms such as RS256, ES256, or HS256 and reject none explicitly
- Rotate any JWT signing keys that may have been exposed through logs or code paths that skipped verification
- Re-issue tokens for active sessions after remediation to invalidate any forged tokens still in circulation
Patch Information
At the time of publication, the maintainers and reporters agree the behavior only surfaces when the caller sets verify_signature: False, and no library patch is listed in NVD. Consult the GitHub Python-Jose Issue #391 and the PyPI Python-Jose Package page for the current maintenance status and any successor libraries recommended by the maintainers.
Workarounds
- Wrap jwt.decode calls in a helper that rejects tokens whose header contains alg=none before any claim is read
- Pass an explicit algorithms=["RS256"] (or the algorithm your issuer uses) argument to every jwt.decode call and keep signature verification enabled
- Where token introspection without verification is genuinely required, isolate that logic and never use the resulting claims for authorization decisions
# Configuration example: reject alg=none before decoding
python - <<'PY'
from jose import jwt
def safe_decode(token, key, algorithms):
header = jwt.get_unverified_header(token)
if header.get("alg", "").lower() == "none":
raise ValueError("Unsigned JWT rejected")
if header.get("alg") not in algorithms:
raise ValueError("Disallowed JWT algorithm")
return jwt.decode(token, key, algorithms=algorithms)
PY
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

