require-audience-validation
The rule provides LLM-optimized error messages (Compact 2-line format) with actionable security guidance:
Require audience (aud) claim validation in JWT verify operations
Severity: 🟡 Medium
CWE: CWE-287
Error Message Format
The rule provides LLM-optimized error messages (Compact 2-line format) with actionable security guidance:
🔒 CWE-287 OWASP:A07 CVSS:9.8 | Improper Authentication detected | CRITICAL
Fix: Review and apply the recommended fix | https://owasp.org/Top10/A07_2021/Message Components
| Component | Purpose | Example |
|---|---|---|
| Risk Standards | Security benchmarks | CWE-287 OWASP:A07 CVSS:9.8 |
| Issue Description | Specific vulnerability | Improper Authentication detected |
| Severity & Compliance | Impact assessment | CRITICAL |
| Fix Instruction | Actionable remediation | Follow the remediation steps below |
| Technical Truth | Official reference | OWASP Top 10 |
Rule Details
This rule mandates audience validation. Without it, tokens intended for other services are accepted.
Examples
❌ Incorrect
jwt.verify(token, secret);
jwt.verify(token, secret, { issuer: 'auth.example.com' });✅ Correct
jwt.verify(token, secret, { audience: 'https://api.example.com' });
jwt.verify(token, secret, {
issuer: 'https://auth.example.com',
audience: 'https://api.example.com',
});Options
| Option | Type | Default | Description |
|---|---|---|---|
knownAudiences | string[] | [] | Known valid audiences to suggest |
trustedSanitizers | string[] | [] | Extra function names to treat as sanitizers |
trustedAnnotations | string[] | [] | Extra JSDoc annotations to treat as safe markers |
strictMode | boolean | false | Disable false-positive suppression — report even sanitized input |
Known False Negatives
The following patterns are not detected due to static analysis limitations:
Options from Variables, Casts and Spreads
What is read: options are followed within the file — an inline object, a const or a never-reassigned let, a destructure, a member of an object literal, an as / satisfies cast, a spread of any of those, and the single return of a same-file function. NestJS JwtService calls are read at the second argument, where @nestjs/jwt takes them. An injected this.<member> counts as a JWT client only on evidence the class gives (a type annotation resolving to a JWT library, an @Inject(X) of a JWT import, or an assignment from one).
const verifyOptions = { algorithms: ['RS256'], audience: 'api://orders' };
jwt.verify(token, key, verifyOptions); // ✅ read through the const
jwt.verify(token, key, { ...verifyOptions, complete: true }); // ✅ spread of a const
jwt.verify(token, key, { ...verifyOptions } as VerifyOptions); // ✅ through the castWhat is not: options from a parameter, an import, a function call, or a spread of one of those cannot be seen. The rule stays silent rather than report an option it cannot prove is missing. NestJS per-call options merge over JwtModule verifyOptions in another file, so they are treated the same way.
// ⚠️ NOT DETECTED - options built elsewhere
jwt.verify(token, key, getVerifyOptions());Mitigation: Keep verify options in a module-level const in the file that verifies.
Spread of an Unresolvable Value
Why: { ...getDefaults() } may carry the option where this file cannot see it, so a missing option is not reported. A spread of a same-file const is read (see above).
// ⚠️ NOT DETECTED - the spread source is a call
jwt.verify(token, key, { ...getVerifyOptions() });Runtime Audience Configuration
Why: Audience from runtime config is not visible.
// ❌ NOT DETECTED - Audience from config
jwt.verify(token, secret, { audience: config.audience }); // Might be undefinedMitigation: Validate config at startup. Use required fields in TypeScript config types.
Wrapper Function
Why: Options passed through wrappers are not traced.
// ❌ NOT DETECTED - Wrapper hides options
function verifyToken(token: string) {
return jwt.verify(token, secret, { algorithms: ['RS256'] }); // No audience
}Mitigation: Apply this rule to all modules including utilities.
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.