← Blog · · df00tech

PyJWT Advisory: Incomplete PEM Guard Allowed HS256/Asymmetric Algorithm-Confusion Forgery (CVE-2026-102268), Fixed in 2.14.0

breaking ghsa pip CVE-2026-102268

A newly published GitHub Security Advisory (GHSA-ffc3-869f-jxw9, CVE-2026-102268, CVSS 9.1, CWE-347) reports that PyJWT's guard against HMAC/asymmetric algorithm confusion could be bypassed using specially formatted PEM public keys.

What was reported

According to the advisory, PyJWT's HMACAlgorithm.prepare_key rejects asymmetric keys used as HMAC secrets by checking a helper, is_pem_format(), which uses a regex requiring exact \r?\n line endings and tightly anchored BEGIN/END markers. The cryptography library's PEM loader is more permissive: it accepts PEM text with marker-adjacent whitespace, CR-only line terminators, or a PEM folded onto a single line. When a public key is supplied in one of these loader-accepted-but-regex-missed forms, PyJWT's guard fails to recognize it as PEM, and the key text is passed through unchanged and used as the HMAC secret. The maintainers state they reproduced this on PyJWT 2.13.0, confirming that an attacker who knows the public key can then forge tokens accepted under HS256. Two conditions are required: the caller's algorithms=[...] allow-list must mix an HMAC algorithm with an asymmetric one, and the verification key must be passed as raw PEM (not via PyJWK) in one of the affected byte-forms. The PyJWK path is stated to be unaffected.

Why it matters

This is a variant of the well-known JWT algorithm-confusion class (the RFC 8725 footgun previously addressed by CVE-2022-29217). Per the advisory, if the two preconditions are met, an attacker needs only the public verification key — public by definition — to mint arbitrary-claim tokens that verify as authentic, which the advisory characterizes as universal forgery. Any Python service using PyJWT with a mixed algorithm allow-list and raw PEM key input is potentially exposed, regardless of whether the mixed-list mistake was intentional.

What defenders should do now

  • Upgrade PyJWT to 2.14.0, which the maintainers confirm is the first release containing the fix (per the 2026-09-11 update, fix commit 8b4e233a22206b34ec1186e912e75c0b2396ac07).
  • Audit your codebase for any jwt.decode(...) calls whose algorithms= list mixes HMAC (e.g. HS256) with an asymmetric algorithm (e.g. RS256/ES256) — this is an anti-pattern independent of this bug and should generally be avoided by pinning a single expected algorithm per key.
  • Review how verification key material is sourced and stored (config files, environment variables, YAML/JSON blocks) — the advisory notes that indentation, single-line env-var encoding, or CR/LF round-tripping through config tooling can all naturally produce the affected PEM byte-forms.
  • Prefer the PyJWK verification path where feasible, since the advisory states it binds a single algorithm and is not affected by this issue.
  • For hunting/detection purposes, consider auditing application logs or code for successful JWT verifications using HS256 where the configured key material originates from a known asymmetric public key.

Developing intel

This item is based on a GitHub Security Advisory published same-day; details above reflect the maintainers' own reproduction and fix notes as posted. Consult the original advisory for full technical detail, proof-of-concept steps, and updates: GHSA-ffc3-869f-jxw9.

Get new detections in your inbox

New ATT&CK coverage plus CISA KEV / CVE detection rules, roughly weekly. No spam, unsubscribe anytime.