no-weak-secret
The rule provides LLM-optimized error messages (Compact 2-line format) with actionable security guidance:
Require strong secrets (256+ bits) for HMAC-based JWT signing
Severity: 🟠 High
CWE: CWE-326
Error Message Format
The rule provides LLM-optimized error messages (Compact 2-line format) with actionable security guidance:
⚠️ CWE-326 OWASP:A04 CVSS:5.9 | Inadequate Encryption Strength detected | MEDIUM
Fix: Review and apply the recommended fix | https://owasp.org/Top10/A04_2021/Message Components
| Component | Purpose | Example |
|---|---|---|
| Risk Standards | Security benchmarks | CWE-326 OWASP:A04 CVSS:5.9 |
| Issue Description | Specific vulnerability | Inadequate Encryption Strength detected |
| Severity & Compliance | Impact assessment | MEDIUM |
| Fix Instruction | Actionable remediation | Follow the remediation steps below |
| Technical Truth | Official reference | OWASP Top 10 |
Rule Details
This rule detects weak secrets used for HMAC-based JWT signing. Weak secrets can be brute-forced offline, allowing attackers to forge tokens.
Examples
❌ Incorrect
// Known weak patterns
jwt.sign(payload, 'secret');
jwt.sign(payload, 'password');
jwt.sign(payload, 'changeme');
// Short secrets (<32 characters)
jwt.sign(payload, 'shortkey');✅ Correct
// Environment variable
jwt.sign(payload, process.env.JWT_SECRET);
// Long secret (32+ characters)
jwt.sign(payload, 'ThisIsAVeryStrongSecretThatIs32Ch+');
// Generated secret
jwt.sign(payload, crypto.randomBytes(32).toString('hex'));Options
{
"jwt/no-weak-secret": ["error", {
"minSecretLength": 32
}]
}| Option | Type | Default | Description |
|---|---|---|---|
minSecretLength | integer | 32 | Minimum secret length (chars) |
Known False Negatives
The following patterns are not detected due to static analysis limitations:
Variable References
Why: Only literal string secrets are analyzed for length/weakness.
// ❌ NOT DETECTED - Secret from variable
const weakSecret = 'abc';
jwt.sign(payload, weakSecret); // Variable not analyzedMitigation: Use environment variables. Apply TypeScript branded types for validated secrets.
Concatenated Secrets
Why: String operations are not evaluated statically.
// ❌ NOT DETECTED - Concatenated weak parts
const part1 = 'short';
const part2 = 'key';
jwt.sign(payload, part1 + part2); // Still weak, but not detectedMitigation: Use single, long secret strings. Avoid dynamic secret construction.
Encoded Weak Secrets
Why: Base64/hex encoding can hide a weak underlying secret.
// ❌ NOT DETECTED - Encoded but short underlying value
const encoded = Buffer.from('weak').toString('base64'); // 'd2Vhaw=='
jwt.sign(payload, encoded); // String is long enough but entropy is lowMitigation: Validate secret entropy at runtime. Use cryptographically random secrets.
Environment Variable Values
Why: The rule trusts environment variables but cannot verify their actual values.
// ❌ NOT DETECTED - Weak secret in env var
// .env: JWT_SECRET=password
jwt.sign(payload, process.env.JWT_SECRET); // Trusts the env varMitigation: Use secret rotation policies. Validate secret strength at application startup.
Secrets from Configuration Files
Why: Values loaded from config files are treated as safe.
// ❌ NOT DETECTED - Weak secret in config
import { JWT_SECRET } from './config'; // Config contains 'weak123'
jwt.sign(payload, JWT_SECRET);Mitigation: Apply secret validation at config load time. Use environment variables for secrets.
Further Reading
Did this rule catch something? Star the repo to get new CWE coverage as we ship it — or follow the AI-code-security benchmarks behind these rules.