| name | security-fundamentals |
| description | This skill should be used when implementing security measures, preventing vulnerabilities, or securing applications - covers OWASP Top 10 prevention, input validation, authentication, secret management, and security best practices for all engineering agents. |
Security Fundamentals
Overview
Build secure applications by preventing common vulnerabilities and following security best practices. Every line of code that accepts user input or stores data needs security consideration.
Core principle: Security is not optional - it's a fundamental requirement that must be built in, not bolted on.
When to Use
Use when:
- Accepting user input
- Implementing authentication
- Storing sensitive data
- Building APIs
- Handling payments
- Before production deployment
OWASP Top 10 (2021)
1. Broken Access Control
Prevention:
// ✅ Check authorization
async function getUser(userId: string, requesterId: string) {
if (userId !== requesterId && !isAdmin(requesterId)) {
throw new ForbiddenError()
}
return db.users.findUnique({ where: { id: userId } })
}
// ❌ No authorization check
async function getUser(userId: string) {
return db.users.findUnique({ where: { id: userId } })
}
2. Cryptographic Failures
Prevention:
import bcrypt from 'bcrypt'
// ✅ Hash passwords
const hash = await bcrypt.hash(password, 10)
// ✅ Use HTTPS only
if (process.env.NODE_ENV === 'production' && !req.secure) {
return res.redirect(`https://${req.headers.host}${req.url}`)
}
// ❌ Store passwords in plaintext
const user = { password: password } // NEVER
3. Injection (SQL, NoSQL, Command)
SQL Injection Prevention:
// ✅ Use parameterized queries
const user = await db.query(
'SELECT * FROM users WHERE email = $1',
[email]
)
// ✅ Use ORM
const user = await prisma.user.findUnique({
where: { email }
})
// ❌ String concatenation
const user = await db.query(
`SELECT * FROM users WHERE email = '${email}'`
)
4. Insecure Design
Prevention:
- Threat modeling during design phase
- Security requirements upfront
- Least privilege principle
- Defense in depth (multiple layers)
- Fail securely (deny by default)
5. Security Misconfiguration
Security Headers:
// Next.js next.config.js
module.exports = {
async headers() {
return [{
source: '/:path*',
headers: [
{
key: 'X-Frame-Options',
value: 'DENY'
},
{
key: 'X-Content-Type-Options',
value: 'nosniff'
},
{
key: 'Referrer-Policy',
value: 'strict-origin-when-cross-origin'
},
{
key: 'Permissions-Policy',
value: 'camera=(), microphone=(), geolocation=()'
}
]
}]
}
}
6. Vulnerable Components
Prevention:
# Regular dependency audits
npm audit
npm audit fix
# Use Dependabot (GitHub)
# Use Snyk for vulnerability scanning
7. Authentication Failures
Secure authentication:
// ✅ Secure session
import { SessionOptions } from 'iron-session'
export const sessionOptions: SessionOptions = {
password: process.env.SESSION_SECRET!, // 32+ chars
cookieName: 'session',
cookieOptions: {
secure: process.env.NODE_ENV === 'production',
httpOnly: true,
sameSite: 'lax',
maxAge: 3600 // 1 hour
}
}
// ✅ Rate limit login attempts
const limiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 5 // 5 attempts per 15 minutes
})
app.use('/api/auth/login', limiter)
8. Software and Data Integrity Failures
Prevention:
// ✅ Verify data integrity
import crypto from 'crypto'
function verifySignature(data: string, signature: string) {
const hash = crypto
.createHmac('sha256', process.env.SECRET_KEY!)
.update(data)
.digest('hex')
return hash === signature
}
// ✅ Use SRI for CDN resources
<script
src="https://cdn.example.com/lib.js"
integrity="sha384-abc123..."
crossOrigin="anonymous"
/>
9. Logging and Monitoring Failures
Secure logging:
// ✅ Don't log sensitive data
logger.info('User login', {
userId: user.id,
// Don't log: password, tokens, PII
})
// ✅ Log security events
logger.warn('Failed login attempt', {
email, // ok to log attempt
ip: req.ip,
timestamp: new Date()
})
// ❌ Log sensitive data
logger.debug(`Password: ${password}`) // NEVER
10. Server-Side Request Forgery (SSRF)
Prevention:
// ✅ Validate and allowlist URLs
const ALLOWED_DOMAINS = ['api.trusted.com']
function fetchExternal(url: string) {
const urlObj = new URL(url)
if (!ALLOWED_DOMAINS.includes(urlObj.hostname)) {
throw new Error('Domain not allowed')
}
return fetch(url)
}
// ❌ Fetch user-provided URLs directly
fetch(userProvidedUrl) // Dangerous!
Input Validation
Validate everything:
import { z } from 'zod'
const UserSchema = z.object({
email: z.string().email().max(255),
password: z.string().min(8).max(100),
age: z.number().int().min(13).max(120)
})
// Validate
const result = UserSchema.safeParse(input)
if (!result.success) {
return { error: result.error.format() }
}
Secret Management
Never commit secrets:
# .gitignore
.env
.env.local
.env.production
*.pem
*.key
secrets/
Use environment variables:
// ✅ Environment variables
const apiKey = process.env.API_KEY
// ❌ Hardcoded
const apiKey = 'sk-abc123...' // NEVER
Secret rotation:
- Rotate secrets every 90 days
- Rotate immediately if compromised
- Use secret management service (AWS Secrets Manager, HashiCorp Vault)
CORS Configuration
// Next.js API route
export async function GET(req: Request) {
return new Response(json, {
headers: {
'Access-Control-Allow-Origin': process.env.ALLOWED_ORIGIN || '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
}
})
}
// ✅ Production: Specific origin
// ❌ Production: '*' (too permissive)
Rate Limiting
import { Ratelimit } from '@upstash/ratelimit'
import { Redis } from '@upstash/redis'
const ratelimit = new Ratelimit({
redis: Redis.fromEnv(),
limiter: Ratelimit.slidingWindow(10, '10 s')
})
export async function POST(req: Request) {
const ip = req.headers.get('x-forwarded-for') || 'unknown'
const { success } = await ratelimit.limit(ip)
if (!success) {
return new Response('Too Many Requests', { status: 429 })
}
// Process request
}
Security Checklist
Before production:
- All secrets in environment variables
- HTTPS enforced
- Security headers configured
- Input validation on all endpoints
- SQL injection prevention (parameterized queries)
- XSS prevention (escape output)
- CSRF protection
- Rate limiting on auth endpoints
- Passwords hashed (bcrypt, scrypt, or Argon2)
- Authentication implemented correctly
- Authorization checks on all protected routes
- Error messages don't leak sensitive info
- Dependencies audited (npm audit)
- CORS configured properly
- Session cookies: httpOnly, secure, sameSite
Resources
- OWASP Top 10: owasp.org/Top10
- OWASP Cheat Sheets: cheatsheetseries.owasp.org
- Security headers: securityheaders.com
Security is not negotiable. Build it in from the start.