
Loading

Loading
We use strictly necessary cookies to run this site, and analytics cookies to understand how it's used. See our Privacy Policy for details.
Broken object-level authorization, excessive data exposure, and missing rate limiting, the API vulnerability classes that show up in almost every assessment.
APIs get tested less thoroughly than the web applications sitting in front of them, there's no UI to click through, so a lot of the surface area only gets exercised by whatever the frontend happens to call. That gap is exactly where the most common API findings live.
The single most common API finding, by a wide margin. An endpoint like GET /api/invoices/1042 checks that you're logged in, but not that invoice 1042 actually belongs to you, change the ID, get someone else's data. This is functionally the API version of broken access control, and it's so consistently the top finding that it's worth testing as the very first thing in any API assessment, not an afterthought.
An endpoint returns the full internal object, including fields the frontend never displays, like internal flags, other users' partial data, or fields that were only meant for an admin view, and relies on the client to filter what it shows. The problem is that "the client doesn't display it" isn't the same as "the client can't see it." Any sufficiently curious user with browser dev tools can see the full response.
Login endpoints, password reset flows, and OTP verification endpoints without rate limiting are directly brute-forceable. This is a design gap more than an implementation bug, see the "insecure design" category in the OWASP Top 10, and it's easy to miss because the endpoint works perfectly fine under normal use.
An API accepts a JSON object and maps it directly onto a database model without an explicit allowlist of which fields can actually be set. If isAdmin happens to be a field on the user model, and the update-profile endpoint blindly assigns whatever's in the request body, a user can potentially set it themselves. The fix is boring but complete: explicitly define what's settable, never implicitly trust the whole payload.
An internal or "not yet public" endpoint that isn't referenced anywhere in the visible frontend but is still live and reachable, often discovered via a mobile app's compiled code, JavaScript bundle, or leaked API documentation. An endpoint with no link to it is not the same as an endpoint that requires authorization; both need to be actually secured, not just unlisted.
Stack traces, internal file paths, or database error messages returned directly in an API response. Beyond the information leak itself, this is often the first hint an attacker gets about the underlying stack, which then narrows down what other known vulnerabilities are worth trying.
For APIs that expose both a REST and a GraphQL layer over the same data, it's common for authorization logic to be implemented once and not consistently reused, a check enforced in the REST controller but not replicated in the GraphQL resolver reaching the same underlying data. Any time the same data is reachable through more than one path, every path needs the same authorization check independently verified, not assumed.
Most of these aren't found by automated scanners, because a scanner can't tell that invoice 1042 doesn't belong to the account it's testing with, that requires understanding the application's actual authorization model. That's the gap manual, business-logic-aware testing is built to close. See our Web & API Security service for how we approach this, grounded in the OWASP API Security Top 10. For the resource-consumption side of that same list, see our companion piece on API rate limiting and resource consumption, and for a deeper look at exactly this "invoice 1042" pattern, see broken access control and IDOR, explained.
Tell us about your environment and goals, we'll help you scope the right engagement.