JWT "None" Algorithm Vulnerability

How a tiny mistake in verifying a web token allows anyone to become a system admin.

The idea

A JSON Web Token (JWT) is used to prove who a user is. It has three parts: Header, Payload (e.g., {"user": "alice", "role": "admin"}), and a Cryptographic Signature. The server verifies the signature to ensure the payload hasn't been tampered with. However, the JWT Header specifies which algorithm was used to create the signature (e.g., "alg": "HS256"). Shockingly, the JWT specification allows an algorithm called "none". If a server blindly trusts the header, an attacker can modify their role to "admin", change the header to "alg": "none", delete the signature, and the server will accept it!

Step 1: Normal JWT. The server checks the signature using its secret key. It matches, so the token is trusted.

How it works (Hardcoding the Algorithm)

The root cause of this vulnerability is servers asking the untrusted token how it should be verified. You should never read the alg header from the token to decide your verification logic. You must hardcode the expected algorithm in your backend server code.

// BAD: Trusting the token's header
// The library reads the header, sees "none", and skips signature check!
const decoded = jwt.verify(token, mySecret); 

// GOOD: Hardcoding the expected algorithm
// If the attacker changes the header to "none", this will throw an error
// because "none" is not in the allowed algorithms array.
const decoded = jwt.verify(token, mySecret, {
    algorithms: ["HS256"] // STRICTLY enforce this!
});

Cost

Fixing this costs nothing in terms of performance, it's simply a configuration detail. Modern JWT libraries usually disable the "none" algorithm by default, but this exact vulnerability still appears in custom-built authentication systems or when developers use older libraries and fail to explicitly define the allowed algorithms.

Watch out for