JWT alg:none Attack (CVE-2015-9235)
The JWT alg:none attack (CVE-2015-9235) lets an attacker forge arbitrary tokens by removing the signature and setting alg to none. Learn how the attack works and the exact fix for every JWT library.
The `alg: none` attack exploits JWT libraries that accept unsigned tokens. An attacker strips the signature, sets `alg` to `none` in the header, and modifies the payload freely. Vulnerable libraries treat these tokens as cryptographically valid. This is CVE-2015-9235, which affected major JWT libraries across multiple languages and was actively exploited in the wild.
How the attack works
The JWT specification allows `alg: "none"` as a valid algorithm value: it signals that the token carries no signature. Several early JWT library implementations treated unsigned tokens as cryptographically valid if the header declared `alg: none`. The attacker takes any legitimate JWT, base64-decodes the header and payload (no key needed), modifies the payload however they want (change the role, extend the expiry, swap the subject), re-encodes the header with `"alg": "none"`, and concatenates `header.payload.` (the trailing dot with nothing after it is the empty signature). A vulnerable verifier reads `alg: none`, skips signature verification, and accepts the forged token as valid.
The fix
Hardcode the expected algorithm in your verification call. Never derive the algorithm from the token header. Reject `none` in any capitalization: variants of this attack use `"NONE"`, `"None"`, or `"nOnE"` to bypass case-sensitive checks. Your setup should reject anything not on an explicit allowlist, and `none` should never appear on that list.
Code examples
The attack (what an attacker constructs)
function base64url(obj) {
return Buffer.from(JSON.stringify(obj))
.toString("base64")
.replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
}
const header = base64url({ alg: "none", typ: "JWT" });
const payload = base64url({
sub: "user_999",
role: "admin", // changed from "user"
exp: 9999999999,
});
// Empty signature segment: the trailing dot is intentional
const forgedToken = `${header}.${payload}.`; The fix (Node.js: jsonwebtoken)
// WRONG: the token decides how it gets verified
const decoded = jwt.verify(token, secret);
// RIGHT: you decide the algorithm, the token does not
const decoded = jwt.verify(token, secret, { algorithms: ["HS256"] }); The fix (Python: PyJWT)
# WRONG: includes "none" in the accepted list
payload = jwt.decode(token, secret, algorithms=["HS256", "none"])
# RIGHT: only the algorithm you actually use
payload = jwt.decode(token, secret, algorithms=["HS256"]) Frequently asked questions
-
What is the JWT alg:none attack?
The alg:none attack (CVE-2015-9235) exploits JWT libraries that accept unsigned tokens. An attacker strips the signature, sets alg to none in the header, modifies the payload freely (e.g. escalating role to admin, extending expiry), and submits the forged token. Vulnerable libraries read alg: none, skip signature verification, and accept the token as valid. The fix is to hardcode the expected algorithm in your verifier and never accept alg: none in any capitalization.
-
How do I prevent the alg:none attack?
Always pass an explicit algorithms allowlist to your verification call: jwt.verify(token, key, { algorithms: ['HS256'] }) in jsonwebtoken, jwt.decode(token, key, algorithms=['HS256']) in PyJWT, or a typed parser in jjwt. Never include 'none' in the list. Reject 'none' in any capitalization (NONE, None, nOnE): variants of the attack bypass case-sensitive checks. PyJWT 2.0+ raises an error if you omit the algorithms argument, which prevents this attack by design.
-
Is CVE-2015-9235 still relevant?
Yes. While most modern JWT libraries have fixed the original vulnerability, the attack pattern reappears when developers misconfigure libraries (e.g. adding 'none' to the algorithms list for testing and forgetting to remove it), use unmaintained forks, or build custom verifiers that trust the token header's alg. The defensive principle is permanent: never let the token dictate its own verification algorithm.