require-secure-credential-storage
This rule detects when credentials are stored using localStorage.setItem() or fs.writeFile() without encryption
Enforces secure storage patterns for credentials
Severity: 🔴 CRITICAL
CWE: CWE-312: Cleartext Storage of Sensitive Information
OWASP Mobile: M1: Improper Credential Usage
Rule Details
This rule detects when credentials are stored using localStorage.setItem() or fs.writeFile() without encryption. Insecure credential storage (plaintext, weak encryption) leads to credential theft if the device is compromised or local storage is accessed.
Why This Matters
Stored credentials must be encrypted to prevent theft:
- Device theft: Attackers access unencrypted storage on stolen devices
- Malware: Keyloggers or storage scanners extract plaintext credentials
- Forensics: Deleted plaintext files can be recovered
- Compliance: GDPR/PCI-DSS require encryption for stored credentials
❌ Incorrect
// Plaintext localStorage (browser)
localStorage.setItem('authToken', user.token); // ❌ Unencrypted
// Plaintext file storage (Node.js)
import fs from 'fs';
fs.writeFile(
'credentials.json',
JSON.stringify({
username: user.username,
password: user.password, // ❌ Plaintext password!
}),
);
// Base64 encoding (NOT encryption!)
const encoded = btoa(JSON.stringify(credentials));
localStorage.setItem('creds', encoded); // ❌ Still plaintext, just encoded
// Weak "encryption" with reversible encoding
const obfuscated = rot13(password);
fs.writeFileSync('pass.txt', obfuscated); // ❌ Trivially reversible✅ Correct
const x = 42;Known False Negatives
The following patterns are not detected due to static analysis limitations:
Encryption via Wrapper Functions
Why: We only detect direct setItem() and writeFile() calls. If encryption happens in a wrapper function, we can't verify it.
// ❌ NOT DETECTED - Wrapper may or may not encrypt
function saveCredentials(creds: Credentials) {
localStorage.setItem('creds', JSON.stringify(creds)); // Actually unencrypted!
}
saveCredentials({ username, password });Mitigation: Document encryption requirements for wrapper functions. Use TypeScript branded types for encrypted data.
Weak or Broken Encryption
Why: We only check for the presence of encrypt() in the call chain. We can't verify encryption strength.
// ❌ NOT DETECTED - Weak encryption
const weakEncrypted = xorEncrypt(password, 'key'); // XOR is broken
localStorage.setItem('pass', weakEncrypted);Mitigation: Use vetted encryption libraries (SubtleCrypto, Node crypto). Enforce AES-256-GCM minimum.
SessionStorage vs LocalStorage
Why: We only check localStorage. sessionStorage and IndexedDB are not analyzed.
// ❌ NOT DETECTED - sessionStorage
sessionStorage.setItem('token', authToken); // Still unencrypted!Mitigation: Apply encryption requirement to all browser storage APIs. Use Content Security Policy.
⚙️ Configuration
This rule has no configuration options. It requires encrypt() wrapper for all setItem() and writeFile() calls.
🔗 Related Rules
no-hardcoded-credentials- Prevent hardcoded passwordsrequire-storage-encryption- General storage encryption