CVE-2026-28802 Overview
CVE-2026-28802 is an Authentication Bypass vulnerability in Authlib, a Python library used to build OAuth and OpenID Connect servers. From version 1.6.5 to before version 1.6.7, a critical flaw existed where malicious JSON Web Tokens (JWTs) containing alg: none and an empty signature could pass signature verification without any changes to the application code. This allowed attackers to forge arbitrary JWT tokens and bypass authentication mechanisms entirely.
Critical Impact
Attackers can forge JWT tokens by exploiting the "none" algorithm vulnerability, completely bypassing authentication and gaining unauthorized access to protected resources.
Affected Products
- Authlib versions >= 1.6.5 and < 1.6.7
- Applications using Authlib's default JWT instance for token verification
- OAuth and OpenID Connect servers built with vulnerable Authlib versions
Discovery Timeline
- 2026-03-06 - CVE CVE-2026-28802 published to NVD
- 2026-03-09 - Last updated in NVD database
Technical Details for CVE-2026-28802
Vulnerability Analysis
This vulnerability represents a classic JWT algorithm confusion attack, specifically exploiting improper handling of the "none" algorithm in JSON Web Signature (JWS) implementations. The core issue lies in how Authlib's NoneAlgorithm class handled signature verification. When an attacker crafted a JWT with "alg": "none" in the header and provided an empty signature, the verification function incorrectly accepted it as valid.
The vulnerability is particularly dangerous because it affects the default JWT instance exported by Authlib. Applications importing and using jwt from authlib.jose were automatically vulnerable, as the default instance included all algorithms in the registry—including the problematic "none" algorithm.
Root Cause
The root cause was a logic error in the NoneAlgorithm.verify() method. The original implementation returned False unconditionally, which should have rejected all tokens using the "none" algorithm. However, when combined with how the algorithm was registered in the default JWT instance, attackers could craft tokens that bypassed this check entirely. The fix corrected the verify method to properly validate that the signature is indeed empty (sig == b""), and more importantly, removed the "none" algorithm from the default JWT instance's allowed algorithms list.
Attack Vector
The attack vector is network-based and requires no authentication or user interaction. An attacker can exploit this vulnerability by:
- Crafting a malicious JWT with a forged payload containing arbitrary claims
- Setting the algorithm header to "alg": "none"
- Providing an empty signature segment
- Submitting this token to any endpoint using Authlib's default JWT verification
The following patches demonstrate the security fixes implemented:
Fix 1: Correcting the NoneAlgorithm verify method:
return b""
def verify(self, msg, sig, key):
- return False
+ return sig == b""
class HMACAlgorithm(JWSAlgorithm):
Source: GitHub Commit a61c2ac
Fix 2: Removing "none" from the default JWT instance:
-jwt = JsonWebToken(list(JsonWebSignature.ALGORITHMS_REGISTRY.keys()))
+jwt = JsonWebToken(
+ [
+ "HS256",
+ "HS384",
+ "HS512",
+ "RS256",
+ "RS384",
+ "RS512",
+ "ES256",
+ "ES384",
+ "ES512",
+ "PS256",
+ "PS384",
+ "PS512",
+ ]
+)
Source: GitHub Commit b87c32e
Detection Methods for CVE-2026-28802
Indicators of Compromise
- JWT tokens with "alg": "none" in the decoded header being accepted by your application
- Authentication logs showing successful authentications with malformed or suspicious tokens
- Unexpected privilege escalation or unauthorized access patterns in application logs
- JWT tokens with empty or missing signature segments (third part of the token) being processed
Detection Strategies
- Implement logging for all JWT verification attempts, capturing the algorithm used in each token
- Deploy Web Application Firewall (WAF) rules to detect and block JWTs containing alg: none in the header
- Audit application code for direct usage of from authlib.jose import jwt and verify the Authlib version
- Use dependency scanning tools to identify vulnerable Authlib versions in your software supply chain
Monitoring Recommendations
- Monitor authentication endpoints for anomalous token patterns, particularly tokens with unusual algorithm specifications
- Set up alerts for any JWT verification failures followed by unexpected successful authentications
- Review access logs for authenticated sessions that bypass normal authentication flows
- Implement real-time monitoring for changes in token structure or algorithm usage patterns
How to Mitigate CVE-2026-28802
Immediate Actions Required
- Upgrade Authlib to version 1.6.7 or later immediately
- Audit all applications using Authlib to ensure they explicitly specify allowed algorithms rather than using defaults
- Review authentication logs for any signs of exploitation during the vulnerable period
- If upgrading is not immediately possible, implement the workaround to explicitly restrict allowed algorithms
Patch Information
The vulnerability has been patched in Authlib version 1.6.7. The fix consists of two key changes: correcting the NoneAlgorithm.verify() method to properly validate empty signatures, and removing the "none" algorithm from the default JWT instance. Security patches are available via the following commits:
- GitHub Commit a61c2ac - Corrects the verify method
- GitHub Commit b87c32e - Removes "none" from default algorithms
For complete details, see the GitHub Security Advisory GHSA-7wc2-qxgw-g8gg.
Workarounds
- Create a custom JWT instance with explicitly defined safe algorithms instead of using the default instance
- Implement server-side validation to reject any tokens with alg: none before passing to Authlib
- Add application-layer checks to verify the algorithm header matches expected values (e.g., RS256, ES256)
- Deploy API gateway rules to filter out tokens containing the "none" algorithm
# Secure configuration example - explicitly specify allowed algorithms
from authlib.jose import JsonWebToken
# Create a JWT instance with only secure algorithms
secure_jwt = JsonWebToken([
"RS256",
"RS384",
"RS512",
"ES256",
"ES384",
"ES512",
])
# Use secure_jwt instead of the default jwt import
claims = secure_jwt.decode(token, key)
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

