- What Is the OWASP Top 10?
- A01 — Broken Access Control
- A02 — Cryptographic Failures
- A03 — Injection
- A04 — Insecure Design
- A05 — Security Misconfiguration
- A06 — Vulnerable Components
- A07 — Authentication Failures
- A08 — Software & Data Integrity Failures
- A09 — Logging & Monitoring Failures
- A10 — Server-Side Request Forgery (SSRF)
- FAQ
The OWASP Top 10 is the definitive reference for web application security risks. Published by the Open Web Application Security Project, it's based on data from hundreds of organizations and over 500,000 real-world vulnerabilities. Understanding and mitigating these risks is essential for any website or API.
This guide explains each vulnerability with real-world examples, detection methods, and copy-paste fix commands.
What Is the OWASP Top 10?
The current OWASP Top 10 (2021) represents a significant shift from the 2017 version:
- Broken Access Control moved from #5 to #1 — the most common vulnerability
- Cryptographic Failures (formerly "Sensitive Data Exposure") moved to #2
- Injection dropped from #1 to #3 — still critical but better understood
- Three new categories: Insecure Design, Software Integrity Failures, SSRF
A01 — Broken Access Control CRITICAL
94% of applications tested had some form of broken access control. This occurs when users can act outside their intended permissions.
Common Examples
- Changing
/api/users/123to/api/users/456to access another user's data (IDOR) - Accessing admin pages without admin privileges
- Modifying JWT tokens to escalate roles
- CORS misconfiguration allowing unauthorized cross-origin access
Fix
// Always verify ownership in every request
app.get('/api/orders/:id', auth, async (req, res) => {
const order = await Order.findOne({
_id: req.params.id,
userId: req.user.id // Ownership check
});
if (!order) return res.status(404).json({ error: 'Not found' });
res.json(order);
});
// Deny by default — explicitly grant access
// Use role-based middleware
function requireRole(...roles) {
return (req, res, next) => {
if (!roles.includes(req.user.role)) {
return res.status(403).json({ error: 'Forbidden' });
}
next();
};
}
app.delete('/api/users/:id', auth, requireRole('admin'), deleteUser);
Related guide: API Security Best Practices
A02 — Cryptographic Failures CRITICAL
Failures related to cryptography that lead to exposure of sensitive data: passwords stored in plaintext, weak encryption, missing HTTPS, exposed API keys.
Fix
# Enforce HTTPS everywhere
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
# Hash passwords with bcrypt (never MD5/SHA1)
const bcrypt = require('bcrypt');
const hash = await bcrypt.hash(password, 12); // 12 rounds
# Encrypt sensitive data at rest with AES-256
# Never store credit card numbers — use Stripe/PayPal tokenization
# Classify data and apply appropriate protection levels
Related guide: SSL/TLS Certificate Fix Guide
A03 — Injection CRITICAL
SQL injection, NoSQL injection, OS command injection, LDAP injection. User-supplied data is sent to an interpreter as part of a command or query.
Fix
// Use parameterized queries — ALWAYS
const [rows] = await db.execute(
'SELECT * FROM users WHERE email = ?',
[email]
);
// Use ORMs that auto-parameterize
const user = await User.findOne({ where: { email } });
// Validate and sanitize all input
const schema = Joi.object({
email: Joi.string().email().required(),
name: Joi.string().alphanum().max(50).required()
});
Related guide: How to Prevent SQL Injection
A04 — Insecure Design HIGH
A new category focusing on design flaws rather than implementation bugs. No amount of perfect code can fix a fundamentally insecure design.
Examples
- Password recovery that asks "What is your mother's maiden name?" (guessable)
- No rate limiting on gift card redemption (allows brute-force)
- Ticket booking system that doesn't prevent bots from buying all tickets
Fix
Use threat modeling during design phase. Apply security design patterns: defense in depth, least privilege, fail-safe defaults. Implement business logic rate limiting and abuse detection.
A05 — Security Misconfiguration HIGH
90% of applications had some form of misconfiguration. This includes missing security headers, default credentials, verbose error messages, unnecessary features enabled, and cloud storage misconfigurations.
Fix
# Essential security headers
Header always set Content-Security-Policy "default-src 'self'"
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "camera=(), microphone=()"
# Disable directory listing
Options -Indexes
# Remove server version info
ServerTokens Prod
ServerSignature Off
Header always unset X-Powered-By
# Disable unnecessary HTTP methods
<LimitExcept GET POST HEAD>
Deny from all
</LimitExcept>
Related guide: Security Headers Guide
A06 — Vulnerable and Outdated Components HIGH
Using libraries, frameworks, or software with known vulnerabilities. This includes outdated WordPress plugins, npm packages with CVEs, and unpatched server software.
Fix
# Check for vulnerable npm packages
npm audit
npm audit fix
# Check for vulnerable Python packages
pip-audit
safety check
# Check for vulnerable PHP packages
composer audit
# WordPress — Check plugin vulnerabilities
wp plugin list --fields=name,version,update_version
# Automate dependency updates
# Use Dependabot, Renovate, or Snyk for automated PRs
Related guide: WordPress Security Checklist
A07 — Identification and Authentication Failures HIGH
Weak passwords, missing MFA, session fixation, credential stuffing. Previously "Broken Authentication" at #2.
Fix
# Implement MFA for all admin accounts
# Use bcrypt with 12+ rounds for password hashing
# Enforce minimum 12-character passwords
# Implement account lockout after failed attempts
# Use secure session management
# Session security
session_set_cookie_params([
'httponly' => true,
'secure' => true,
'samesite' => 'Strict',
'lifetime' => 900 // 15 minute timeout
]);
# Regenerate session ID after login
session_regenerate_id(true);
A08 — Software and Data Integrity Failures MEDIUM
A new category covering insecure CI/CD pipelines, auto-updates without integrity verification, and deserialization vulnerabilities.
Fix
# Verify package integrity with checksums
# Use lock files (package-lock.json, composer.lock)
# Sign commits and verify signatures
# Use Subresource Integrity (SRI) for CDN resources
<script src="https://cdn.example.com/lib.js"
integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
crossorigin="anonymous"></script>
A09 — Security Logging and Monitoring Failures MEDIUM
Without adequate logging and monitoring, breaches go undetected. The average time to detect a breach is 197 days.
Fix
# Log these events:
# - All authentication attempts (success and failure)
# - All access control failures (403s)
# - All input validation failures
# - All admin actions
# - All data access to sensitive records
# Centralize logs with ELK Stack, Datadog, or CloudWatch
# Set up alerts for:
# - Multiple failed logins from same IP
# - Access control failures spike
# - Unusual data access patterns
# - New admin accounts created
A10 — Server-Side Request Forgery (SSRF) HIGH
A new entry. SSRF occurs when an application fetches a remote resource based on user-supplied input without validating the destination URL. Attackers can use this to access internal services, cloud metadata endpoints, and internal networks.
Fix
// Validate and sanitize URLs before fetching
const url = require('url');
function isAllowedUrl(inputUrl) {
const parsed = url.parse(inputUrl);
// Block internal/private IPs
const blockedHosts = ['localhost', '127.0.0.1', '0.0.0.0', '169.254.169.254'];
if (blockedHosts.includes(parsed.hostname)) return false;
// Block private IP ranges
const ip = parsed.hostname;
if (ip.startsWith('10.') || ip.startsWith('192.168.') ||
ip.startsWith('172.16.') || ip.startsWith('172.17.')) return false;
// Only allow HTTPS
if (parsed.protocol !== 'https:') return false;
// Whitelist allowed domains if possible
const allowedDomains = ['api.example.com', 'cdn.example.com'];
if (!allowedDomains.includes(parsed.hostname)) return false;
return true;
}
// AWS — Block metadata endpoint
# iptables -A OUTPUT -d 169.254.169.254 -j DROP
# Or use IMDSv2 which requires a token
Deep-dive guides for each OWASP category
- A01 Broken Access Control: Review the website security checklist for access control checks
- A02 Cryptographic Failures: SSL/TLS fix guide — disable weak ciphers and enforce TLS 1.2+
- A03 Injection (SQLi): How to prevent SQL injection and SQL injection testing checklist
- A05 Security Misconfiguration: Security headers guide and exposed .env file fix guide
- A07 Authentication Failures: WordPress auth hardening and pre-launch auth checklist
- XSS (A03/client): How to prevent XSS and XSS explained
- CORS misconfigurations: CORS misconfiguration fix guide
Check Your OWASP Compliance
Free compliance scan — maps findings to OWASP Top 10, PCI DSS, ISO 27001, and SOC 2.
Run Compliance ScanFrequently Asked Questions
What is the OWASP Top 10?
The OWASP Top 10 is a standard awareness document for web application security, representing the most critical risks based on data from hundreds of organizations.
What is the #1 OWASP vulnerability?
A01:2021 Broken Access Control — found in 94% of applications tested. It occurs when users can act outside their intended permissions.
How do I check my website against the OWASP Top 10?
Use AI QA Monkey's free compliance scanner which maps findings to OWASP Top 10 categories, plus PCI DSS, ISO 27001, and SOC 2.