Jun 4, 2026·7 min read·4 visits
An algorithm-confusion vulnerability in PyJWT allows remote attackers to bypass authentication by signing forged tokens with a public JWK string treated as a symmetric HMAC secret.
CVE-2026-48526 is an algorithm-confusion vulnerability in PyJWT prior to version 2.13.0. When an application decodes tokens using a raw JSON Web Key (JWK) string while simultaneously supporting mixed algorithm families (symmetric and asymmetric), PyJWT does not validate that the key matches its intended algorithm context. This allows an attacker to sign a forged token using the public JWK string as an HMAC symmetric secret, bypassing authentication controls.
JSON Web Tokens (JWT) are widely adopted for stateless authentication and authorization in web applications. To maintain security, verifying applications must ensure that tokens are validated using the correct cryptographic algorithm and key. The pyjwt library provides token encoding and decoding functionality for Python applications.
CVE-2026-48526 identifies a critical algorithm-confusion vulnerability in pyjwt before version 2.13.0. The flaw manifests when an application validates tokens using keys supplied as raw JSON Web Key (JWK) strings and supports mixed algorithm families, such as allowing both asymmetric RS256 and symmetric HS256 validation. In this scenario, the library fails to validate that the key material matches the chosen algorithm family.
An attacker with access to the public JWK can sign a forged token using the raw JWK JSON string as the HMAC symmetric secret. The target backend processes the forged token with the HS256 algorithm, uses the public JWK string as the symmetric key, and successfully verifies the signature. This behavior enables a complete authentication bypass and unauthorized privilege escalation.
The root cause of CVE-2026-48526 lies in the key preparation phase of pyjwt's signature verification logic. To prevent traditional algorithm-confusion attacks, the library verifies that keys passed to the HMACAlgorithm class are not PEM-formatted or SSH public keys. This validation is designed to prevent asymmetric public keys from being interpreted as symmetric HMAC secrets.
However, this defense relies on the assumption that public keys are only provided in PEM or SSH formats. Public keys represented as structured JSON Web Keys (JWK) bypass this validation because they do not contain the typical header and footer markers of PEM or SSH keys. Consequently, the HMACAlgorithm class accepts the raw byte representation of a JWK JSON document as a valid HMAC secret.
When a developer configures an application to accept both symmetric and asymmetric algorithms (mixed families) and passes a raw JWK string to the decoder, a logical vulnerability is introduced. The application delegates the selection of the verification algorithm to the 'alg' header of the incoming token. If the token specifies an HMAC algorithm like HS256, the library utilizes the HMAC path and treats the raw JWK string as the HMAC shared secret.
Prior to version 2.13.0, the prepare_key method in jwt/algorithms.py processed keys without checking for structured JSON metadata. The function received the key, converted it to bytes, and performed basic PEM and SSH checks. Below is the vulnerable implementation of the method:
# Vulnerable implementation in jwt/algorithms.py
def prepare_key(self, key: str | bytes) -> bytes:
key_bytes = force_bytes(key)
if is_pem_format(key_bytes) or is_ssh_key(key_bytes):
raise InvalidKeyError(
"The specified key is an asymmetric key or x509 certificate and"
" should not be used as an HMAC secret."
)
return key_bytesThe fix introduced in commit 95791b1759b8aa4f2203575d344d5c78564cdc81 enhances the validation mechanism. It strips leading whitespace and determines if the input byte sequence begins with the character {, which indicates a JSON payload. If the string is valid JSON and contains the 'kty' (key type) key, the library rejects the key to prevent its use as an HMAC secret.
# Patched implementation in jwt/algorithms.py
def prepare_key(self, key: str | bytes) -> bytes:
key_bytes = force_bytes(key)
if len(key_bytes) == 0:
raise InvalidKeyError("HMAC key must not be empty.")
if is_pem_format(key_bytes) or is_ssh_key(key_bytes):
raise InvalidKeyError(
"The specified key is an asymmetric key or x509 certificate and"
" should not be used as an HMAC secret."
)
stripped = key_bytes.lstrip()
if stripped.startswith(b"{"):
try:
jwk_obj = json.loads(key_bytes)
except ValueError:
jwk_obj = None
if isinstance(jwk_obj, dict) and "kty" in jwk_obj:
raise InvalidKeyError(
"The specified key looks like a JWK and should not be "
"used directly as an HMAC secret. Load it via "
"PyJWK / HMACAlgorithm.from_jwk first."
)
return key_bytesExploiting CVE-2026-48526 requires three primary conditions. First, the application must verify tokens using a list of mixed algorithms (e.g., RS256 and HS256). Second, the application must pass the raw JSON JWK string directly as the verification key. Third, the attacker must have access to the exact JSON representation of the public JWK, which is standard for public JWK endpoints.
The attacker retrieves the public JWK from the victim server's public key endpoint. Next, the attacker constructs a malicious payload, setting the 'alg' header to 'HS256' and modifying claims to escalate privileges. Using the raw public JWK JSON string as the symmetric key, the attacker signs the token using HMAC-SHA256. Upon receiving the token, pyjwt sees the 'HS256' algorithm, retrieves the public JWK string, and performs symmetric verification. The signatures match, bypassing authentication.
While the implemented defense-in-depth patch significantly reduces the attack surface, security analysis reveals potential gaps in the validation logic. One notable gap is Byte Order Mark (BOM) confusion. The patched code calls key_bytes.lstrip() to remove leading standard ASCII whitespace before checking if the string starts with b'{'. If a JWK contains a Unicode BOM, such as a UTF-8 BOM, the startswith check evaluates to False, bypassing the JSON check while still being decodable by standard JSON libraries.
Another critical bypass vector involves JSON Web Key Sets (JWKS). The patch evaluates whether the decoded JSON object is a dictionary containing the 'kty' key. However, public keys are frequently distributed within a JWKS, which wraps multiple JWK objects inside a 'keys' list. If a developer incorrectly passes a full JWKS JSON string to the decoder, the parsed object is a dictionary but contains 'keys' instead of 'kty', bypassing the check.
These edge cases highlight the limitations of signature-based or format-based heuristics. They emphasize that security controls must not rely on parsing structure to determine key validity. Instead, applications must enforce strict separation of algorithm families and validate keys using cryptographic typing.
The primary remediation for CVE-2026-48526 is upgrading the pyjwt library to version 2.13.0 or later. This upgrade integrates the JSON verification check within the key preparation process, preventing raw JWKs from being misinterpreted as HMAC secrets. Ensure that all dependency files are updated and redeployed across target environments.
In addition to upgrading, developers must implement secure key handling practices. Avoid using mixed algorithm families within the same verification path. If an endpoint is designed to process tokens signed with asymmetric keys, restrict the accepted algorithms strictly to asymmetric protocols like RS256. This prevents the library from falling back to symmetric verification paths.
# Secure configuration using PyJWK
from jwt import PyJWK
jwk_dict = {"kty": "RSA", "n": "...", "e": "AQAB"}
jwk_obj = PyJWK(jwk_dict)
# Secure decoding
jwt.decode(token, jwk_obj.key, algorithms=["RS256"])Lastly, ensure that raw JWK JSON strings are never passed directly to jwt.decode(). Use the structured PyJWK class to explicitly deserialize the JSON into a cryptographic key object prior to verification. This forces the library to evaluate the key context before signature verification, rendering algorithm-confusion attacks ineffective.
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
pyjwt jpadilla | < 2.13.0 | 2.13.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-287 |
| Attack Vector | Network |
| CVSS | 7.4 |
| EPSS Score | 0.00017 |
| Impact | High |
| Exploit Status | Proof-of-Concept |
| KEV Status | Not Listed |
The system does not prove or insufficiently proves that an identity claim is correct.
CVE-2026-23479 is a critical Use-After-Free (UAF) vulnerability inside the blocking-client code path of the Redis in-memory data structure server. In affected versions from 7.2.0 until 8.6.3, the unblock client flow fails to handle an error return from processCommandAndResetClient when re-executing a previously blocked command. If a blocked client is evicted due to maxmemory limits or client eviction policies during this command processing flow, its client structure is freed. Because the caller ignores the error return and continues processing, it attempts to read and write properties on the freed client structure, leading to a Use-After-Free condition.
A critical vulnerability exists in React Router v7 when running in Framework Mode. The vulnerability arises from insecure deserialization of TYPE_ERROR objects in the internal turbo-stream library, which resolves constructors from the global scope. If an application contains an independent prototype pollution vulnerability, an attacker can trigger unauthenticated Remote Code Execution (RCE) on the server.
AIOHTTP prior to version 3.14.0 fails to clear request-specific cookies when executing cross-origin automatic HTTP redirects. This vulnerability allows remote web servers to harvest sensitive credentials and session cookies originally scoped to an authorized target domain.
An unauthenticated path traversal vulnerability in BrowserStack Runner versions up to and including 0.9.5 allows remote or adjacent network attackers to read arbitrary files from the host system. The flaw exists within the local HTTP test server's fallback and patch file handlers, which fail to sanitize path inputs before passing them to file resolution APIs.
An unauthenticated remote code execution (RCE) vulnerability exists in the browserstack-runner npm package (versions up to and including 0.9.5). The flaw lies in the /_log HTTP endpoint handler, which evaluates user-supplied input within a non-secure Node.js VM context combined with dynamic eval() execution. Network-adjacent attackers can exploit this behavior to escape the sandbox and execute arbitrary system commands on the host machine.
An architectural flaw in the Froxlor server administration control panel allows attackers to completely bypass Two-Factor Authentication (2FA) by issuing commands directly through the API. The API authentication routine in 'FroxlorRPC::validateAuth' fails to check the account's 2FA status, enabling arbitrary execution of administrative and customer actions. Furthermore, in versions prior to 2.3.7, API keys could be created without validating the current user password, exposing users to persistent backdoor access via session hijacking or CSRF.