The RFC loophole
RFC 7518 §3.6 defines none as a valid JWA algorithm identifier meaning "no digital signature or MAC performed." The specification intends this for use in contexts where integrity is guaranteed by other means (e.g., TLS with mutual authentication or a secure channel). Vulnerable JWT libraries treat none as a valid algorithm in all contexts - including arbitrary web API requests - effectively allowing any bearer to strip signature verification.
The exploit is deceptively simple. A standard JWT has three segments: header, payload, signature. To produce an alg:none token, the attacker changes the header algorithm, re-encodes, and removes the signature (leaving the trailing dot or omitting it entirely):
Case variation bypasses
After the initial 2015 disclosure, some libraries patched by checkingif alg == "none" - a case-sensitive string comparison. This left case variations as working bypasses for several months after the original patch:
The correct fix is a case-insensitive comparison against a strict allowlist of permitted algorithms, rejecting everything not explicitly allowed - including none in any casing.
Affected libraries (coordinated disclosure, 2015)
Tim McLean and the Auth0 security team independently discovered this class of vulnerability and coordinated disclosure with library maintainers. At least 8 major libraries were affected simultaneously:
node-jsonwebtoken< 4.2.2PythonPyJWT< 1.0.0Rubyruby-jwt< 1.5.1PHPphp-firebase/php-jwt< 5.0.0PHPnamshi/jose< 1.2.2JSjsjwt< 1.2.0.NETjose-jwt< 2.1Javaauth0-java-jwt< 2.1.0Vulnerable code patterns
node-jsonwebtoken ≤ 4.2.1
PyJWT - algorithms parameter
algorithms=[] list and interpret it as "no restriction," which is the opposite of the intended semantics. Always pass a non-empty allowlist. Some libraries also accept algorithms=None with the same broken semantics.The compact serialization angle
The JWT spec defines two serialization formats: compact (the dot-separated string) and JSON. The compact form always has exactly three segments. A valid alg:none token in compact form ends with a dot and an empty signature: header.payload.. Some parsers split on dots and expect exactly 3 parts - if the trailing dot is omitted, the parser may raise a parse error before the algorithm check even runs, blocking the attack. However, relying on a parse error to prevent a security bypass is not a defence.
- Auth0 security bulletin documented bypasses in 8 libraries simultaneously
- Case-variation bypasses survived in some libraries for months after the initial patch
- Libraries that check
alg !== "none"(case-sensitive) remain vulnerable toNone/NONE - Still found in CTF challenges and legacy codebases using pinned old library versions
Mitigations
- Enforce a strict algorithm allowlist - never accept any value not in the list
- The allowlist check must be case-insensitive
- Reject tokens with
alg:noneat the library level and at the application level - Upgrade all JWT libraries to current versions - this is a library-level bug, not just a configuration one
- If
noneis legitimately needed (unusual), use a separate code path gated by explicit configuration, never auto-detected from the token