Back to Blog
critical SEVERITY6 min read

JWT Algorithm Confusion: How a Missing Parameter Can Compromise Authentication

A critical authentication vulnerability was discovered where the jsonwebtoken library was being used without explicitly specifying allowed algorithms during token verification. This oversight enables attackers to exploit algorithm confusion attacks, potentially forging valid tokens by manipulating the algorithm header to 'none' or switching from asymmetric to symmetric algorithms, completely bypassing authentication controls.

O
By orbisai0security
March 6, 2026

Introduction

JSON Web Tokens (JWT) have become the de facto standard for stateless authentication in modern web applications. However, their security depends entirely on proper implementation. A recently patched vulnerability in an application using the jsonwebtoken library (^9.0.2) highlights a common but dangerous oversight: failing to specify allowed algorithms during token verification.

This vulnerability, while seemingly minor in code terms, can have catastrophic consequences—allowing attackers to completely bypass authentication and impersonate any user in your system. If you're using JWTs in your application, this is a must-read.

The Vulnerability Explained

What is Algorithm Confusion?

JWT tokens consist of three parts: a header, a payload, and a signature. The header specifies which cryptographic algorithm was used to sign the token. When verifying a JWT, the server must check both the signature's validity AND ensure the algorithm used is one that's expected and secure.

The vulnerability occurs when jwt.verify() is called without the algorithms parameter:

// VULNERABLE CODE
const decoded = jwt.verify(token, secretOrPublicKey);

Without explicit algorithm specification, the library will trust whatever algorithm is declared in the token's header. This opens two critical attack vectors:

Attack Vector 1: The "None" Algorithm Attack

An attacker can modify a valid JWT's header to use the "none" algorithm, which indicates no signature verification is required:

{
  "alg": "none",
  "typ": "JWT"
}

When the server attempts to verify this token without algorithm restrictions, it may accept the token as valid without checking any signature at all. The attacker simply needs to:

  1. Decode an existing JWT
  2. Change the algorithm header to "none"
  3. Remove the signature portion
  4. Re-encode the token

Result: Complete authentication bypass.

Attack Vector 2: RS256 to HS256 Confusion

Many applications use asymmetric algorithms (like RS256) where tokens are signed with a private key and verified with a public key. If algorithm validation is missing, an attacker can:

  1. Obtain the public key (often publicly accessible)
  2. Create a new token signed with HS256 (symmetric algorithm)
  3. Use the public key as the "secret" for HMAC signing

The server, expecting RS256 but not enforcing it, will use the public key to verify the HMAC signature—which the attacker created using that same public key.

Result: Token forgery with publicly available information.

Real-World Impact

This vulnerability allows attackers to:

  • Impersonate any user by forging tokens with arbitrary user IDs
  • Escalate privileges by adding admin roles to forged tokens
  • Bypass authentication entirely using the "none" algorithm
  • Access sensitive data belonging to other users
  • Perform unauthorized actions on behalf of legitimate users

Example Attack Scenario

Consider an e-commerce application:

  1. Alice registers as a regular user and receives a JWT
  2. Attacker intercepts or obtains Alice's token
  3. Attacker decodes the token and changes the header to "alg": "none"
  4. Attacker modifies the payload: {"userId": "admin", "role": "administrator"}
  5. Attacker re-encodes without a signature
  6. Server verifies token without algorithm check and grants admin access

The attacker now has full administrative control over the application.

The Fix

What Changed

The fix involves adding the algorithms parameter to all jwt.verify() calls throughout the application:

// BEFORE (Vulnerable)
const decoded = jwt.verify(token, secretOrPublicKey);

// AFTER (Secure)
const decoded = jwt.verify(token, secretOrPublicKey, {
  algorithms: ['RS256']  // Explicitly whitelist allowed algorithms
});

How It Solves the Problem

By specifying algorithms: ['RS256'] (or whichever algorithm your application uses), the verification process now:

  1. Rejects "none" algorithm tokens immediately, preventing signature bypass
  2. Prevents algorithm confusion by refusing tokens signed with unexpected algorithms
  3. Enforces cryptographic integrity by ensuring only your chosen secure algorithm is accepted

If an attacker tries to submit a token with "alg": "none" or "alg": "HS256" when only RS256 is allowed, the verification will fail with an error:

JsonWebTokenError: invalid algorithm

Complete Implementation Example

Here's a comprehensive example of secure JWT verification:

const jwt = require('jsonwebtoken');
const fs = require('fs');

// Load your keys securely (example for RS256)
const publicKey = fs.readFileSync('public-key.pem');

function verifyToken(token) {
  try {
    const decoded = jwt.verify(token, publicKey, {
      algorithms: ['RS256'],           // Whitelist allowed algorithms
      issuer: 'your-app.com',          // Verify token issuer
      audience: 'your-api',            // Verify intended audience
      maxAge: '1h'                     // Enforce expiration
    });

    return decoded;
  } catch (error) {
    if (error.name === 'TokenExpiredError') {
      throw new Error('Token has expired');
    }
    if (error.name === 'JsonWebTokenError') {
      throw new Error('Invalid token');
    }
    throw error;
  }
}

// Express middleware example
function authenticateJWT(req, res, next) {
  const authHeader = req.headers.authorization;

  if (!authHeader || !authHeader.startsWith('Bearer ')) {
    return res.status(401).json({ error: 'No token provided' });
  }

  const token = authHeader.substring(7);

  try {
    req.user = verifyToken(token);
    next();
  } catch (error) {
    return res.status(403).json({ error: error.message });
  }
}

Prevention & Best Practices

1. Always Specify Allowed Algorithms

Never call jwt.verify() without the algorithms parameter:

// ❌ NEVER DO THIS
jwt.verify(token, secret);

// ✅ ALWAYS DO THIS
jwt.verify(token, secret, { algorithms: ['HS256'] });

2. Use Strong, Appropriate Algorithms

  • HS256/HS512: Suitable for symmetric scenarios where both signing and verification happen on the same server
  • RS256/RS512: Recommended for distributed systems where tokens are signed by one service and verified by multiple services
  • ES256/ES512: Modern elliptic curve algorithms offering better performance with equivalent security

Avoid: HS256 with RS256 public keys, any "none" algorithm, or weak algorithms like HS1.

3. Implement Defense in Depth

Algorithm specification is just one layer. Also implement:

const decoded = jwt.verify(token, secret, {
  algorithms: ['RS256'],
  issuer: 'trusted-issuer',      // Verify token source
  audience: 'your-service',      // Verify token destination
  maxAge: '15m',                 // Short expiration
  clockTolerance: 30             // Allow 30s clock skew
});

// Additional validation
if (!decoded.sub || !decoded.role) {
  throw new Error('Invalid token structure');
}

4. Use Security Linting Tools

Configure ESLint with security plugins to catch these issues:

{
  "plugins": ["security"],
  "rules": {
    "security/detect-unsafe-jwt": "error"
  }
}

5. Regular Security Audits

  • Automated scanning: Use tools like npm audit, Snyk, or OWASP Dependency-Check
  • Code review: Ensure all JWT operations are reviewed by security-aware developers
  • Penetration testing: Include JWT attack vectors in security assessments

6. Keep Dependencies Updated

The jsonwebtoken library has evolved to address security concerns. Always use the latest stable version:

npm update jsonwebtoken
npm audit fix

Security Standards References

  • CWE-347: Improper Verification of Cryptographic Signature
  • CWE-327: Use of a Broken or Risky Cryptographic Algorithm
  • OWASP Top 10 2021: A02:2021 – Cryptographic Failures
  • OWASP JWT Cheat Sheet: Comprehensive guide to JWT security
  • RFC 7519: JSON Web Token specification

Conclusion

The JWT algorithm confusion vulnerability demonstrates that security often fails not from complex exploits, but from simple oversights in implementation. A single missing parameter—algorithms—can completely undermine your authentication system.

Key Takeaways:

  1. Always specify allowed algorithms when verifying JWTs
  2. Use asymmetric algorithms (RS256) for distributed systems
  3. Implement multiple layers of validation beyond just signature verification
  4. Keep security libraries updated and monitor for vulnerabilities
  5. Audit your codebase specifically for JWT verification calls

If you're using the jsonwebtoken library, review your codebase today. Search for all instances of jwt.verify() and ensure they include the algorithms parameter. This simple fix could be the difference between a secure application and a compromised one.

Remember: in security, what you don't specify can hurt you as much as what you do. Write defensive code, assume malicious input, and always validate explicitly.

Have you checked your JWT implementation? Share your experiences or questions in the comments below.


Stay secure, and happy coding!

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #59

Related Articles

medium

JWT Authentication Vulnerability: How Weak Token Validation Exposed Dashboard APIs

A critical authentication bypass vulnerability was discovered in a dashboard application where JWT tokens could be forged due to improper validation. The vulnerability affected multiple routes including backup, live chat, and authentication endpoints, potentially allowing attackers to access sensitive operations without proper authorization. This fix demonstrates why robust JWT validation is essential for API security.

critical

Path Traversal in node-tar: How Hardlink Bypass Exposed Your Files

A medium-severity vulnerability (CVE-2026-24842) in node-tar allowed attackers to bypass hardlink security checks and create arbitrary files through path traversal attacks. This vulnerability, combined with improper configuration management storing JWT secrets in plaintext .env files, created a dangerous attack vector for token forgery and unauthorized access.

critical

Heap Buffer Overflow in Audio Ring Buffer: How a Missing Bounds Check Could Crash Your App

A critical heap buffer overflow vulnerability was discovered in `audio_backend.c`, where the audio ring buffer's `memcpy` operations lacked bounds validation before writing PCM data. Without checking that incoming data sizes fell within the allocated buffer's capacity, a maliciously crafted audio file could corrupt adjacent heap memory, potentially enabling arbitrary code execution. The fix adds a concise pre-flight validation guard that rejects out-of-range write requests before any memory oper

critical

Critical Memory Safety Bug: Free of Uninitialized Memory in Rust Telemetry (CVE-2021-29937)

CVE-2021-29937 is a critical memory safety vulnerability in the Rust `telemetry` crate (versions prior to 0.1.3) that allows freeing uninitialized memory, leading to undefined behavior, potential crashes, and possible code execution. The fix involves upgrading the crate from version 0.1.0 to 0.1.3, which patches the unsafe memory handling at the root cause. Despite Rust's reputation for memory safety, this vulnerability demonstrates that `unsafe` code blocks can still introduce serious bugs that

critical

Critical Heap Buffer Overflow in SSDP Control Point: How Unbounded String Operations Put Networks at Risk

A critical heap buffer overflow vulnerability was discovered and patched in the SSDP control point implementation (`ssdp_ctrlpt.c`), where multiple unbounded `strcpy` and `strcat` operations constructed HTTP request buffers without any length validation. Network-received SSDP response fields — including service type strings and location URLs — could be crafted by an attacker to exceed buffer boundaries, potentially enabling arbitrary code execution or denial of service. The fix replaces the unsa

critical

Heap Buffer Overflow in OPDS Parser: How a Misplaced Variable Nearly Opened the Door to Remote Code Execution

A critical heap buffer overflow vulnerability was discovered in `lib/OpdsParser/OpdsParser.cpp`, where the buffer allocation size was calculated *after* a fixed chunk size was used to allocate memory, meaning the actual bytes read could exceed the allocated buffer. On embedded devices parsing untrusted OPDS catalog data from the network, this flaw could allow a remote attacker to corrupt heap memory and potentially achieve arbitrary code execution. The fix was elegantly simple: move the `toRead`