Package Exports
- eslint-plugin-jwt
- eslint-plugin-jwt/types
Readme
eslint-plugin-jwt
🔐 Security-focused ESLint plugin for JWT authentication. Detects algorithm confusion (CVE-2022-23540), replay attacks, weak secrets, and library-specific vulnerabilities with AI-optimized fix guidance.
💡 What You Get
- 13 Security Rules - Algorithm attacks, replay prevention, claim validation
- 6 JWT Libraries - jsonwebtoken, jose, express-jwt, @nestjs/jwt, jwks-rsa, jwt-decode
- 2025 Research - "Back to the Future" replay attack prevention (LightSEC 2025)
- AI-Optimized - Structured messages for GitHub Copilot, Cursor, Claude assistance
- CWE References - Every rule maps to Common Weakness Enumeration
📦 Installation
npm install --save-dev eslint-plugin-jwt
# or
pnpm add -D eslint-plugin-jwt🚀 Quick Start
Flat Config (ESLint 9+)
// eslint.config.js
import jwt from 'eslint-plugin-jwt';
export default [
jwt.configs.recommended,
// or jwt.configs.strict for maximum security
];Custom Configuration
import jwt from 'eslint-plugin-jwt';
export default [
{
plugins: { jwt },
rules: {
// Critical - Algorithm attacks
'jwt/no-algorithm-none': 'error',
'jwt/no-algorithm-confusion': 'error',
// High - Verification and secrets
'jwt/require-algorithm-whitelist': 'warn',
'jwt/no-decode-without-verify': 'warn',
'jwt/no-weak-secret': 'error',
'jwt/no-hardcoded-secret': 'error',
// Medium - Best practices
'jwt/require-expiration': 'warn',
'jwt/require-issuer-validation': 'warn',
'jwt/require-audience-validation': 'warn',
},
},
];🔐 Rules
💼 = Set in recommended | 🔧 = Auto-fixable | 💡 = Has suggestions
Critical Severity (Algorithm Attacks)
| Rule | CWE | OWASP | Description | 💼 | 🔧 | 💡 |
|---|---|---|---|---|---|---|
| no-algorithm-none | CWE-347 | A02:2021 | Prevent alg:"none" attack (CVE-2022-23540) |
💼 | 💡 | |
| no-algorithm-confusion | CWE-347 | A02:2021 | Prevent RS256→HS256 key confusion | 💼 | 💡 |
High Severity (Verification & Secrets)
| Rule | CWE | OWASP | Description | 💼 | 🔧 | 💡 |
|---|---|---|---|---|---|---|
| require-algorithm-whitelist | CWE-757 | A02:2021 | Require explicit algorithm specification | 💼 | 💡 | |
| no-decode-without-verify | CWE-345 | A04:2021 | Prevent trusting decoded payloads | 💼 | 💡 | |
| no-weak-secret | CWE-326 | A02:2021 | Require 256-bit minimum secrets | 💼 | 💡 | |
| no-hardcoded-secret | CWE-798 | A05:2021 | Prevent secrets in source code | 💼 | 💡 | |
| no-timestamp-manipulation | CWE-294 | A05:2021 | Prevent disabling automatic iat |
💼 | 💡 |
Medium Severity (Claims & Best Practices)
| Rule | CWE | OWASP | Description | 💼 | 🔧 | 💡 |
|---|---|---|---|---|---|---|
| require-expiration | CWE-613 | A04:2021 | Require exp claim or expiresIn |
💼 | 💡 | |
| require-issued-at | CWE-294 | A04:2021 | Require iat claim for freshness |
💼 | 💡 | |
| require-issuer-validation | CWE-287 | A01:2021 | Require issuer validation | 💼 | 💡 | |
| require-audience-validation | CWE-287 | A01:2021 | Require audience validation | 💼 | 💡 | |
| require-max-age | CWE-294 | A04:2021 | Require maxAge for replay prevention | 💼 | 💡 | |
| no-sensitive-payload | CWE-359 | A01:2021 | Prevent PII in token payload | 💼 | 💡 |
🔐 OWASP Top 10 2021 Coverage
| OWASP Category | Rules | Coverage |
|---|---|---|
| A01:2021 Broken Access Control | require-audience-validation, require-issuer-validation |
✅ |
| A02:2021 Cryptographic Failures | no-algorithm-none, no-algorithm-confusion, no-weak-secret, require-algorithm-whitelist |
✅ |
| A04:2021 Insecure Design | no-decode-without-verify, require-expiration, require-max-age |
✅ |
| A05:2021 Security Misconfiguration | no-hardcoded-secret, no-timestamp-manipulation |
✅ |
| A07:2021 Identification Failures | require-issuer-validation, require-audience-validation |
✅ |
| A08:2021 Software/Data Integrity | no-algorithm-none, no-algorithm-confusion, no-decode-without-verify |
✅ |
CWE Coverage Summary
| CWE | Description | Rules |
|---|---|---|
| CWE-287 | Improper Authentication | require-issuer-validation, require-audience-validation |
| CWE-294 | Authentication Bypass by Capture-Replay | require-issued-at, no-timestamp-manipulation, require-max-age |
| CWE-326 | Inadequate Encryption Strength | no-weak-secret |
| CWE-345 | Insufficient Verification of Data Authenticity | no-decode-without-verify |
| CWE-347 | Improper Cryptographic Signature Verification | no-algorithm-none, no-algorithm-confusion |
| CWE-359 | Exposure of Private Information | no-sensitive-payload |
| CWE-613 | Insufficient Session Expiration | require-expiration |
| CWE-757 | Selection of Less-Secure Algorithm | require-algorithm-whitelist |
| CWE-798 | Use of Hard-coded Credentials | no-hardcoded-secret |
🛡️ Security Research Coverage
CVE-2022-23540 (jsonwebtoken Algorithm None)
The no-algorithm-none rule detects attempts to use alg:"none" which bypasses signature verification entirely.
// ❌ Vulnerable - Accepts unsigned tokens
jwt.verify(token, secret, { algorithms: ['none'] });
// ✅ Safe - Explicit secure algorithm
jwt.verify(token, secret, { algorithms: ['RS256'] });LightSEC 2025 "Back to the Future" Attack
The no-timestamp-manipulation and require-max-age rules prevent replay attacks where tokens are captured and replayed years later.
// ❌ Vulnerable - Disables timestamp, enables replay
jwt.sign(payload, secret, { noTimestamp: true });
// ✅ Safe - Automatic iat, maxAge validation
jwt.sign(payload, secret, { expiresIn: '1h' });
jwt.verify(token, secret, { maxAge: '1h' });Algorithm Confusion Attack
The no-algorithm-confusion rule detects when symmetric algorithms (HS256) are used with asymmetric keys (public keys).
// ❌ Vulnerable - Public key as HMAC secret
jwt.verify(token, publicKey, { algorithms: ['HS256'] });
// ✅ Safe - Asymmetric algorithm with public key
jwt.verify(token, publicKey, { algorithms: ['RS256'] });⚙️ Configuration Presets
| Preset | Description | Rules |
|---|---|---|
recommended |
Balanced security | Critical=error, High=warn |
strict |
Maximum security (2025 research) | All 13 rules=error |
legacy |
Migration mode | Critical rules only |
📚 Supported Libraries
| Library | npm | Detection |
|---|---|---|
| jsonwebtoken | ✅ Full | |
| jose | ✅ Full | |
| express-jwt | ✅ Full | |
| @nestjs/jwt | ✅ Full | |
| jwks-rsa | ✅ Full | |
| jwt-decode | ✅ Full |
🤖 AI-Optimized Messages
Every rule uses formatLLMMessage for structured output:
🔒 CWE-347 OWASP:A02-Crypto CVSS:9.8 | Using alg:"none" bypasses signature verification
Fix: Remove "none" and use RS256, ES256, or other secure algorithms
https://nvd.nist.gov/vuln/detail/CVE-2022-23540📖 References
- RFC 8725 - JWT Best Current Practices
- CVE-2022-23540 - jsonwebtoken algorithm none
- CVE-2025-30204 - golang-jwt DoS
- LightSEC 2025 - "Back to the Future" Attack
- PortSwigger - JWT Algorithm Confusion
- OWASP JWT Security Cheat Sheet
🔗 Related ESLint Plugins
Part of the Interlace ESLint Ecosystem — AI-native security plugins with LLM-optimized error messages:
| Plugin | Description | Rules |
|---|---|---|
eslint-plugin-secure-coding |
Universal security (OWASP Top 10 Web + Mobile) | 89 |
eslint-plugin-crypto |
Cryptographic best practices (weak algorithms, key handling) | 24 |
eslint-plugin-pg |
PostgreSQL/node-postgres security | 13 |
eslint-plugin-vercel-ai-security |
Vercel AI SDK security | 19 |
eslint-plugin-import-next |
High-performance import linting | 12 |
📄 License
MIT © Ofri Peretz