JWT None Algorithm

CRITICAL

Detects jwt.encode() calls using algorithm='none', which creates unsigned tokens that anyone can forge.

Rule Information

Language
Python
Category
JWT
Author
Shivasurya
Shivasurya
Last Updated
2026-03-22
Tags
pythonjwtpyjwtnone-algorithmunsigned-tokentoken-forgerycryptographic-failureCWE-327CWE-345OWASP-A02
CWE References

Interactive Playground

Experiment with the vulnerable code and security rule below. Edit the code to see how the rule detects different vulnerability patterns.

pathfinder scan --ruleset python/PYTHON-JWT-SEC-002 --project .
1
2
3
4
5
6
7
rule.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

About This Rule

Understanding the vulnerability and how it is detected

This rule detects jwt.encode() calls that explicitly set algorithm="none". The "none" algorithm produces unsigned JWT tokens -- the token has no signature at all, which means anyone can modify the payload (change user IDs, add admin roles, extend expiration) and the receiving service has no way to tell.

This is one of the most exploited JWT vulnerabilities. The "none" algorithm was originally intended for cases where the token integrity was already guaranteed by the transport layer (e.g., mutual TLS). In practice, it became an attack vector: libraries that accepted "none" as a valid algorithm allowed attackers to strip the signature from a legitimately signed token and re-submit it.

The rule uses .where("algorithm", "none") for precise matching. It only fires when the algorithm keyword argument is literally "none" -- it will not flag jwt.encode() calls using HS256, RS256, ES256, or any other real algorithm. Zero false positives on properly configured encode calls.

Security Implications

Potential attack scenarios if this vulnerability is exploited

1

Complete Token Forgery

With algorithm="none", there is no signature. An attacker can create a JWT with any payload -- admin privileges, any user identity, any expiration date -- and the server will accept it if it doesn't enforce algorithm verification.

2

Privilege Escalation

An attacker takes a valid low-privilege token, decodes the payload (JWT payloads are just base64), changes "role" from "user" to "admin", re-encodes with algorithm="none", and submits it. If the server accepts unsigned tokens, the attacker is now admin.

3

Authentication Bypass

An unsigned token can impersonate any user. The attacker doesn't need the victim's password, the signing key, or any other credential. They just need to know the expected payload structure.

How to Fix

Recommended remediation steps

  • 1Never use algorithm="none" in production code -- there is no legitimate use case for unsigned tokens in a web application
  • 2Use HS256 for single-service architectures where the same service signs and verifies tokens
  • 3Use RS256 or ES256 for microservice architectures where multiple services need to verify tokens
  • 4On the verification side, always pass an explicit algorithms list to jwt.decode() to prevent algorithm confusion attacks
  • 5Add a linter rule or pre-commit check to catch "none" algorithm usage before it reaches production

Detection Scope

How Code Pathfinder analyzes your code for this vulnerability

This rule matches jwt.encode() calls where the keyword argument algorithm is set to "none". It uses QueryType resolution to identify the jwt module by its fully qualified name and the .where("algorithm", "none") qualifier to precisely match only the unsafe algorithm value. Calls with algorithm="HS256", "RS256", "ES256", or any other value are not flagged.

Compliance & Standards

Industry frameworks and regulations that require detection of this vulnerability

CWE Top 25
CWE-327 ranked in Most Dangerous Software Weaknesses
OWASP Top 10
A02:2021 - Cryptographic Failures
PCI DSS v4.0
Requirement 4.2.1 -- strong cryptography for transmission of sensitive data
NIST SP 800-63B
Section 7.1 -- signed assertions must use approved algorithms
NIST SP 800-53
SC-13: Cryptographic Protection

References

External resources and documentation

Similar Rules

Explore related security rules for Python

Frequently Asked Questions

Common questions about JWT None Algorithm

Because it removes the only thing that makes a JWT trustworthy -- the signature. JWTs are just base64-encoded JSON. Anyone can read and create them. The signature is what proves the token was created by your server. Remove the signature and the token is just a JSON string that anyone can modify.
Not currently. The rule precisely matches jwt.encode() with algorithm="none". The decode variant uses algorithms (plural) which takes a list value like ["none"]. Matching values inside list arguments requires a contains() qualifier that the engine doesn't support yet. This is tracked as a product roadmap item.
In theory, RFC 7518 defines "none" for cases where integrity is provided by the transport layer. In practice, there is no real-world web application scenario where unsigned tokens are safe. Even in testing, use a test-specific HS256 secret instead of disabling signing entirely.
Yes -- this is the classic algorithm confusion attack. The attacker takes a valid RS256-signed token, changes the header to {"alg": "none"}, strips the signature, and submits it. If the server's jwt.decode() doesn't enforce an algorithms whitelist, it will accept the unsigned token. This is why you should always pass algorithms=["RS256"] (or whichever algorithm you use) to jwt.decode().
Run: pathfinder ci --ruleset python/jwt --project . It outputs SARIF, JSON, or CSV. On GitHub, it posts inline review comments directly on pull requests pointing to the exact lines. No dashboard needed.
For most applications, HS256 (HMAC-SHA256) is the right default. It's fast, widely supported, and secure with a 256-bit key. For microservices where you want to distribute verification without sharing the signing key, use RS256 (RSA-SHA256) or ES256 (ECDSA-P256). ES256 produces smaller tokens than RS256.

New feature

Get these findings posted directly on your GitHub pull requests

The JWT None Algorithm rule runs in CI and posts inline review comments on the exact lines — no dashboard, no SARIF viewer.

See how it works