Skip to content

OWASP Top 10: Vulnerabilities, Exploits & Fixes

The web's most exploited vulnerability classes, shown as vulnerable code, exploit, and fix — plus the headers every app should ship.

OWASP Top 10Security HeadersBurp Suite
RR

Ranjith R

Linux SysAdmin & Cloud Engineer

Published April 2, 2026Updated June 15, 2026
9 min readAdvanced#OWASP#AppSec#Security#Web Security
Share
Section 01

Introduction

Application security is not a checklist you run once — it is a set of habits baked into how code gets written, reviewed, and deployed. The OWASP Top 10is the industry's reference list of the most common and most damaging web application vulnerability categories, maintained by the Open Web Application Security Project from real-world incident and bug-bounty data.

This guide is deliberately defensive: every vulnerability class is shown as a minimal, realistic vulnerable code sample next to its fixed counterpart, the way it would appear in a secure-coding training or a code review comment — never as a working exploit against a live target. The goal is that a developer or sysadmin can recognize these patterns in their own codebase and know exactly what to change.

Who this is for

  • Developers who want to review their own code for the most common security bugs.
  • Sysadmins responsible for the headers, TLS, and WAF layer in front of an app.
  • Anyone preparing for an AppSec-flavored interview or a secure-coding certification.
Section 02

Prerequisites

To get the most out of this guide, you should already have:

  • Basic familiarity with how HTTP requests/responses and cookies work.
  • Comfort reading SQL and at least one server-side language (PHP/JavaScript used in examples).
  • Access to a browser's developer tools (Network and Console tabs).
  • A local Nginx or Apache instance if you want to try the header configurations yourself.

Educational scope only

Every snippet below is a textbook-style illustration of a vulnerability class, not a usable exploit. None of it targets a specific product, and none of it should be run against a system you do not own or have written authorization to test.
Section 03

Theory

What the OWASP Top 10 actually is

The OWASP Top 10 is a periodically-updated ranking of the ten application security risk categories that show up most often and cause the most damage across real-world applications. It is not a law or a compliance standard by itself, but it underpins most compliance frameworks (PCI-DSS, SOC 2 application-security controls) and is the shared vocabulary security teams and developers use to talk about risk.

Risk rating: likelihood x impact

OWASP rates each category using a methodology that multiplies likelihood (how easy is this to discover and exploit, how common is the weakness) by impact (technical impact like data loss, and business impact like reputational or regulatory damage). A vulnerability that is trivial to find and gives full database read access ranks far higher than one that requires a rare configuration and leaks a low-sensitivity field.

FactorQuestions asked
LikelihoodHow discoverable is the flaw? How common is the pattern? Is exploitation automatable?
ImpactWhat data or systems are exposed? Confidentiality, integrity, availability?
PrevalenceHow often does this weakness appear across scanned/tested applications?
DetectabilityWould existing logging/monitoring catch exploitation attempts?

Defense in depth

No single control fully closes any of these categories. A parameterized query stops SQL injection at the data-access layer, but a WAF rule, least-privilege database account, and query-timeout limit each reduce the blast radius if that first layer is ever bypassed by a bug. Treat every mitigation in this guide as one layer in a stack, not a silver bullet.

Section 04

Architecture

The diagram below traces a single request through a typical web stack, annotating where each Top 10 category is realistically exploited along that path:

Browser → WAF → App → Authorization → Database, with the vulnerability class exploitable at each hop

The WAF is a layer, not the fix

A Web Application Firewall can block known injection and XSS payload signatures at the edge, but it cannot fix broken access-control logic or an unsafe deserialization call inside your application code — those require the fix at the source.

The Top 10 categories at a glance

CategoryWhat it means
Broken Access ControlUsers can act outside their intended permissions — viewing or modifying another user's data.
Cryptographic FailuresSensitive data exposed due to missing/weak encryption in transit or at rest.
InjectionUntrusted input alters the structure of a command — SQL, OS, LDAP, or template injection.
Insecure DesignA missing security control at the architecture stage, not a bug in an existing control.
Security MisconfigurationDefault credentials, verbose errors, open cloud storage, missing hardening.
Vulnerable & Outdated ComponentsUsing libraries/frameworks with known, unpatched CVEs.
Identification & Auth FailuresWeak session handling, credential stuffing, missing MFA.
Software & Data Integrity FailuresTrusting unsigned code, plugins, or CI/CD pipelines without integrity checks.
Security Logging & Monitoring FailuresAttacks go undetected because events aren't logged, alerted on, or retained.
Server-Side Request Forgery (SSRF)The server is tricked into making requests to unintended internal/external destinations.
Section 05

Installation

Before writing a line of application code, the web server itself should ship a secure-by-default baseline: TLS-only, no server version leakage, and the core security headers present on every response.

/etc/nginx/conf.d/security.conf
server_tokens off;

add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header Content-Security-Policy "default-src 'self'" always;

server {
    listen 443 ssl;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
}

Enable the config, then test

After enabling (a2enmod headers on Apache, reload on Nginx), verify the headers actually reach the client — see the Commands section — before assuming the baseline is live.
Section 06

Configuration

Security headers, in full

Each header closes a specific gap. Ship all of them together rather than picking one or two — they cover different attack surfaces.

HeaderPurpose
Content-Security-PolicyRestricts which script/style/image/frame sources the browser will load — the primary XSS mitigation at the browser layer.
Strict-Transport-SecurityForces the browser to only ever connect over HTTPS for this domain, even if a link uses http://.
X-Content-Type-Optionsnosniff stops the browser from guessing (MIME-sniffing) a different content type than declared.
X-Frame-OptionsDENY/SAMEORIGIN prevents the page being embedded in a hostile iframe (clickjacking).
Referrer-PolicyLimits how much of the URL is leaked to third parties via the Referer header.
Permissions-PolicyDisables browser features (camera, geolocation, USB) the app doesn't use.
/etc/nginx/conf.d/security.conf
# A CSP that allows self-hosted assets and a specific analytics origin,
# blocks inline scripts, and disallows framing entirely.
add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://analytics.example.com; style-src 'self' 'unsafe-inline'; img-src 'self' data:; frame-ancestors 'none'; object-src 'none'; base-uri 'self'" always;

add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Permissions-Policy "geolocation=(), camera=(), microphone=()" always;

CSP rollout: start in report-only mode

Ship Content-Security-Policy-Report-Only alongside a report-uri/report-to endpoint first, review violation reports for a few days, then switch to the enforcing header once the policy is confirmed not to break legitimate functionality.
Section 07

Commands

Inspecting headers

terminal
# Fetch only response headers
curl -I https://example.com

# Follow redirects and show headers at each hop
curl -IL https://example.com

# Show full request/response including TLS handshake details
curl -v https://example.com 2>&1 | less

# Check which TLS protocol versions are accepted
openssl s_client -connect example.com:443 -tls1_2
openssl s_client -connect example.com:443 -tls1_3

Automated header and TLS scanning

terminal
# Mozilla Observatory-style local header check via curl + grep
curl -sI https://example.com | grep -iE 'content-security-policy|strict-transport|x-frame|x-content-type'

# testssl.sh: comprehensive TLS/cipher/protocol audit
./testssl.sh https://example.com

# nmap script scan for common web misconfigurations
nmap --script http-headers,http-security-headers -p 443 example.com

Dependency and component scanning

Vulnerable and outdated components are found with tooling, not manual review: npm audit / pip-audit / composer audit for language-level dependencies, and a Software Composition Analysis tool in CI for continuous coverage.
Section 08

Examples

The four examples below are the classic, most-tested vulnerability classes. Each is shown as the vulnerable pattern first, then the fix — read them as a pair.

SQL Injection (Injection)

Untrusted input is concatenated directly into a SQL query string, letting an attacker change the query's logic instead of just supplying a value.

login.php
// User input is concatenated straight into the query string.
$username = $_POST['username'];
$password = $_POST['password'];

$query = "SELECT id, role FROM users WHERE username = '$username' AND password = '$password'";
$result = mysqli_query($conn, $query);

// Submitting username: admin' -- as the username bypasses the password
// check entirely, because everything after -- becomes a SQL comment.

Cross-Site Scripting / XSS (Injection)

XSS comes in three flavors: stored (the payload is saved server-side and served to other users, e.g. in a comment field), reflected (the payload comes back in the same response, e.g. echoed from a search query parameter), and DOM-based (client-side JavaScript writes untrusted data into the page without ever touching the server). All three are fixed the same way: encode output for the context it renders into, and use CSP as a second layer.

comments.js
// Reflected XSS: search term is written straight into the DOM.
const params = new URLSearchParams(window.location.search);
const term = params.get("q");
document.getElementById("results").innerHTML =
  "Showing results for: " + term;

// A URL like ?q=<img src=x onerror=alert(document.cookie)>
// executes arbitrary script in the victim's session.

Cross-Site Request Forgery / CSRF (Broken Access Control)

A logged-in user's browser is tricked into submitting a request to your app from a malicious page. Cookies are sent automatically by the browser, so without a separate proof of intent, the server cannot tell the request apart from a legitimate one.

transfer.php
<!-- No anti-CSRF token; only relies on the session cookie -->
<form action="/transfer" method="POST">
  <input type="text" name="amount" />
  <input type="text" name="to_account" />
  <button type="submit">Transfer</button>
</form>

<!-- A hostile page can auto-submit an identical form to
     /transfer while the victim is logged in, and the browser
     attaches their session cookie automatically. -->

Remote Code Execution / RCE (Injection & Insecure Design)

Passing untrusted input into eval, a shell command, or an unrestricted deserializer lets an attacker run arbitrary code on the server.

calc.js
// "Calculator" endpoint that evaluates user-supplied expressions.
app.post("/calculate", (req, res) => {
  const expression = req.body.expression;
  const result = eval(expression); // never do this
  res.json({ result });
});

// Input like: require('child_process').execSync('id')
// runs an arbitrary shell command on the server.
Section 10

Real World Example

Scenario: during a routine code review ahead of a release, a reviewer notices the login endpoint builds its SQL query with string concatenation instead of the ORM the rest of the codebase uses.

  1. Spot the pattern during review

    A diff adds WHERE username = '" + username + "'as a "quick fix" for a login bug, bypassing the ORM's query builder that every other endpoint uses.
  2. Confirm the risk, don't exploit production

    The reviewer reproduces the issue only in a local/staging environment with test data, confirming that a crafted username can alter the query's logic, and documents it as a blocking finding rather than merging it.
  3. Fix with a parameterized query

    The endpoint is rewritten to use the ORM's parameter binding (or a prepared statement), matching the rest of the codebase, and a unit test is added asserting that a single-quote in the username field is treated as data.
  4. Prevent recurrence

    A static-analysis rule (e.g. a linter or SAST check) is added to CI to flag raw string concatenation into query strings, and the finding is shared with the team as a short write-up rather than filed and forgotten.
Troubleshooting

Common Issues

Overly strict CSP breaks the app

A default-src 'self' policy will silently block third-party widgets, inline event handlers, and CDN-hosted scripts. Roll out changes in Content-Security-Policy-Report-Only mode first and review violation reports before enforcing.

SameSite=Strict breaks legitimate cross-site flows

Strict cookies won't be sent on a link arriving from an external site (e.g. an email link into an authenticated page), breaking that flow entirely. Lax is usually the right default for session cookies — it still blocks the classic CSRF pattern of a cross-site POST.

An ORM doesn't make you immune to injection

Most ORMs expose a raw-query escape hatch (.raw(), whereRaw()) for complex queries. Any developer who drops to raw SQL there and concatenates input reintroduces SQL injection — the ORM only protects the code paths that use its query builder.

Client-side validation is not server-side validation

Disabling the submit button or validating a field with JavaScript only stops honest users. An attacker can call the API directly with curl or a proxy tool — every constraint enforced in the browser must be re-checked on the server.

Security headers set in code get overridden by the proxy

If both the app framework and the reverse proxy set the same header (e.g. X-Frame-Options), the value that reaches the client is whichever one is applied last — verify with curl -I against the real edge, not just the app server directly.
Best Practices

Best Practices

  • Validate and encode at the boundary — validate input on entry, encode output for the exact context (HTML, attribute, URL, SQL) it lands in.
  • Prefer allow-lists over deny-lists for input validation; deny-lists are always missing the next bypass.
  • Never trust client-side checks for anything security-relevant — re-verify on the server.
  • Keep dependencies current and run automated vulnerability scanning in CI, not just at release time.
  • Fail closed: on an unexpected error, deny access rather than defaulting to allow.
  • Log security-relevant events (auth failures, access-control denials) with enough context to investigate later, without logging secrets.
Security

Security Hardening

  • WAF — filters known injection/XSS payload patterns at the edge before they reach application code.
  • Least-privilege database accounts — the application's DB user should not have DROP/ALTER or access to schemas it doesn't need.
  • Dependency scanning — automated SCA tooling in CI catches known-CVE libraries before they ship.
  • Secure headers — CSP, HSTS, X-Content-Type-Options, X-Frame-Options shipped on every response, not just the login page.
  • Secrets management — credentials and API keys in a vault or secrets manager, never committed to source control or baked into images.
  • Rate limiting and MFA — reduce the value of credential-stuffing and brute-force attempts against authentication endpoints.
Interview Questions

Interview Questions

SQL injection manipulates a database query by injecting input that alters its structure, and executes on the server against the database. XSS injects script that executes in another user's browser, in the context of your site's origin — the target is the victim's session/browser, not the database.
Cheat Sheet

Cheat Sheet

owasp-top10-cheatsheet.txt
OWASP Top 10 — category -> #1 mitigation
------------------------------------------------------------
Broken Access Control        -> Deny by default; check ownership on every request
Cryptographic Failures       -> TLS everywhere; hash passwords with bcrypt/argon2
Injection                    -> Parameterized queries / prepared statements
Insecure Design               -> Threat-model before building, not after shipping
Security Misconfiguration    -> Secure-by-default config; remove unused features
Vulnerable & Outdated Deps   -> Automated dependency/CVE scanning in CI
Auth Failures                 -> MFA + rate limiting + secure session cookies
Data Integrity Failures      -> Verify signatures on code/CI pipeline artifacts
Logging & Monitoring Failures -> Log auth + access-control events, alert on them
SSRF                          -> Allow-list outbound destinations; block private IPs

Headers to ship on every response:
  Content-Security-Policy, Strict-Transport-Security,
  X-Content-Type-Options: nosniff, X-Frame-Options: DENY,
  Referrer-Policy, Permissions-Policy
Summary

Summary

The OWASP Top 10 categories keep recurring for a simple reason: they map to a small number of trust mistakes — trusting input, trusting the client, trusting a session cookie alone, trusting a dependency, trusting a config default. Fixing each one comes down to the same handful of habits shown above: validate and encode at the boundary, parameterize anything that reaches a query or shell, verify identity and ownership on the server for every request, and ship a solid security-headers baseline everywhere. None of these controls is exotic — the skill is applying them consistently, and catching the raw-query or eval-on-user-input escape hatch before it ships.

Resources

Resources

  • OWASP Top 10 project and documentation — owasp.org
  • OWASP Cheat Sheet Series (per-vulnerability defensive guidance) — cheatsheetseries.owasp.org
  • Mozilla web security and header guidelines — developer.mozilla.org
  • PortSwigger Web Security Academy (free, hands-on labs) — portswigger.net
  • National Vulnerability Database (CVE lookup) — nvd.nist.gov