Skip to main content

OWASP Top 10 2024 Security Checklist

A developer-focused checklist covering the most critical web application security risks. Use this during code review, security audits, and pre-launch hardening.

✓ All 10 OWASP categories ✓ Code examples & fixes ✓ Printable checklist ✓ 2024 updated guidance

The OWASP Top 10 — Quick Reference Table

# Category Risk Level Key Fix
A01Broken Access ControlCriticalEnforce authz server-side on every request
A02Cryptographic FailuresCriticalUse Argon2id for passwords, AES-GCM for data
A03Injection (SQL, NoSQL, OS)CriticalParameterized queries, input validation
A04Insecure DesignHighThreat modeling, secure design patterns
A05Security MisconfigurationHighHarden defaults, disable unused features
A06Vulnerable ComponentsHighSCA tools, automated dependency updates
A07Auth & Session FailuresHighMFA, secure session management
A08Software & Data IntegrityMediumVerify signatures, pin dependencies
A09Logging & Monitoring FailuresMediumCentralized logs, alerting on anomalies
A10SSRFMediumAllowlist outbound URLs, block internal ranges

A03 — Injection Prevention

Injection attacks occur when untrusted data is sent to an interpreter as part of a command or query. SQL injection remains the most exploited vulnerability across all languages and frameworks.

Vulnerable SQL (Never do this)

// ❌ VULNERABLE — direct string interpolation
const query = `SELECT * FROM users WHERE email = '{req.body.email}'`;
// Attacker input: ' OR '1'='1
// Resulting query: SELECT * FROM users WHERE email = '' OR '1'='1'
// Returns ALL users!

Safe Parameterized Query (Node.js / pg)

// ✅ SAFE — parameterized query
const result = await pool.query(
  'SELECT * FROM users WHERE email = $1',
  [req.body.email]  // value is never interpolated into SQL
);

// ✅ SAFE — with an ORM (Prisma)
const user = await prisma.user.findFirst({
  where: { email: req.body.email }
});

Python SQLAlchemy (Safe)

from sqlalchemy import text

# ✅ SAFE — bound parameters
result = db.execute(
    text("SELECT * FROM users WHERE email = :email"),
    {"email": email_input}
)

# ❌ VULNERABLE — f-string in query
result = db.execute(f"SELECT * FROM users WHERE email = '{email_input}'")

A03 — XSS Prevention

Cross-Site Scripting (XSS) lets attackers inject client-side scripts into pages viewed by other users. Reflected XSS comes from request data; stored XSS persists in the database; DOM-based XSS manipulates client-side code.

Content Security Policy Header

# Nginx — strong CSP header
add_header Content-Security-Policy
  "default-src 'self';
   script-src 'self' 'nonce-{NONCE}';
   style-src 'self' 'unsafe-inline';
   img-src 'self' data: https:;
   font-src 'self';
   connect-src 'self' https://api.yourapp.com;
   frame-ancestors 'none';"
  always;

Sanitize HTML before rendering (DOMPurify)

import DOMPurify from 'dompurify';

// ❌ XSS risk — never do this with user content
element.innerHTML = userContent;

// ✅ SAFE — sanitize first
const clean = DOMPurify.sanitize(userContent, {
  ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a'],
  ALLOWED_ATTR: ['href']
});
element.innerHTML = clean;

A05 — Security Misconfiguration: CORS

CORS misconfiguration is one of the most common real-world vulnerabilities. A wildcard Access-Control-Allow-Origin: * combined with Access-Control-Allow-Credentials: true is a critical vulnerability that allows any origin to make credentialed requests.

Misconfigured CORS (Dangerous)

// ❌ DANGEROUS — wildcard with credentials
app.use(cors({
  origin: '*',
  credentials: true  // This combination is a critical vuln!
}));

// ❌ DANGEROUS — reflecting Origin header without validation
app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', req.headers.origin);
  res.header('Access-Control-Allow-Credentials', 'true');
  next();
});

Correct CORS Configuration (Express)

// ✅ SAFE — explicit allowlist
const ALLOWED_ORIGINS = [
  'https://app.yourcompany.com',
  'https://admin.yourcompany.com',
];

app.use(cors({
  origin: (origin, callback) => {
    if (!origin || ALLOWED_ORIGINS.includes(origin)) {
      callback(null, true);
    } else {
      callback(new Error('Not allowed by CORS'));
    }
  },
  credentials: true,
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization'],
}));

A01 — Broken Access Control (IDOR)

Access control enforces that users can only act within their intended permissions. IDOR (Insecure Direct Object Reference) is the most common access control failure found in bug bounty programs.

// ❌ VULNERABLE — no authorization check
app.get('/api/invoices/:id', async (req, res) => {
  const invoice = await db.invoices.findById(req.params.id);
  res.json(invoice);  // Any authenticated user can read any invoice!
});

// ✅ SAFE — verify ownership
app.get('/api/invoices/:id', authenticate, async (req, res) => {
  const invoice = await db.invoices.findOne({
    id: req.params.id,
    userId: req.user.id  // Must belong to requesting user
  });
  if (!invoice) return res.status(404).json({ error: 'Not found' });
  res.json(invoice);
});

Security Headers Checklist

Header Recommended Value Protects Against
Strict-Transport-Securitymax-age=63072000; includeSubDomains; preloadSSL stripping, MITM
X-Frame-OptionsDENYClickjacking
X-Content-Type-OptionsnosniffMIME sniffing attacks
Referrer-Policystrict-origin-when-cross-originData leakage in Referer
Permissions-Policycamera=(), microphone=(), geolocation=()Feature abuse
Content-Security-Policydefault-src 'self'; ...XSS, data injection

Frequently Asked Questions

What is the OWASP Top 10?▼

The OWASP Top 10 is a standard awareness document representing the most critical security risks to web applications. Published by the Open Web Application Security Project, it is updated periodically (most recently for 2021, with 2024 updates) based on data from hundreds of organizations and thousands of applications. It serves as a baseline checklist for secure development practices.

What is the difference between SQL injection and NoSQL injection?▼

SQL injection targets relational databases by inserting malicious SQL syntax into queries. NoSQL injection targets document databases like MongoDB by exploiting JSON/BSON query operators — for example, passing {'$gt': ''} as a password to bypass authentication. Both require parameterized queries or input sanitization. In MongoDB, always use parameterized queries and validate that inputs are the expected type (string, not object).

How do I prevent XSS in a React or Vue application?▼

React and Vue escape output by default when using JSX / template syntax. XSS risks occur when using dangerouslySetInnerHTML (React) or v-html (Vue) — avoid these with untrusted content. Use a library like DOMPurify to sanitize HTML before rendering. For backend-rendered HTML, use context-aware output encoding: HTML-encode for HTML context, JavaScript-encode for JS context, URL-encode for URL params.

What is an IDOR vulnerability and how do I prevent it?▼

Insecure Direct Object Reference (IDOR) occurs when an application exposes internal identifiers (database IDs, filenames) directly and doesn't verify the requesting user is authorized to access that resource. Prevention: always perform authorization checks server-side before returning any object — never rely on the client to enforce access control. Use indirect references (UUIDs instead of sequential integers) and log access attempts.

What is security misconfiguration and what are common examples?▼

Security misconfiguration is the most common OWASP category. Examples include: running services with default credentials, leaving debug mode enabled in production, exposing stack traces in error messages, unnecessary open ports or services, missing security headers (CSP, HSTS, X-Frame-Options), public cloud storage buckets (S3), and overly permissive CORS policies. Remediation involves hardening guides, automated config scanning, and infrastructure-as-code reviews.

What are cryptographic failures and what algorithms should I use in 2024?▼

Cryptographic failures include using broken algorithms (MD5, SHA-1 for passwords, DES), transmitting sensitive data unencrypted, weak key sizes, or misusing cryptographic primitives. For passwords use bcrypt, Argon2id, or scrypt — never SHA-256 alone. For symmetric encryption use AES-256-GCM. For hashing use SHA-256 or SHA-3. For key exchange use ECDH with P-256 or X25519. Always use TLS 1.2+ for data in transit.

Share this tool: X / Twitter LinkedIn
✓ 60,000+ developers use DevPlaybook ★★★★★ 4.8 / 5 on Gumroad ✓ MIT licensed · Instant download ✓ No login required

Related Products

on Gumroad

You Might Also Need

More Free Tools

Enjoying this tool? Get more like it.

Weekly developer tool guides, productivity playbooks & AI tricks. Free. No spam.

DevPlaybook Pro 7 days free

Unlock AI-Powered Dev Tools

  • ⚡ AI Code Review, Doc Generator & SQL Builder
  • ⚡ All premium templates & early access
  • ⚡ Member discounts on Gumroad products
Start Free Trial →

$9/mo after trial · Cancel anytime

Want the full toolkit?

Get DevPlaybook Pro

Every template, guide, boilerplate, and automation script in one bundle. 13 premium products — grab them all at once and save big.

$79
$241 separately Save $162 (67% off)
Get DevPlaybook Pro — $79 →

MIT licensed · Instant download · No subscription

See what's included → Browse all deals →