A web application threat is any way an attacker can compromise the confidentiality, integrity, or availability of a web app, and the vast majority fall into a small set of well-understood categories: injection, broken access control, authentication failures, and vulnerable dependencies. The good news is that because these threats are so consistent, the defenses are too. You don't need to anticipate every exotic exploit — you need to close the handful of doors that attackers actually walk through. This guide maps the main web application threat categories to concrete, buildable defenses, framed for people who ship code rather than write threat reports.
Injection: still the classic web application threat
Injection happens when untrusted input is interpreted as a command or query. SQL injection is the archetype — a login form that concatenates user input into a query, letting an attacker turn ' OR '1'='1 into an authentication bypass — but the same threat class covers command injection, LDAP injection, and template injection.
The defense is uniform: never build an interpreted string from raw input. For databases, use parameterized queries so the input can only ever be data, never structure:
# Vulnerable
cursor.execute(f"SELECT * FROM users WHERE email = '{email}'")
# Safe
cursor.execute("SELECT * FROM users WHERE email = %s", (email,))
The safe version tells the database engine "this is a value," and no amount of quote-juggling in the input can escape that boundary. The same principle applies everywhere: parameterize, escape for the specific interpreter, and validate input against an allowlist of what you expect. We're describing the attack conceptually here — the point is detection and prevention, not building a working exploit.
Broken access control
Broken access control is consistently the most prevalent web application threat in real-world testing. It's the failure to enforce what an authenticated user is allowed to do. The classic form is the insecure direct object reference: a URL like /api/invoices/1043 where changing 1043 to 1044 returns someone else's invoice because the server checks that you're logged in but never that the record is yours.
Defense requires an authorization check on every request, tied to the specific resource:
invoice = db.get_invoice(invoice_id)
if invoice.owner_id != current_user.id:
abort(403)
Enforce authorization server-side, deny by default, and never rely on hiding a button in the UI — the API endpoint behind it is directly reachable. Function-level checks matter too: an admin-only endpoint must verify the caller's role, not assume that only admins know the URL.
Authentication and session threats
Weak authentication opens the front door. Credential-stuffing attacks replay passwords leaked from other breaches against your login form, which is why rate limiting, breached-password checks, and multi-factor authentication are baseline defenses rather than nice-to-haves. Store passwords with a purpose-built hash — Argon2, bcrypt, or scrypt — never a plain SHA-256, which is far too fast to resist offline cracking.
Session handling is the other half. Session fixation lets an attacker set a victim's session ID before login; defend by regenerating the session identifier on authentication. Session hijacking via stolen cookies is blunted by setting HttpOnly (scripts can't read the cookie) and Secure (it only travels over HTTPS) flags, and by scoping the SameSite attribute to limit cross-site sending. Short session lifetimes and server-side revocation close the window when a token does leak.
Cross-site scripting and CSRF
Cross-site scripting (XSS) is a web application threat where an attacker gets their script to run in another user's browser, typically to steal session tokens or perform actions as the victim. The root cause is rendering untrusted input into a page without encoding it. The defense is contextual output encoding — HTML-encode when writing into markup, JavaScript-encode when writing into a script context — plus a Content Security Policy that restricts which scripts the browser will execute at all. Modern frameworks like React escape by default, which eliminates most XSS as long as you don't reach for dangerouslySetInnerHTML.
Cross-site request forgery (CSRF) tricks a logged-in user's browser into submitting a state-changing request they didn't intend. Anti-CSRF tokens — a per-session secret the server verifies on every mutating request — combined with the SameSite cookie attribute defeat it. The Axios credential-leak issue in CVE-2023-45857 is a real example of how a leaked CSRF token undermines this defense, which is why protecting the token itself matters.
The supply-chain threat you don't write
The fastest-growing web application threat isn't in your code at all — it's in your dependencies. A modern web app pulls in hundreds of open-source packages, and any one of them can carry a known CVE or, worse, be compromised at the source. The 2021 Log4Shell flaw and the recurring npm package hijacks show that a single poisoned dependency can hand an attacker remote code execution across every app that uses it.
You cannot review hundreds of transitive dependencies by hand. Software composition analysis maps your full dependency tree against vulnerability databases and flags the risky ones; a tool such as Safeguard can catch a vulnerable package that arrived several layers deep through something you added for an unrelated reason. Our SCA overview explains the mechanics, and for the runtime side, DAST probes your deployed app the way an external attacker would — the two together cover both the code you import and the app you expose.
Denial of service and business-logic abuse
Not every web application threat aims to steal data. Denial-of-service attacks aim to make your app unavailable, whether through raw traffic volume or through algorithmic complexity — a single crafted request that forces expensive computation. Rate limiting, request-size caps, timeouts on every external call, and input bounds (reject the 10-million-item array before you iterate it) are the practical defenses.
Business-logic abuse is subtler and specific to your app: coupon-stacking, race conditions in a checkout flow, or abusing a password-reset endpoint as an enumeration oracle. Automated scanners rarely catch these because they're not generic flaws. This is where threat modeling — sitting down and asking "how would someone abuse this feature?" — earns its keep, and where periodic human-led testing complements automated tooling.
FAQ
What is the most common web application threat?
Broken access control consistently ranks as the most prevalent in real-world assessments, including recent OWASP Top 10 data. It's the failure to enforce what an authenticated user is permitted to access, and it shows up most often as insecure direct object references where changing an ID in a request exposes another user's data.
How do I defend against injection attacks?
Never construct interpreted commands or queries by concatenating untrusted input. Use parameterized queries for databases, contextual escaping for other interpreters, and validate input against an allowlist. Parameterization moves user input into a data-only position where it can't alter the command's structure.
Are my dependencies a web application threat?
Yes, and increasingly the dominant one. Open-source dependencies can carry known CVEs or be compromised at the source, and a single flaw can affect every app that uses the package. Software composition analysis is the standard defense for finding vulnerable dependencies, including transitive ones you never chose directly.
Does using a modern framework eliminate web application threats?
It removes many by default — React escapes output to prevent most XSS, and ORMs parameterize queries to prevent SQL injection — but it doesn't cover access control, business-logic abuse, authentication design, or vulnerable dependencies. Frameworks raise the floor; they don't replace deliberate security work.