no-sensitive-cookie-js
The rule provides LLM-optimized error messages (Compact 2-line format) with actionable security guidance:
🔒 Disallow storing sensitive data (tokens, passwords) in cookies via JavaScript
CWE: CWE-359
OWASP Mobile: OWASP Mobile Top 10
Error Message Format
The rule provides LLM-optimized error messages (Compact 2-line format) with actionable security guidance:
⚠️ CWE-1004 OWASP:A02 CVSS:5.3 | Sensitive Cookie Without HttpOnly detected | MEDIUM
Fix: Review and apply the recommended fix | https://owasp.org/Top10/A02_2021/Message Components
| Component | Purpose | Example |
|---|---|---|
| Risk Standards | Security benchmarks | CWE-1004 OWASP:A02 CVSS:5.3 |
| Issue Description | Specific vulnerability | Sensitive Cookie Without HttpOnly 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 prevents setting sensitive cookies (authentication tokens, session IDs, etc.) via document.cookie. Cookies set through JavaScript are accessible to XSS attacks, while server-set cookies with the HttpOnly flag are protected.
Why is this dangerous?
When you set cookies via JavaScript:
- Any XSS attack can read the cookie via
document.cookie - No way to add HttpOnly flag - only the server can set it
- Session tokens become vulnerable to theft
Examples
❌ Incorrect
// A secret in a cookie set from JavaScript
document.cookie = 'password=' + password;
document.cookie = `api_key=${key}; Secure; SameSite=Strict`;
// Even with security attributes, still readable by any script
document.cookie = 'client_secret=xyz; Secure; SameSite=Strict';
// Bearer credentials — token, jwt, sessionId, access_token, refreshToken —
// are reported by no-cookie-auth-tokens, not this rule:
document.cookie = 'access_token=' + accessToken;✅ Correct
// Non-sensitive cookies are fine
document.cookie = 'theme=dark';
document.cookie = 'locale=en-US';
document.cookie = 'visited=true';
// Set auth tokens via server response:
// Server: res.cookie('token', value, {
// httpOnly: true,
// secure: true,
// sameSite: 'strict'
// });
// Or use fetch to get server-set HttpOnly cookie
await fetch('/api/auth/login', {
method: 'POST',
credentials: 'include',
body: JSON.stringify({ username, password }),
});
// Server sets: Set-Cookie: token=xxx; HttpOnly; Secure; SameSite=StrictOptions
| Option | Type | Default | Description |
|---|---|---|---|
allowInTests | boolean | true | Skip this rule in *.test.* / *.spec.* files |
sensitivePatterns | string[] | ["password","passwd","pwd","passphrase","secret","api key","apikey","private key","secret key","encryption key","signing key","client secret","credit card","card number","cvv","cvc","ssn","social security","seed phrase","mnemonic","recovery code"] | Patterns to detect as sensitive |
{
"browser-security/no-sensitive-cookie-js": [
"error",
{
"allowInTests": true,
"sensitivePatterns": [
"token",
"jwt",
"session",
"auth",
"password",
"secret",
"api_key",
"credential"
]
}
]
}| Option | Type | Default | Description |
|---|---|---|---|
allowInTests | boolean | true | Skip checking in test files |
sensitivePatterns | string[] | See below | Patterns to detect as sensitive |
Default Sensitive Patterns
Whole-word terms, matched after splitting the cookie name on _, -, . and case
boundaries. Bearer credentials (token, jwt, session, auth, …) are not in
this list: they are owned by no-cookie-auth-tokens,
which reports them under the same vocabulary partition. Setting sensitivePatterns
replaces the list.
[
'password',
'passwd',
'pwd',
'passphrase',
'secret',
'api key',
'apikey',
'private key',
'secret key',
'encryption key',
'signing key',
'client secret',
'credit card',
'card number',
'cvv',
'cvc',
'ssn',
'social security',
'seed phrase',
'mnemonic',
'recovery code',
];When Not To Use It
You may disable this rule if:
- You're implementing a legacy system that requires client-side cookie management
- You're working with non-sensitive cookies only
However, always prefer server-set HttpOnly cookies for any authentication-related data.
Server-Side Cookie Best Practices
Express.js
res.cookie('token', jwtToken, {
httpOnly: true, // Prevents XSS access
secure: true, // HTTPS only
sameSite: 'strict', // CSRF protection
maxAge: 3600000, // 1 hour
});NestJS
@Post('login')
login(@Res() res: Response) {
res.cookie('token', jwtToken, {
httpOnly: true,
secure: true,
sameSite: 'strict'
});
}Related
- CWE-1004: Sensitive Cookie Without 'HttpOnly' Flag
- MDN: Cookie Security
- OWASP: Session Management Cheat Sheet
Known False Negatives
The following patterns are not detected due to static analysis limitations:
Dynamic Cookie Name
Why: Computed names not analyzed.
// ❌ NOT DETECTED - Dynamic name
const name = 'authToken';
document.cookie = `${name}=${value}`;Mitigation: Never set auth cookies client-side.
Cookie Values from Variables
Why: Value patterns in variables not traced.
// ❌ NOT DETECTED - Value from variable
const data = jwt;
document.cookie = 'data=' + data;Mitigation: Set auth cookies server-side.
Cookie Library Wrappers
Why: Library methods not recognized.
// ❌ NOT DETECTED - Library wrapper
js - cookie.set('token', jwt);Mitigation: Apply rule to library implementations.
OWASP Mapping
| Category | ID |
|---|---|
| OWASP Top 10 2021 | A02:2021 - Cryptographic Failures |
| CWE | CWE-1004 |
| CVSS | 8.1 (High) |
Use this rule
npm install -D oxlint-plugin-browser-security{ "jsPlugins": ["oxlint-plugin-browser-security"], "rules": { "browser-security/no-sensitive-cookie-js": "error" }}import { defineConfig } from 'vite-plus';export default defineConfig({ lint: { jsPlugins: ['oxlint-plugin-browser-security'], rules: { 'browser-security/no-sensitive-cookie-js': 'error', }, },});oxlint-plugin-browser-security re-exports eslint-plugin-browser-security/oxlint: the same rules under the same IDs, and no ESLint install. Why oxlint.
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.