| name | hashing-passwords |
| description | CRITICAL security skill teaching proper credential and password handling. NEVER store passwords, use bcrypt/argon2, NEVER accept third-party credentials. Use when handling authentication, passwords, API keys, or any sensitive credentials. |
| allowed-tools | Read, Write, Edit, Glob, Grep, Bash, Task, TodoWrite |
| version | 1.0.0 |
THIS IS A ZERO-TOLERANCE SECURITY SKILL. NO EXCEPTIONS.
- Working with passwords or authentication
- Handling API keys, tokens, or credentials
- Storing sensitive user data
- Implementing login, signup, or password reset
- User mentions passwords, credentials, encryption, hashing, or authentication
- Code contains password storage, credential handling, or third-party auth
RULE 1: NEVER STORE PASSWORDS
Store password HASHES only, using bcrypt or argon2. Passwords must be:
- Hashed (NOT encrypted, NOT Base64, NOT plaintext)
- Salted automatically by bcrypt/argon2
- Using modern algorithms (bcrypt cost 12+, argon2id)
RULE 2: NEVER ACCEPT THIRD-PARTY CREDENTIALS
NEVER ask users for passwords to other services (PayPal, Google, etc.):
- Use OAuth instead
- Use API keys from the service
- Use service-provided SDKs
RULE 3: NEVER USE ENCODING AS ENCRYPTION
- Base64 is NOT encryption (trivially reversible)
- URL encoding is NOT security
- Hex encoding is NOT security
RULE 4: USE PROPER CRYPTOGRAPHY
- For passwords: bcrypt or argon2
- For encryption: Use established libraries (crypto module, Web Crypto API)
- For API keys: Store in environment variables, use secret management
❌ Base64 "Encryption": Buffer.from(password).toString("base64") is encoding, NOT encryption. Trivially reversible.
❌ Third-Party Passwords: Never accept PayPal/Google/etc passwords. Use OAuth.
❌ Plaintext Storage: Never store raw passwords. Always hash.
❌ Weak Hashing: MD5/SHA-1/SHA-256 too fast. Use bcrypt/argon2.
See references/never-do-this.md for detailed examples and failures.
import bcrypt from "bcrypt";
const SALT_ROUNDS = 12;
async function hashPassword(password: string): Promise<string> {
return await bcrypt.hash(password, SALT_ROUNDS);
}
async function verifyPassword(
password: string,
hash: string
): Promise<boolean> {
return await bcrypt.compare(password, hash);
}
interface User {
id: string;
email: string;
passwordHash: string;
}
Key Points:
- bcrypt designed for passwords
- Automatic salting
- Cost factor 12+ (prevents brute force)
- Never stores actual password
✅ CORRECT: argon2 (More Modern)
import argon2 from "argon2";
async function hashPassword(password: string): Promise<string> {
return await argon2.hash(password, {
type: argon2.argon2id,
memoryCost: 2 ** 16,
timeCost: 3,
parallelism: 1
});
}
Advantages: Memory-hard, resists GPU attacks, latest standard.
✅ CORRECT: OAuth for Third-Party Services
import { google } from "googleapis";
const oauth2Client = new google.auth.OAuth2(
process.env.GOOGLE_CLIENT_ID,
process.env.GOOGLE_CLIENT_SECRET,
"http://localhost:3000/auth/callback"
);
function getAuthUrl(): string {
return oauth2Client.generateAuthUrl({
access_type: "offline",
scope: ["https://www.googleapis.com/auth/userinfo.email"]
});
}
Key Points: Token-based, never sees user password, revocable.
✅ CORRECT: Environment Variables for API Keys
function loadConfig(): Config {
const apiKey = process.env.STRIPE_API_KEY;
if (!apiKey) {
throw new Error("Missing required API key");
}
return { apiKey };
}
See references/correct-implementations.md for complete examples.
- Use bcrypt (cost 12+) or argon2id for password hashing
- Store password HASHES only, never passwords
- Use OAuth for third-party service authentication
- Store API keys in environment variables
- Validate password strength (min length, complexity)
- Use HTTPS for all authentication endpoints
NEVER:
- Store passwords in any form (plaintext, Base64, encrypted)
- Use MD5, SHA-1, or SHA-256 for passwords
- Accept third-party credentials (PayPal, Google, etc.)
- Hardcode API keys or secrets
- Use encoding (Base64, hex) as "encryption"
- Email passwords to users
- Log passwords (even in dev mode)
SHOULD:
- Implement password strength requirements
- Rate-limit login attempts
- Use two-factor authentication (2FA)
- Implement account lockout after failed attempts
- Rotate API keys periodically
- Use secret management services (AWS Secrets Manager, HashiCorp Vault)
- Length: 12+ characters (prefer 16+)
- Complexity: Uppercase, lowercase, numbers, special chars
- Validation: Reject common passwords ("password", "12345678")
See references/password-validation.md for complete implementation.
bcrypt:
npm install bcrypt
npm install -D @types/bcrypt
argon2:
npm install argon2
npm install -D @types/argon2
Note: Both require native compilation. Ensure build tools are available.
Detailed Examples:
references/never-do-this.md- Security failures and anti-patternsreferences/correct-implementations.md- Complete working examplesreferences/password-validation.md- Password strength validationreferences/emergency-response.md- Breach response and migration
Related Skills:
- Input Validation: Use the sanitizing-user-inputs skill
- Dependencies: Use the auditing-dependencies skill
- External Data: Use the validating-external-data skill
Password Storage:
- Uses bcrypt (cost 12+) or argon2id
- NEVER stores actual passwords
- Password hashes stored in separate column
- No way to retrieve original password
Third-Party Auth:
- Uses OAuth/OpenID Connect
- NEVER asks for third-party passwords
- Tokens stored securely
- Follows service Terms of Service
API Keys:
- Stored in environment variables
- Not hardcoded in source
- Not committed to git
-
.envfile in.gitignore
Password Requirements:
- Minimum 12 characters (prefer 16+)
- Complexity requirements enforced
- Common passwords rejected
- Strength meter for users
Additional Security:
- HTTPS required for auth endpoints
- Rate limiting on login
- Account lockout after failures
- Password reset via email only
- No password hints or security questions
"I need to retrieve the password later" → You never need to retrieve passwords. Use password reset instead.
"Base64 is encryption" → Base64 is encoding for transport, not security.
"I'll encrypt passwords" → If you can decrypt, so can attackers. Hash, don't encrypt.
"SHA-256 is secure" → SHA-256 is too fast. Use bcrypt/argon2.
"I need PayPal credentials to check balance" → Use PayPal's API with OAuth tokens.
IMMEDIATE ACTIONS:
- Stop the application (if running)
- Do NOT commit the code
- Implement proper hashing (bcrypt/argon2)
- Force password reset for all users
- Notify security team
- Assess breach scope
See references/emergency-response.md for complete migration guide.