The most common ways web applications get broken, in plain language.
October 14, 2025
The Open Worldwide Application Security Project publishes a list of the most critical web application security risks, compiled from data across many organizations. It is free, it is the industry's default reference, and it appears in contracts and compliance requirements constantly.
It is a list of categories rather than specific bugs, which is why it stays useful across technologies.
The application checks who you are and then fails to check what you are allowed to do. It has sat at or near the top of the list for years because it is easy to introduce and hard to test automatically.
The classic version is an insecure direct object reference. You view your own invoice at a URL ending in id=1042, you change it to 1043, and you see someone else's. Nothing was hacked. The application simply never asked whether the invoice belonged to you.
The fix is to check authorization on every request, server side, against the authenticated user, and to deny by default. Hiding a button is not access control.
Sensitive data that is not protected properly: transmitted without encryption, stored in plain text, hashed with an algorithm designed for speed rather than for passwords, or encrypted with a key sitting in the same repository.
Passwords should be stored with a slow, salted algorithm designed for the purpose, such as bcrypt, scrypt, or Argon2. MD5 and SHA-1 are not password hashing algorithms, and SHA-256 on its own is not either.
Untrusted input reaches an interpreter and gets treated as instructions. SQL injection is the famous one, but the same shape applies to operating system commands, LDAP queries, and templates.
The fix for SQL injection has been known for over twenty years and is not input filtering. It is parameterized queries, which keep the query structure and the data on separate rails so a value can never become syntax.
Cross site scripting is injection into a page rather than a database. The fix is context aware output encoding plus a content security policy, not a blocklist of dangerous words.
A category for flaws that no amount of careful implementation fixes, because the design itself is wrong.
A password reset flow using security questions whose answers are on a public profile is implemented perfectly and still broken. A funds transfer with no verification step is not a coding error.
The remedy is threat modelling during design: asking what could go wrong here and who benefits, before anything is built.
Default credentials still active. Directory listing enabled. Verbose error messages returning stack traces to users. Administrative interfaces reachable from the internet. Cloud storage set to public. Unnecessary features enabled.
This category is enormous in practice and it is mostly not a developer problem. It is an operations and hardening problem, which is why the CIS benchmarks and configuration baselines exist.
Modern applications are mostly other people's code. A dependency with a known vulnerability is a vulnerability in your application, whether or not you wrote a line of it.
The controls are a software bill of materials, dependency scanning in the build pipeline, and a process that actually acts on the results. Tools such as OWASP Dependency-Check, Snyk, and GitHub Dependabot cover this ground.
Weak password rules, no protection against credential stuffing, session identifiers that do not rotate after login, sessions that never expire, and multi factor authentication that can be bypassed or relayed.
The single biggest improvement available is phishing resistant multi factor authentication, covered in identity and MFA.
Trusting code or data whose integrity has not been verified: unsigned updates, build pipelines that pull unpinned dependencies, and insecure deserialization of attacker controlled objects.
This is the supply chain category, and it grew in importance after a series of high profile incidents where the compromise arrived through a trusted update mechanism.
The category that connects application security to the blue team. If an application does not log authentication events, access control failures, and significant actions, an intrusion through it is invisible.
Logging that nobody sends anywhere and nobody alerts on counts as a failure too.
The application fetches a URL supplied by the user, and the attacker points it somewhere internal. In a cloud environment the favorite target is the instance metadata service, which can hand back temporary credentials for the workload's role.
That single technique connects web application security directly to cloud security, and it is why metadata service protections exist.
The fix is an allow list of permitted destinations plus network level restrictions, not a blocklist, because there are many ways to write the same address.
Read the current list at owasp.org, then exploit each category yourself in a deliberately vulnerable application. OWASP Juice Shop and WebGoat are both free and built for that purpose.
Modules 13 through 15 of the CEH course cover web servers, web applications, and SQL injection with labs, and there is a separate OWASP Top 10 for LLM Applications covered in our prompt injection guide.
The CEH course exploits a real web application in a lab rather than describing it, which is the only way this material actually sticks.