The OWASP (Open Web Application Security Project) Top 10 is a consensus list of the most critical web application security risks. It gets updated periodically, but many items persist across years because the underlying mistakes remain common.
Here are the ones that matter most to understand as a developer building web applications.
Injection (SQL, Command, LDAP)
Injection attacks happen when untrusted data is sent to an interpreter as part of a command or query. SQL injection is the classic example:
# Vulnerable: string interpolation in queries
query = f"SELECT * FROM users WHERE email = '{user_input}'"
# Safe: parameterized queries
query = "SELECT * FROM users WHERE email = $1"
result = await conn.fetchrow(query, user_input)Parameterized queries are the complete fix. There is no reason to use string interpolation in database queries in 2026.
Broken Authentication
Common authentication failures:
- Weak password policies (allowing short or common passwords)
- No rate limiting on login attempts (allows credential stuffing)
- Session tokens that do not expire
- Passwords stored in plain text or with weak hashing (MD5, SHA1)
Use bcrypt, scrypt, or Argon2 for password hashing. Always.
import bcrypt
def hash_password(password: str) -> str:
return bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode()
def verify_password(plain: str, hashed: str) -> bool:
return bcrypt.checkpw(plain.encode(), hashed.encode())Cross-Site Scripting (XSS)
XSS occurs when user-supplied content is rendered as HTML without escaping. An attacker can inject scripts that run in other users' browsers.
Modern frontend frameworks (React, Vue, Angular) escape dynamic content by default — which is why XSS is less common in framework-built frontends. The danger comes when you deliberately bypass this:
// Dangerous — only do this with fully sanitized, trusted content
<div dangerouslySetInnerHTML={{ __html: userContent }} />If you need to render user-provided HTML, use a sanitizer like DOMPurify to strip dangerous elements before rendering.
Security Misconfiguration
The catch-all category: running with debug mode enabled in production, leaving default credentials unchanged, exposing stack traces to end users, overly permissive CORS settings, missing security headers.
A checklist for every production deployment:
- Debug/admin endpoints not publicly accessible