← Back to Networking

OWASP Top 10 Vulnerabilities: Complete Guide with Examples

The OWASP Top 10 is a regularly updated list of the most critical security risks facing web applications. These vulnerabilities account for the majority of real-world exploits and data breaches. Understanding each one—and how to prevent it—is essential for every developer and security professional.

What Is OWASP and Why Should You Care?

The Open Worldwide Application Security Project (OWASP) is a nonprofit foundation dedicated to improving software security. Every three years, they release the Top 10 list based on data from thousands of organizations, penetration tests, and vulnerability disclosures. The 2021 list reorganized priorities based on attack frequency and impact.

Why does this matter? Because these vulnerabilities are actively exploited by attackers right now. They're not theoretical—they're present in production systems and have caused billions in damages. By learning them, you're learning what attackers actively target.

1. Broken Access Control

Broken access control occurs when users can act outside their intended permissions. This is the #1 vulnerability in the 2021 OWASP Top 10, appearing in 94% of tested applications.

Real-world example: A user logs into their bank account and changes the URL from /account/profile?user_id=123 to /account/profile?user_id=124—and sees someone else's financial data. The application didn't verify that the logged-in user had permission to view that specific account.

Prevention: Always implement server-side authorization checks. Never trust client-side validation or user input.

// VULNERABLE CODE
app.get('/api/user/:id/details', (req, res) => {
  const user = User.findById(req.params.id);
  res.json(user);
});

// SECURE CODE
app.get('/api/user/:id/details', (req, res) => {
  if (req.user.id !== req.params.id) {
    return res.status(403).json({ error: 'Unauthorized' });
  }
  const user = User.findById(req.params.id);
  res.json(user);
});

2. Cryptographic Failures

This replaces the old "Sensitive Data Exposure" category. It encompasses failures to protect data in transit and at rest—including weak encryption, missing encryption, and poor key management.

Example: An application transmits passwords over HTTP instead of HTTPS. An attacker on the same network can intercept credentials in plaintext using tools like Wireshark.

Another example: Database passwords are stored with MD5 hashing. MD5 collisions are trivial to generate, and rainbow tables contain trillions of pre-computed hashes.

Prevention: Use HTTPS/TLS for all data in transit. For data at rest, use bcrypt, Argon2, or scrypt for passwords. Use AES-256 for sensitive data encryption. Rotate encryption keys regularly.

// VULNERABLE - MD5 hashing
const hashedPassword = md5(userPassword);

// SECURE - bcrypt with salt rounds
const bcrypt = require('bcrypt');
const hashedPassword = await bcrypt.hash(userPassword, 12);

3. Injection

Injection flaws occur when untrusted data is sent to an interpreter as part of a command or query. SQL injection, OS command injection, and LDAP injection all fall here.

SQL Injection example: A login form concatenates user input directly into a SQL query:

// VULNERABLE CODE
const username = req.body.username;
const password = req.body.password;
const query = `SELECT * FROM users WHERE username='${username}' AND password='${password}'`;
db.query(query, (err, results) => { ... });

An attacker enters username: admin' OR '1'='1 and bypasses authentication entirely. The query becomes:

SELECT * FROM users WHERE username='admin' OR '1'='1' AND password='...'

Prevention: Always use parameterized queries (prepared statements):

// SECURE CODE
const query = 'SELECT * FROM users WHERE username=? AND password=?';
db.query(query, [username, password], (err, results) => { ... });

4. Insecure Design

This is a new category in the 2021 list focusing on design and architectural flaws. It's about missing security controls before coding begins—threat modeling failures, missing security requirements, and incomplete security architectures.

Example: An application has no rate limiting on login attempts. An attacker performs a brute-force attack, trying thousands of passwords per second until gaining access.

Another example: A password reset feature doesn't verify email ownership properly. An attacker can reset any user's password by guessing their username.

Prevention: Include security in the design phase. Create threat models, define security requirements upfront, and implement controls like rate limiting, account lockouts, and proper multi-factor authentication.

5. Security Misconfiguration

Security misconfiguration includes default credentials, unnecessary features enabled, unpatched systems, missing security headers, and exposed debug information.

Common examples:

Prevention: Use infrastructure-as-code and automated security scanning. Apply principle of least privilege—disable unnecessary services. Keep all software patched. Implement security headers:

app.use((req, res, next) => {
  res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
  res.setHeader('X-Content-Type-Options', 'nosniff');
  res.setHeader('X-Frame-Options', 'DENY');
  res.setHeader('Content-Security-Policy', "default-src 'self'");
  next();
});

6. Vulnerable and Outdated Components

Using libraries and frameworks with known vulnerabilities is incredibly common. Many development teams don't track dependency versions or patch them regularly.

Real incident: The Equifax breach in 2017 affected 147 million people. The root cause? An unpatched Apache Struts vulnerability that had been public for months. The patch was available, but Equifax didn't apply it.

Prevention: Maintain a software bill of materials (SBOM). Use tools like OWASP Dependency-Check, Snyk, or npm audit to identify vulnerable dependencies. Automate patching where possible. Regularly update frameworks and libraries.

// Check Node.js dependencies
npm audit

// Fix automatically
npm audit fix

// For JavaScript, use Snyk
snyk test

7. Identification and Authentication Failures

These failures allow attackers to compromise user accounts through weak credentials, session management flaws, or lack of multi-factor authentication.

Examples:

Prevention: Implement strong password policies and require MFA. Use secure session management with short expiration times. Hash passwords with bcrypt or Argon2. Implement rate limiting on login endpoints to prevent brute force attacks.

8. Software and Data Integrity Failures

This vulnerability covers insecure CI/CD pipelines, unsigned updates, and unverified data deserialization.

Example: An application auto-updates itself without verifying the digital signature of the update. An attacker performs a man-in-the-middle attack and injects malware into the update. All users running the application download and execute the malicious code.

Prevention: Digitally sign all software releases. Verify signatures before installation. Use secure deserialization practices—never deserialize untrusted data. Implement secure CI/CD pipelines with artifact signing.

9. Logging and Monitoring Failures

Many breaches go undetected for months because organizations don't log security events or monitor them. Without visibility, you can't detect attacks in progress.

Industry data: The average dwell time for attackers in a network is 207 days—mostly undetected. Better logging and monitoring could reduce this dramatically.

Gaps include:

Prevention: Log all authentication attempts, authorization failures, and access to sensitive data. Use centralized logging (ELK stack, Splunk, CloudWatch). Set up alerts for suspicious patterns. Protect logs from tampering with write-once storage.

10. Server-Side Request Forgery (SSRF)

SSRF occurs when an application fetches remote resources without validating user-supplied URLs. An attacker can trick the server into making requests to internal systems it shouldn't access.

Example: A document preview feature accepts a URL:

// VULNERABLE CODE
app.post('/preview', (req, res) => {
  const url = req.body.documentUrl;
  fetch(url).then(response => response.text())
    .then(text => res.json({ preview: text }));
});

An attacker submits http://localhost:8080/admin or http://169.254.169.254/latest/meta-data/iam/security-credentials/ (AWS metadata endpoint). The server makes requests to internal systems and returns sensitive data.

Prevention: Validate and whitelist URLs. Block access to private IP ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, localhost). Use a URL allowlist instead of a blocklist.

// SECURE CODE
const ALLOWED_DOMAINS = ['trusted.com', 'cdn.example.com'];
app.post('/preview', (req, res) => {
  const url = new URL(req.body.documentUrl);
  if (!ALLOWED_DOMAINS.includes(url.hostname)) {
    return res.status(403).json({ error: 'Domain not allowed' });
  }
  fetch(url).then(response => response.text())
    .then(text => res.json({ preview: text }));
});

Other Critical Vulnerabilities Worth Knowing

Cross-Site Scripting (XSS): While not in the Top 10 separately anymore, XSS attacks—both reflected and stored—remain extremely common. Always escape user input when rendering HTML. Use Content Security Policy headers. See our complete XSS prevention guide.

Cross-Site Request Forgery (CSRF): CSRF tokens prevent