The OWASP Top 10 is a genuinely useful document and a poor checklist. It frames the categories of risk well, which makes it valuable for communicating with people who do not test applications for a living. It does not tell you how these flaws present in a real system, which is the part that matters when you are trying to find them.
This guide covers what these categories actually look like in assessments, with attention to the API surface, where the same failures appear in more dangerous forms.
Broken Access Control Dominates
Access control is the most common serious finding in application testing by a wide margin, and it will remain so, because it is the category tools are least able to address.
The reason is structural. Access control encodes business rules, and a scanner has no way to know that invoice 4021 belongs to a different customer, that a support agent should not be able to change their own role, or that a draft should be invisible until published. Finding these requires someone who understands the intended model and systematically tries to break it.
In practice it presents as:
- Object-level failures. An endpoint checks authentication but not ownership, so changing an identifier returns another user's data. In an API this is called broken object-level authorization and it is the most common serious API flaw we find.
- Function-level failures. Administrative endpoints hidden in the interface but reachable directly, because the front end enforced the restriction and the backend did not.
- Privilege escalation through legitimate features. A user with a limited role able to invite a new user at a higher role, then use that account.
- Enforcement in the wrong place. Rules applied in the browser, which controls nothing, rather than on the server.
Testing this properly requires multiple accounts across multiple roles and, in multi-tenant systems, multiple tenants, so cross-boundary access can be attempted directly rather than inferred.
Injection, Still
Injection has been on this list for two decades and remains present, though the shape has shifted. Parameterized queries have substantially reduced classic SQL injection in code written with modern frameworks, and it survives in older code, in dynamically constructed queries, and in the places developers reach past the framework to build a query by hand.
Meanwhile the category expanded. Command injection appears where an application shells out to a utility. Template injection appears in reporting and email features. NoSQL injection appears where operators can be smuggled into a query object. Deserialization flaws appear where an application accepts serialized objects from a client.
The defense is unchanged and reliable: never construct a query, command or template by concatenating input. Use parameterization, and where a value must reach a sensitive context, validate it against an allowlist.
Server-Side Request Forgery
SSRF earned its own place in the Top 10 largely because of what it reaches in cloud environments. An application that can be induced to fetch a URL of the attacker's choosing makes requests from inside your network, and the highest-value destination is the cloud metadata service, which returns credentials for the role attached to the instance.
The pattern appears anywhere an application accepts a URL: image imports, webhooks, document fetchers, link previews, PDF generators and integrations with third-party services.
Blocklists fail here, consistently. They lose to alternate address representations, DNS entries resolving to internal addresses, and redirects, which is the one that defeats most implementations because the filter checks the submitted URL rather than the final destination. Use an allowlist, resolve and check the address before connecting, and re-check after every redirect. Then enforce IMDSv2 and cut the instance role down, so a successful SSRF is contained. We have written up a worked example in SSRF to cloud takeover.
The API Surface Specifically
APIs deserve separate attention because the assumptions that protect a web interface do not hold.
There is no interface constraining what a client sends, so any validation performed only in the front end is absent. The surface is larger than the application reveals, and enumeration routinely finds deprecated versions still live, internal endpoints reachable from outside, and functionality no current client uses. Documentation, where it exists, describes what the API is meant to expose rather than what it does.
Two failures recur:
Deprecated versions. An older API version, believed retired, remains reachable without the authorization improvements added since. Attackers look for these first.
Excessive data exposure. An endpoint returns a complete object and relies on the client to display only part of it. The additional fields are in the response regardless, frequently including internal identifiers, permission flags or personal data.
Rate limiting is also applied inconsistently. Login endpoints are usually protected; password reset, invitation and search endpoints frequently are not.
Components and Configuration
Vulnerable dependencies and security misconfiguration are the categories automated tooling handles best, which is a good reason to automate them and stop spending manual effort there.
Maintain a software bill of materials, scan dependencies continuously including transitively, and treat the pipeline as production infrastructure, because deployment credentials typically hold more privilege than any human account. Verify security headers, error handling that does not leak stack traces, and default credentials on anything shipped with them.
Using the List Well
Treat the Top 10 as a map of where to look rather than a set of boxes to tick. An application can be free of every category listed and still contain a business logic flaw that lets someone order goods without paying, because that flaw belongs to no category.
The practical division is to automate what tools do well, dependencies, configuration and known vulnerability classes, and to spend human effort on access control, business logic and the API surface. That is where the findings that matter are, and it is where application and API testing earns its cost.
To have your application and API tested together, get in touch.
Frequently asked questions
What is the OWASP Top 10?
The OWASP Top 10 is a widely referenced awareness document listing the most critical categories of web application security risk, maintained by the Open Worldwide Application Security Project. There is a separate OWASP API Security Top 10 covering risks specific to APIs. Both are useful for framing and for communicating with non-specialists, and neither is a test methodology on its own.
Why is broken access control ranked first?
Because it is the most commonly found serious flaw and the hardest to detect automatically. Access control is a business rule, and a scanner has no way to know that a given user should not see a given record. Finding it requires a tester who understands the application's intended authorization model and systematically tries to violate it from multiple accounts.
What is broken object-level authorization?
The API-specific form of broken access control, and the most common serious API flaw. An endpoint verifies that the caller is authenticated but not that the requested object belongs to them, so changing an identifier in the request returns another user's data. It is trivially exploitable, frequently affects every record in a system, and is invisible to tools that do not know who should own what.
Can automated scanning find these issues?
Partially. Scanners are reasonably good at injection, known vulnerable components and misconfiguration. They are poor at access control, business logic and anything requiring understanding of intent, which is where the most serious findings usually live. Use scanning for continuous breadth and manual testing for the categories tools cannot reason about.
How does API testing differ from web application testing?
APIs have no user interface to constrain what is sent, expose more endpoints than the front end reveals, and often carry authorization logic that the web interface enforces separately and inconsistently. Testing an API means enumerating the full surface including undocumented and deprecated versions, and exercising it directly rather than through the application the developers expect to be used.
