browser-security/no-jwt-in-storage
This rule prevents storing JWT tokens in browser storage (localStorage/sessionStorage). JWTs stored in these locations are fully accessible to JavaScript, makin
🔒 Disallow storing JWT tokens in localStorage or sessionStorage
Rule Details
This rule prevents storing JWT tokens in browser storage (localStorage/sessionStorage). JWTs stored in these locations are fully accessible to JavaScript, making them vulnerable to XSS attacks.
Why is this dangerous?
When you store JWTs in browser storage:
- Any XSS attack can read the token via
localStorage.getItem('token') - Tokens can be exfiltrated to attacker-controlled servers
- Attackers can impersonate users with stolen tokens
Examples
❌ Incorrect
// Storing JWT in localStorage
localStorage.setItem('token', jwtToken);
localStorage.setItem('accessToken', response.access_token);
localStorage.setItem('jwt', authResult.jwt);
// Storing in sessionStorage (equally vulnerable)
sessionStorage.setItem('refreshToken', refreshToken);
sessionStorage.setItem('id_token', idToken);
// Direct assignment
localStorage['bearer'] = bearerToken;
localStorage.access_token = token;
// Even with obfuscated keys - if value is a JWT, it's detected
localStorage.setItem('data', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...');✅ Correct
// Non-sensitive data is fine
localStorage.setItem('theme', 'dark');
localStorage.setItem('locale', 'en-US');
sessionStorage.setItem('searchHistory', JSON.stringify(history));
// Token counters and metadata (not actual tokens)
localStorage.setItem('tokenCount', '5');
localStorage.setItem('tokenExpiry', '1234567890');
// Use HttpOnly cookies instead (set by server)
// Server: res.cookie('token', jwt, { httpOnly: true, secure: true, sameSite: 'strict' })
// Or use in-memory only (cleared on page refresh)
let token = response.jwt; // Not persistedOptions
{
"browser-security/no-jwt-in-storage": [
"error",
{
"allowInTests": true
}
]
}| Option | Type | Default | Description |
|---|---|---|---|
allowInTests | boolean | true | Skip checking in test files (_.test.ts, _.spec.ts) |
Detection Patterns
The rule detects JWT storage through two mechanisms:
1. Key Name Detection
Keys matching these patterns are flagged:
jwt,token,bearer(exact)access_token,accessToken,access-tokenrefresh_token,refreshTokenid_token,idTokenauth_token,authToken- Any key ending with
token(e.g.,userToken,apiToken)
2. Value Detection
Values that look like JWTs are detected:
- Matches pattern:
eyJ[...].eyJ[...].[...](base64.base64.signature)
False Positive Prevention
These patterns are explicitly excluded:
tokenCount,tokenLength,tokenSizetokenLimit,tokenMax,tokenMintokenIndex,tokenPosition
When Not To Use It
You may disable this rule if:
- Your application doesn't handle authentication
- You're building a demo/prototype without security requirements
- You have specific requirements that mandates browser storage (not recommended)
However, always prefer HttpOnly cookies for JWT storage in production.
Secure Token Storage Alternatives
Option 1: HttpOnly Cookies (Recommended)
// Server-side (Express.js)
res.cookie('token', jwtToken, {
httpOnly: true, // Not accessible via JavaScript
secure: true, // HTTPS only
sameSite: 'strict', // CSRF protection
maxAge: 3600000, // 1 hour
});
// Client-side - token is automatically sent with requests
fetch('/api/protected', {
credentials: 'include',
});Option 2: Memory-Only Storage
// Token lives only in memory - cleared on page refresh
class TokenService {
private token: string | null = null;
setToken(jwt: string) { this.token = jwt; }
getToken() { return this.token; }
clearToken() { this.token = null; }
}Related
- CWE-922: Insecure Storage of Sensitive Information
- Auth0: Token Storage
browser-security/no-sensitive-localstorage- General sensitive data detection
Known False Negatives
The following patterns are not detected due to static analysis limitations:
JWT Value from Variable
Why: Token values from variables are not traced.
// ❌ NOT DETECTED - Value from variable
const value = response.jwt;
localStorage.setItem('data', value);Mitigation: Never store JWTs in localStorage.
Custom Storage Wrappers
Why: Storage wrappers not recognized.
// ❌ NOT DETECTED - Custom wrapper
myStorage.save('token', jwt); // Uses localStorage internallyMitigation: Apply rule to wrapper implementations.
Obfuscated Key Names
Why: Key patterns may not match.
// ❌ NOT DETECTED - Obfuscated key
localStorage.setItem('_t', jwt); // Not in key patternsMitigation: Configure additional key patterns.
Encrypted Tokens
Why: Encrypted JWTs don't match pattern.
// ❌ NOT DETECTED - Encrypted
localStorage.setItem('data', encrypt(jwt)); // Pattern brokenMitigation: Still avoid localStorage for auth data.
OWASP Mapping
| Category | ID |
|---|---|
| OWASP Top 10 2021 | A02:2021 - Cryptographic Failures |
| CWE | CWE-922 |
| CVSS | 8.1 (High) |
no-innerhtml
Detects dangerous innerHTML/outerHTML assignments that can lead to Cross-Site Scripting (XSS). This rule is part of [`eslint-plugin-frontend-security`](https://
browser-security/no-postmessage-innerhtml
The rule provides **LLM-optimized error messages** (Compact 2-line format) with actionable security guidance: