# OWASP Top 10 (2021) — Detailed Reference
Comprehensive breakdown of each OWASP Top 10 category with CWE mappings, vulnerability patterns, and remediation strategies.
## A01:2021 – Broken Access Control
Access control enforces policy such that users cannot act outside of their intended permissions. Failures typically lead to unauthorized information disclosure, modification, or destruction of data.
### Common Weaknesses
- **Missing Function Level Access Control** — users can access admin functions
- **Missing Resource Level Access Control (IDOR)** — users can access others' resources
- **CORS Misconfiguration** — overly permissive cross-origin policies
- **Force Browsing** — accessing pages/resources by URL guessing
- **Metadata Manipulation** — JWT/cookie tampering to elevate privileges
- **POST-based CSRF** — state-changing operations without CSRF protection
### CWE Mappings
- CWE-200: Exposure of Sensitive Information to an Unauthorized Actor
- CWE-201: Insertion of Sensitive Information Into Sent Data
- CWE-352: Cross-Site Request Forgery (CSRF)
- CWE-359: Exposure of Private Personal Information to an Unauthorized Actor
- CWE-377: Insecure Temporary File
- CWE-402: Transmission of Private Resources into a New Sphere
- CWE-425: Direct Request (Forced Browsing)
- CWE-639: Authorization Bypass Through User-Controlled Key
- CWE-759: Use of a One-Way Hash without a Salt
- CWE-918: Server-Side Request Forgery (SSRF)
- CWE-1275: Sensitive Cookie with Improper SameSite Attribute
### Vulnerability Patterns
**IDOR (Insecure Direct Object Reference)**:
```typescript
// VULNERABLE — sequential IDs, no ownership check
GET /api/invoices/1001
{
"invoice_id": 1001,
"customer_id": 42,
"amount": 1500
}
// ATTACK — iterate through IDs
GET /api/invoices/1002 // Access someone else's invoice
GET /api/invoices/1003
GET /api/invoices/1004
```
**Remediation**:
```typescript
// SECURE — verify ownership before returning
app.get('/api/invoices/:id', authenticate, async (req, res) => {
const invoice = await db.getInvoice(req.params.id);
if (!invoice) {
return res.status(404).json({ error: 'Not found' });
}
// Verify user owns resource or is admin
if (invoice.customerId !== req.user.id && !req.user.isAdmin) {
return res.status(403).json({ error: 'Forbidden' });
}
res.json(invoice);
});
// BETTER — use UUIDs instead of sequential IDs
const invoiceId = crypto.randomUUID(); // Non-guessable
```
**Missing Function Level Access Control**:
```typescript
// VULNERABLE — client-side check only
function AdminPanel() {
if (!user.isAdmin) {
return
Access Denied
;
}
return ;
}
// Attacker can still call API directly:
fetch('/api/admin/users').then(r => r.json()) // No server-side check!
```
**Remediation**:
```typescript
// SECURE — enforce on server
app.get('/api/admin/users', authenticate, requireAdmin, async (req, res) => {
// Server validates role on every request
if (!req.user.isAdmin) {
return res.status(403).json({ error: 'Forbidden' });
}
const users = await db.getAllUsers();
res.json(users);
});
// Middleware
function requireAdmin(req, res, next) {
if (!req.user?.isAdmin) {
return res.status(403).json({ error: 'Forbidden' });
}
next();
}
```
**CORS Misconfiguration**:
```typescript
// VULNERABLE — allows all origins
app.use(cors({
origin: '*',
credentials: true // Allows any site to make authenticated requests!
}));
```
**Remediation**:
```typescript
// SECURE — explicit allowlist
const allowedOrigins = [
'https://app.example.com',
'https://admin.example.com',
];
app.use(cors({
origin: (origin, callback) => {
if (!origin || allowedOrigins.includes(origin)) {
callback(null, true);
} else {
callback(new Error('Not allowed by CORS'));
}
},
credentials: true,
}));
```
---
## A02:2021 – Cryptographic Failures
Previously known as Sensitive Data Exposure. Focuses on failures related to cryptography which often lead to exposure of sensitive data.
### Common Weaknesses
- **Transmitting data in clear text** — HTTP instead of HTTPS
- **Old/weak cryptographic algorithms** — MD5, SHA1, DES
- **Default/weak keys** — hardcoded or predictable
- **Missing encryption at rest** — sensitive data stored unencrypted
- **Improper certificate validation** — accepting self-signed certs in production
- **Insufficient entropy** — predictable random numbers
### CWE Mappings
- CWE-259: Use of Hard-coded Password
- CWE-327: Use of a Broken or Risky Cryptographic Algorithm
- CWE-331: Insufficient Entropy
### Vulnerability Patterns
**Weak Hashing Algorithm**:
```typescript
// VULNERABLE — MD5 is broken
const hash = crypto.createHash('md5').update(password).digest('hex');
// VULNERABLE — SHA1 is deprecated
const hash = crypto.createHash('sha1').update(password).digest('hex');
// VULNERABLE — no salt (rainbow tables)
const hash = crypto.createHash('sha256').update(password).digest('hex');
```
**Remediation**:
```typescript
// SECURE — bcrypt with sufficient cost
import bcrypt from 'bcrypt';
const saltRounds = 12; // Minimum 10, increase as hardware improves
const hash = await bcrypt.hash(password, saltRounds);
// Verification
const isValid = await bcrypt.compare(inputPassword, storedHash);
// ALTERNATIVE — Argon2 (winner of Password Hashing Competition)
import argon2 from 'argon2';
const hash = await argon2.hash(password, {
type: argon2.argon2id, // Resistant to GPU and side-channel attacks
memoryCost: 2 ** 16, // 64 MiB
timeCost: 3,
parallelism: 1,
});
```
**Hardcoded Secrets**:
```typescript
// VULNERABLE — secrets in code
const API_KEY = 'sk-1234567890abcdef';
const DB_PASSWORD = 'admin123';
const JWT_SECRET = 'mysecret';
// Committed to Git — now in history forever!
```
**Remediation**:
```typescript
// SECURE — environment variables
const API_KEY = process.env.API_KEY;
const DB_PASSWORD = process.env.DB_PASSWORD;
const JWT_SECRET = process.env.JWT_SECRET;
// Validate at startup
if (!API_KEY || !DB_PASSWORD || !JWT_SECRET) {
throw new Error('Missing required environment variables');
}
// .env (add to .gitignore!)
API_KEY=sk-real-key-here
DB_PASSWORD=strong-password-here
JWT_SECRET=long-random-string-here
// .env.example (commit this)
API_KEY=your_api_key_here
DB_PASSWORD=your_db_password_here
JWT_SECRET=your_jwt_secret_here
```
**Weak Encryption Algorithm**:
```typescript
// VULNERABLE — DES is broken
const cipher = crypto.createCipher('des', key);
// VULNERABLE — ECB mode (patterns leak)
const cipher = crypto.createCipheriv('aes-256-ecb', key, null);
// VULNERABLE — no authentication (malleable)
const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
```
**Remediation**:
```typescript
// SECURE — AES-256-GCM (authenticated encryption)
const algorithm = 'aes-256-gcm';
const key = crypto.randomBytes(32); // 256 bits
const iv = crypto.randomBytes(16); // 128 bits
// Encryption
const cipher = crypto.createCipheriv(algorithm, key, iv);
let encrypted = cipher.update(plaintext, 'utf8', 'hex');
encrypted += cipher.final('hex');
const authTag = cipher.getAuthTag();
// Store: iv + authTag + encrypted
// Decryption
const decipher = crypto.createDecipheriv(algorithm, key, iv);
decipher.setAuthTag(authTag);
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
decrypted += decipher.final('utf8');
```
**Insufficient Entropy**:
```typescript
// VULNERABLE — predictable
const sessionId = Math.random().toString(36);
const resetToken = Date.now().toString(36);
const apiKey = userId + '-' + Math.floor(Math.random() * 1000000);
```
**Remediation**:
```typescript
// SECURE — cryptographically secure random
const sessionId = crypto.randomBytes(32).toString('hex'); // 64 hex chars
const resetToken = crypto.randomBytes(32).toString('base64url');
const apiKey = crypto.randomBytes(24).toString('base64url');
// For UUIDs
const uuid = crypto.randomUUID(); // UUIDv4
```
---
## A03:2021 – Injection
Application is vulnerable to injection when user-supplied data is not validated, filtered, or sanitized by the application.
### Common Weaknesses
- **SQL Injection** — malicious SQL in queries
- **NoSQL Injection** — malicious queries in MongoDB, etc.
- **OS Command Injection** — executing shell commands
- **LDAP Injection** — malicious LDAP queries
- **XPath Injection** — malicious XPath queries
- **ORM Injection** — unsafe ORM query construction
### CWE Mappings
- CWE-20: Improper Input Validation
- CWE-74: Improper Neutralization of Special Elements in Output
- CWE-75: Failure to Sanitize Special Elements into a Different Plane
- CWE-77: Improper Neutralization of Special Elements used in a Command
- CWE-78: Improper Neutralization of Special Elements used in an OS Command
- CWE-79: Improper Neutralization of Input During Web Page Generation (XSS)
- CWE-80: Improper Neutralization of Script-Related HTML Tags
- CWE-83: Improper Neutralization of Script in Attributes
- CWE-89: Improper Neutralization of Special Elements used in an SQL Command
- CWE-91: XML Injection
- CWE-93: Improper Neutralization of CRLF Sequences
- CWE-94: Improper Control of Generation of Code
- CWE-95: Improper Neutralization of Directives in Dynamically Evaluated Code
- CWE-96: Improper Neutralization of Directives in Statically Saved Code
- CWE-97: Improper Neutralization of Server-Side Includes
- CWE-183: Permissive List of Allowed Inputs
- CWE-184: Incomplete List of Disallowed Inputs
### Vulnerability Patterns
**SQL Injection**:
```sql
-- VULNERABLE — string concatenation
const query = `SELECT * FROM users WHERE email = '${userEmail}' AND password = '${userPassword}'`;
-- ATTACK
userEmail: admin@example.com'--
userPassword: anything
-- RESULTS IN
SELECT * FROM users WHERE email = 'admin@example.com'--' AND password = 'anything'
-- Comment removes password check!
-- ATTACK 2 — data exfiltration
userEmail: ' UNION SELECT password FROM users--
-- ATTACK 3 — blind SQL injection
userEmail: ' OR 1=1--
```
**Remediation**:
```typescript
// SECURE — parameterized queries (prepared statements)
const query = 'SELECT * FROM users WHERE email = ? AND password = ?';
const [rows] = await db.execute(query, [userEmail, passwordHash]);
// PostgreSQL — numbered placeholders
const query = 'SELECT * FROM users WHERE email = $1 AND password = $2';
const result = await pool.query(query, [userEmail, passwordHash]);
// ORM — use safe methods
const user = await User.findOne({
where: {
email: userEmail,
password: passwordHash,
},
});
// NEVER — string interpolation or concatenation in SQL
```
**NoSQL Injection**:
```javascript
// VULNERABLE — object injection
app.post('/login', async (req, res) => {
const { email, password } = req.body;
const user = await db.collection('users').findOne({
email: email,
password: password,
});
});
// ATTACK — bypass authentication
POST /login
{
"email": { "$gt": "" },
"password": { "$gt": "" }
}
// Query becomes: find where email > "" AND password > ""
// Returns first user!
```
**Remediation**:
```typescript
// SECURE — type validation
app.post('/login', async (req, res) => {
const { email, password } = req.body;
// Ensure inputs are strings
if (typeof email !== 'string' || typeof password !== 'string') {
return res.status(400).json({ error: 'Invalid input' });
}
const user = await db.collection('users').findOne({
email: email,
password: await hashPassword(password),
});
});
// BETTER — schema validation
import { z } from 'zod';
const loginSchema = z.object({
email: z.string().email(),
password: z.string().min(8),
});
app.post('/login', async (req, res) => {
const result = loginSchema.safeParse(req.body);
if (!result.success) {
return res.status(400).json({ error: 'Invalid input' });
}
const { email, password } = result.data;
// Now guaranteed to be strings
});
```
**OS Command Injection**:
```typescript
// VULNERABLE — user input in shell command
const filename = req.query.file;
exec(`convert ${filename} output.png`, (err, stdout) => {
// Process output
});
// ATTACK
?file=; rm -rf /
// RESULTS IN
convert ; rm -rf / output.png
// Executes rm -rf /!
```
**Remediation**:
```typescript
// SECURE — use parameterized API
import { execFile } from 'child_process';
const filename = req.query.file;
// Validate filename
if (!/^[a-zA-Z0-9._-]+$/.test(filename)) {
return res.status(400).json({ error: 'Invalid filename' });
}
// Use execFile with array arguments (no shell)
execFile('convert', [filename, 'output.png'], (err, stdout) => {
if (err) {
logger.error('Conversion failed', err);
return res.status(500).json({ error: 'Conversion failed' });
}
// Process output
});
// BETTER — use library instead of shell command
import sharp from 'sharp';
await sharp(filename).toFile('output.png');
```
**XSS (Cross-Site Scripting)**:
```html
?name=
Hello

!
```
**Remediation**:
```html
```
---
## A04:2021 – Insecure Design
New category focusing on risks related to design and architectural flaws. Requires threat modeling, secure design patterns, and reference architectures.
### Common Weaknesses
- **Missing Security Controls** — no rate limiting, no CAPTCHA
- **Business Logic Flaws** — discount code stacking, negative quantities
- **Insufficient Isolation** — multi-tenant data leakage
- **Weak Security Architecture** — no defense in depth
### CWE Mappings
- CWE-209: Generation of Error Message Containing Sensitive Information
- CWE-256: Plaintext Storage of a Password
- CWE-257: Storing Passwords in a Recoverable Format
- CWE-266: Incorrect Privilege Assignment
- CWE-269: Improper Privilege Management
- CWE-280: Improper Handling of Insufficient Permissions
- CWE-311: Missing Encryption of Sensitive Data
- CWE-312: Cleartext Storage of Sensitive Information
- CWE-313: Cleartext Storage in a File or on Disk
- CWE-316: Cleartext Storage of Sensitive Information in Memory
- CWE-419: Unprotected Primary Channel
- CWE-430: Deployment of Wrong Handler
- CWE-434: Unrestricted Upload of File with Dangerous Type
- CWE-444: Inconsistent Interpretation of HTTP Requests
### Vulnerability Patterns
**Missing Rate Limiting**:
```typescript
// VULNERABLE — no rate limiting
app.post('/api/login', async (req, res) => {
const { email, password } = req.body;
const user = await authenticateUser(email, password);
if (!user) {
return res.status(401).json({ error: 'Invalid credentials' });
}
res.json({ token: generateToken(user) });
});
// ATTACK — brute force attack
// Try thousands of passwords per second
```
**Remediation**:
```typescript
// SECURE — rate limiting with exponential backoff
import rateLimit from 'express-rate-limit';
const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 5, // 5 attempts per window
skipSuccessfulRequests: true,
standardHeaders: true,
legacyHeaders: false,
handler: (req, res) => {
res.status(429).json({
error: 'Too many login attempts, please try again later',
});
},
});
app.post('/api/login', loginLimiter, async (req, res) => {
// Authentication logic
});
// BETTER — account lockout after failed attempts
const MAX_FAILED_ATTEMPTS = 5;
const LOCKOUT_DURATION = 30 * 60 * 1000; // 30 minutes
app.post('/api/login', async (req, res) => {
const { email, password } = req.body;
const account = await getAccount(email);
// Check if locked
if (account.lockedUntil && account.lockedUntil > Date.now()) {
return res.status(429).json({
error: 'Account locked. Try again later.',
});
}
const user = await authenticateUser(email, password);
if (!user) {
// Increment failed attempts
account.failedAttempts += 1;
if (account.failedAttempts >= MAX_FAILED_ATTEMPTS) {
account.lockedUntil = Date.now() + LOCKOUT_DURATION;
await saveAccount(account);
return res.status(429).json({ error: 'Account locked' });
}
await saveAccount(account);
return res.status(401).json({ error: 'Invalid credentials' });
}
// Reset on success
account.failedAttempts = 0;
account.lockedUntil = null;
await saveAccount(account);
res.json({ token: generateToken(user) });
});
```
**Business Logic Flaw — Race Condition**:
```typescript
// VULNERABLE — time-of-check to time-of-use
app.post('/api/transfer', async (req, res) => {
const { from, to, amount } = req.body;
const balance = await getBalance(from);
if (balance < amount) {
return res.status(400).json({ error: 'Insufficient funds' });
}
// RACE CONDITION — balance could be spent between check and update
await deduct(from, amount);
await credit(to, amount);
res.json({ success: true });
});
// ATTACK — send two transfer requests simultaneously
// Both pass balance check before either updates
```
**Remediation**:
```typescript
// SECURE — atomic transaction
app.post('/api/transfer', async (req, res) => {
const { from, to, amount } = req.body;
const result = await db.transaction(async (trx) => {
// Lock row for update
const account = await trx('accounts')
.where({ id: from })
.forUpdate()
.first();
if (account.balance < amount) {
throw new Error('Insufficient funds');
}
// Atomic debit/credit
await trx('accounts')
.where({ id: from })
.decrement('balance', amount);
await trx('accounts')
.where({ id: to })
.increment('balance', amount);
return { success: true };
});
res.json(result);
});
// Database-level constraint
ALTER TABLE accounts ADD CONSTRAINT positive_balance CHECK (balance >= 0);
```
---
## A05:2021 – Security Misconfiguration
### Common Weaknesses
- **Unnecessary features enabled** — debug mode in production
- **Default accounts** — admin/admin still active
- **Verbose error messages** — stack traces to users
- **Missing security headers** — no CSP, X-Frame-Options
- **Outdated software** — old framework versions
### CWE Mappings
- CWE-2: 7PK - Environment
- CWE-11: ASP.NET Misconfiguration
- CWE-13: ASP.NET Misconfiguration: Password in Configuration File
- CWE-15: External Control of System or Configuration Setting
- CWE-16: Configuration
- CWE-260: Password in Configuration File
- CWE-315: Cleartext Storage of Sensitive Information in a Cookie
- CWE-520: .NET Misconfiguration
- CWE-526: Exposure of Sensitive Information Through Environmental Variables
- CWE-537: Java Runtime Error Message Containing Sensitive Information
- CWE-541: Inclusion of Sensitive Information in an Include File
- CWE-547: Use of Hard-coded, Security-relevant Constants
- CWE-611: Improper Restriction of XML External Entity Reference
- CWE-614: Sensitive Cookie in HTTPS Session Without 'Secure' Attribute
- CWE-756: Missing Custom Error Page
- CWE-776: Improper Restriction of Recursive Entity References in DTDs
### Remediation
**Security Headers**:
```typescript
import helmet from 'helmet';
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-inline'"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "data:", "https:"],
connectSrc: ["'self'"],
fontSrc: ["'self'"],
objectSrc: ["'none'"],
mediaSrc: ["'self'"],
frameSrc: ["'none'"],
},
},
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true,
},
}));
// Additional headers
app.use((req, res, next) => {
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('X-Frame-Options', 'DENY');
res.setHeader('X-XSS-Protection', '1; mode=block');
res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
next();
});
```
---
## A06:2021 – Vulnerable and Outdated Components
### Common Weaknesses
- **Known vulnerabilities** — using libs with CVEs
- **Outdated dependencies** — years-old versions
- **No security updates** — never updating packages
- **Unused dependencies** — unnecessary attack surface
### CWE Mappings
- CWE-1035: Using Components with Known Vulnerabilities
- CWE-1104: Use of Unmaintained Third Party Components
### Remediation
```bash
# Audit dependencies
npm audit
npm audit fix
# Update outdated packages
npm outdated
npm update
# Check for known vulnerabilities
npx snyk test
# Automated dependency updates
# Use Dependabot/Renovate for automated PRs
```
---
## A07:2021 – Identification and Authentication Failures
### Common Weaknesses
- **Weak passwords** — no complexity requirements
- **Brute force** — no rate limiting
- **Session fixation** — accepting user-supplied session IDs
- **Credential stuffing** — no breach detection
- **Missing MFA** — single factor only
### CWE Mappings
- CWE-287: Improper Authentication
- CWE-288: Authentication Bypass Using an Alternate Path or Channel
- CWE-290: Authentication Bypass by Spoofing
- CWE-294: Authentication Bypass by Capture-replay
- CWE-295: Improper Certificate Validation
- CWE-297: Improper Validation of Certificate with Host Mismatch
- CWE-300: Channel Accessible by Non-Endpoint
- CWE-302: Authentication Bypass by Assumed-Immutable Data
- CWE-304: Missing Critical Step in Authentication
- CWE-306: Missing Authentication for Critical Function
- CWE-307: Improper Restriction of Excessive Authentication Attempts
- CWE-346: Origin Validation Error
- CWE-384: Session Fixation
- CWE-521: Weak Password Requirements
- CWE-613: Insufficient Session Expiration
- CWE-640: Weak Password Recovery Mechanism for Forgotten Password
- CWE-798: Use of Hard-coded Credentials
- CWE-940: Improper Verification of Source of a Communication Channel
- CWE-1216: Lockout Mechanism Errors
### Remediation
See main SKILL.md for authentication patterns.
---
## A08:2021 – Software and Data Integrity Failures
### Common Weaknesses
- **Unsigned updates** — accepting any code update
- **Insecure deserialization** — unvalidated object deserialization
- **Missing CI/CD security** — compromised build pipeline
### CWE Mappings
- CWE-345: Insufficient Verification of Data Authenticity
- CWE-353: Missing Support for Integrity Check
- CWE-426: Untrusted Search Path
- CWE-494: Download of Code Without Integrity Check
- CWE-502: Deserialization of Untrusted Data
- CWE-565: Reliance on Cookies without Validation and Integrity Checking
- CWE-784: Reliance on Cookies without Validation and Integrity Checking in a Security Decision
- CWE-829: Inclusion of Functionality from Untrusted Control Sphere
### Vulnerability Pattern
**Insecure Deserialization**:
```typescript
// VULNERABLE — deserialize untrusted data
const userData = JSON.parse(req.cookies.user);
const obj = deserialize(req.body.data); // Arbitrary code execution!
```
**Remediation**:
```typescript
// SECURE — validate structure
import { z } from 'zod';
const userSchema = z.object({
id: z.string().uuid(),
role: z.enum(['user', 'admin']),
});
const result = userSchema.safeParse(JSON.parse(req.cookies.user));
if (!result.success) {
throw new Error('Invalid user data');
}
```
---
## A09:2021 – Security Logging and Monitoring Failures
### Common Weaknesses
- **Missing audit logs** — no record of critical operations
- **Insufficient log detail** — can't reconstruct attack
- **No monitoring** — logs not reviewed
- **Insecure log storage** — logs tamper-able
### CWE Mappings
- CWE-117: Improper Output Neutralization for Logs
- CWE-223: Omission of Security-relevant Information
- CWE-532: Insertion of Sensitive Information into Log File
- CWE-778: Insufficient Logging
### Remediation
```typescript
// Log security events
logger.info('User login', {
userId: user.id,
ip: req.ip,
userAgent: req.headers['user-agent'],
timestamp: new Date().toISOString(),
});
logger.warn('Failed login attempt', {
email: req.body.email, // Don't log password!
ip: req.ip,
attempts: failedAttempts,
});
logger.error('Unauthorized access attempt', {
userId: req.user.id,
resource: req.path,
method: req.method,
ip: req.ip,
});
// NEVER log sensitive data
logger.info('User data', {
email: user.email,
password: '[REDACTED]',
ssn: '[REDACTED]',
creditCard: '[REDACTED]',
});
```
---
## A10:2021 – Server-Side Request Forgery (SSRF)
### Common Weaknesses
- **Unvalidated URLs** — fetching arbitrary URLs
- **Cloud metadata access** — accessing AWS/GCP metadata endpoints
- **Internal network scanning** — probing internal services
### CWE Mappings
- CWE-918: Server-Side Request Forgery (SSRF)
### Vulnerability Pattern
```typescript
// VULNERABLE — fetch arbitrary URL
app.get('/api/fetch', async (req, res) => {
const url = req.query.url;
const response = await fetch(url);
const data = await response.text();
res.send(data);
});
// ATTACK — access cloud metadata
?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/
// ATTACK — scan internal network
?url=http://localhost:6379/ // Redis
?url=http://10.0.0.5:22/ // SSH
```
**Remediation**:
```typescript
// SECURE — allowlist of domains
const ALLOWED_DOMAINS = ['api.example.com', 'cdn.example.com'];
app.get('/api/fetch', async (req, res) => {
const url = new URL(req.query.url);
// Validate domain
if (!ALLOWED_DOMAINS.includes(url.hostname)) {
return res.status(403).json({ error: 'Domain not allowed' });
}
// Block private IPs
const ip = await dns.resolve4(url.hostname);
if (isPrivateIP(ip[0])) {
return res.status(403).json({ error: 'Private IP not allowed' });
}
const response = await fetch(url.href);
const data = await response.text();
res.send(data);
});
function isPrivateIP(ip: string): boolean {
return /^(10\.|172\.(1[6-9]|2[0-9]|3[01])\.|192\.168\.|127\.)/.test(ip)
|| ip === '::1'
|| ip.startsWith('169.254.'); // Cloud metadata
}
```
---
## Quick Reference Table
| Category | Key CWEs | Top Mitigations |
|----------|----------|-----------------|
| A01 Broken Access Control | 200, 352, 639, 918 | Server-side checks, ownership validation, CSRF tokens |
| A02 Cryptographic Failures | 259, 327, 331 | TLS, bcrypt, no hardcoded secrets, crypto.randomBytes |
| A03 Injection | 20, 79, 89 | Parameterized queries, input validation, output encoding |
| A04 Insecure Design | 209, 256, 434 | Threat modeling, rate limiting, defense in depth |
| A05 Security Misconfiguration | 16, 611, 614 | Security headers, disable debug, defaults changed |
| A06 Vulnerable Components | 1035, 1104 | npm audit, Dependabot, regular updates |
| A07 Authentication Failures | 287, 307, 521, 798 | Strong passwords, MFA, rate limiting, no defaults |
| A08 Integrity Failures | 502, 494 | Verify signatures, CI/CD hardening, schema validation |
| A09 Logging Failures | 117, 532, 778 | Audit logs, monitoring, redact sensitive data |
| A10 SSRF | 918 | URL allowlist, block private IPs, validate domains |