← Home ← Codex ← DEBT
Browse by Category
+ added · updated 7d
← Back to glossary

JWT Vulnerabilities

Security CWE-287 OWASP A2:2021 CVSS 8.8 PHP 7.0+ Intermediate
debt(d5/e3/b3/t7)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches it' (d5). The detection_hints list semgrep and psalm as tools, both specialist static analysis tools. The code patterns (accepting alg from token header, no algorithm whitelist, base64_decode without signature verification) are detectable by these tools but not by a standard compiler or default linter pass. Some misuses (e.g. weak secrets, unvalidated claims) may slip through even these tools, but the primary vulnerabilities are in scope for SAST.

e3 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix' (e3). The quick_fix specifies explicitly naming the allowed algorithm when decoding and using firebase/php-jwt — a targeted library swap or configuration change within the authentication layer. Addressing all common_mistakes (algorithm whitelist, secret strength, claim validation) requires touching the JWT verification code in one component, but it does not span multiple files or require architectural rework.

b3 Burden Structural debt — long-term weight of choosing wrong

Closest to 'localised tax' (b3). The applies_to contexts are web and api, and JWT verification logic is typically concentrated in authentication middleware or a single service. While authentication is important, the burden is localised — it does not impose a persistent tax across unrelated work streams or define the system's shape.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap' (t7). The misconception field explicitly states the canonical wrong belief: a valid JWT signature is taken to mean the token is fully trustworthy. This contradicts how many developers reason about cryptographic signing — they assume signature validity implies claim validity. The alg confusion attack (accepting whatever algorithm the token declares) is a well-documented gotcha that contradicts intuition built from other authentication systems, placing this at t7.

About DEBT scoring →

Also Known As

JWT attack JSON Web Token weakness

TL;DR

Misimplemented JSON Web Token handling allows attackers to forge tokens, bypass authentication, or escalate privileges.

Explanation

Common JWT vulnerabilities include: accepting the 'none' algorithm (no signature required), algorithm confusion attacks (RS256 public key used as HS256 secret), weak secrets susceptible to offline brute-force, missing expiry validation, and insecure storage of tokens in localStorage. Always validate the algorithm explicitly, reject 'none', use strong secrets or asymmetric keys, verify exp/nbf claims, and store tokens in HttpOnly cookies rather than JavaScript-accessible storage.

How It's Exploited

An attacker takes a valid JWT, changes the algorithm header to 'none', and strips the signature. A vulnerable library that doesn't reject the 'none' algorithm will accept the tampered token as valid, allowing the attacker to forge arbitrary claims.

Diagram

flowchart TD
    subgraph alg none attack
        J1[Header: alg=none] --> J2[Signature stripped]
        J2 --> J3[Server accepts<br/>unsigned token!]
    end
    subgraph Algorithm confusion
        J4[RS256 token] --> J5[Attacker changes<br/>alg=HS256]
        J5 --> J6[Signs with<br/>public key as HMAC secret]
        J6 --> J7[Server verifies<br/>with same public key]
    end
    subgraph Fix
        F1[Whitelist allowed algorithms<br/>never accept none<br/>validate exp, iss, aud]
    end
    style J3 fill:#f85149,color:#fff
    style J7 fill:#f85149,color:#fff
    style F1 fill:#238636,color:#fff

Watch Out

Never use the token's own header to determine which algorithm to use for verification — always enforce the expected algorithm in your server-side code.

Common Misconception

A valid JWT signature proves the token is trustworthy. The signature only proves the token was not tampered with after signing — it says nothing about the claims inside. Always validate exp, iss, aud, and sub server-side after verifying the signature.

Why It Matters

JWTs are widely misimplemented — algorithm confusion, weak secrets, and unverified claims have each caused complete authentication bypass in real applications.

Common Mistakes

  • Not explicitly specifying the allowed algorithm when verifying — accepting whatever alg the token declares.
  • Using a short or guessable HMAC secret — HS256 with a weak secret is crackable offline.
  • Not validating exp, nbf, and iss claims after signature verification.
  • Storing sensitive data in the payload without encrypting it — the payload is only base64-encoded, not secret.

Code Examples

✗ Vulnerable
// Trusting the algorithm from the token header:
$decoded = JWT::decode($token, $secret); // No algorithm allowlist specified
// Attacker sends alg=none token — some libraries accept it
✓ Fixed
// Whitelist algorithm — reject none and algorithm confusion:
use Firebase\JWT\JWT;
use Firebase\JWT\Key;

// Always specify algorithm explicitly:
$decoded = JWT::decode(
    $token,
    new Key($publicKey, 'RS256') // Only RS256 accepted — rejects HS256, none
);

// Validate all critical claims:
if ($decoded->iss !== 'https://auth.example.com') {
    throw new Exception('Invalid issuer');
}
if ($decoded->aud !== 'api.example.com') {
    throw new Exception('Invalid audience');
}
if ($decoded->exp < time()) {
    throw new Exception('Token expired');
}

Added 15 Mar 2026
Edited 22 Mar 2026
Views 101
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
1 ping T 0 pings W 1 ping T 0 pings F 0 pings S 0 pings S 0 pings M 1 ping T 1 ping W 0 pings T 8 pings F 1 ping S 2 pings S 1 ping M 1 ping T 1 ping W 4 pings T 0 pings F 0 pings S 0 pings S 0 pings M 1 ping T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 2 pings M 0 pings T 0 pings W
No pings yet today
No pings yesterday
Perplexity 37 Scrapy 15 Amazonbot 8 Google 5 Ahrefs 4 SEMrush 4 Meta AI 2 Unknown AI 2 Bing 2 Majestic 1 ChatGPT 1 Claude 1 Sogou 1 PetalBot 1
crawler 82 crawler_json 1 pre-tracking 1
DEV INTEL Tools & Severity
🔴 Critical ⚙ Fix effort: Medium
⚡ Quick Fix
Explicitly specify the allowed algorithm when decoding: never trust the 'alg' header from the token itself; use a dedicated library like firebase/php-jwt
📦 Applies To
PHP 7.0+ web api
🔗 Prerequisites
🔍 Detection Hints
JWT decode accepting algorithm from token header; no algorithm whitelist; base64_decode without signature verification
Auto-detectable: ✓ Yes semgrep psalm
⚠ Related Problems
🤖 AI Agent
Confidence: High False Positives: Medium ✗ Manual fix Fix: Medium Context: File Tests: Update
CWE-347 CWE-345


✓ schema.org compliant