Auto-invoke when reviewing authentication, authorization, input handling, data exposure, or any user-facing code. Enforces OWASP top 10 awareness and security-first thinking.
"Security is not a feature. It's a foundation. Build on sand, and the house falls."
Activate this skill when reviewing:
❌ db.query(`SELECT * FROM users WHERE id = ${userId}`);
✅ db.query('SELECT * FROM users WHERE id = ?', [userId]);
❌ if (req.headers.admin === 'true') { /* allow admin */ }
✅ const user = await verifyToken(req.headers.authorization);
if (user.role !== 'admin') throw new ForbiddenError();
❌ res.json({ user: { ...user, password, ssn } });
✅ res.json({ user: { id: user.id, name: user.name } });
❌ app.get('/users/:id', async (req, res) => {
const user = await User.findById(req.params.id);
res.json(user);
});
✅ app.get('/users/:id', async (req, res) => {
const user = await User.findById(req.params.id);
if (user.id !== req.user.id && req.user.role !== 'admin') {
throw new ForbiddenError();
}
res.json(user);
});
❌ CORS: origin: '*'
❌ Detailed error messages in production
❌ Debug mode enabled in production
✅ CORS: origin: process.env.ALLOWED_ORIGINS
✅ Generic error messages to clients
✅ Debug mode disabled in production
❌ element.innerHTML = userInput;
✅ element.textContent = userInput;
✅ DOMPurify.sanitize(userInput);
Ask the junior these questions instead of giving answers:
git clone this repo, what secrets would I see?"'; DROP TABLE users; -- as input?"| Flag | Risk | Question |
|---|---|---|
| String concatenation in queries | SQL Injection | "Can this input contain SQL?" |
eval() or new Function() |
Code Injection | "Why is dynamic code execution needed?" |
innerHTML with user data |
XSS | "What if the user includes <script>?" |
| Passwords in logs | Data Leak | "Who can see these logs?" |
| No rate limiting on auth | Brute Force | "What stops someone from trying every password?" |
CORS: * |
Security Bypass | "Should any website be able to call this API?" |
| JWT with no expiry | Token Theft | "What happens if this token is stolen?" |
| IDs in URLs | IDOR | "Can user A access user B's data by changing the ID?" |
| Action | Why |
|---|---|
| Store passwords in plaintext | One breach exposes all users |
| Put secrets in code | Git history is forever |
| Trust client-side validation only | Anyone can bypass the client |
| Return full database objects | Exposes internal fields |
| Log sensitive data | Logs get compromised too |
Use md5 or sha1 for passwords |
Cryptographically broken |