Definition
What is API Security?
API security is the practice of protecting APIs from abuse: authenticating callers, authorising every object and action they request, validating input, and limiting what a single caller can consume. Most API breaches are authorisation failures, not exotic exploits.
A set of practices and controls designed to protect application programming interfaces (APIs) from unauthorized access, misuse, and attacks. APIs directly expose business logic and data, making them high-value targets; common vulnerabilities include broken object-level authorization, mass assignment, and excessive data exposure. Automated penetration testing tools increasingly focus on API-specific attack patterns as API-first architectures become the norm.
GraphQL: The Same Rules, Enforced in More Places
GraphQL does not introduce a new class of vulnerability so much as multiply the places the old ones have to be enforced. One endpoint, many resolvers: authorisation has to hold per field, and a single resolver that trusts its parent object is enough to leak data the query should never have returned.
The GraphQL-specific list is short and worth testing explicitly. Introspection enabled in production hands an attacker your complete schema, including the mutations you thought nobody knew about. Query depth and nesting turn one request into expensive database work, and batching multiplies it — a rate limit counted per request does nothing when a single request contains five hundred operations. Aliasing defeats naive per-field rate limits the same way.
Then the ordinary things, in GraphQL clothing: mutations that accept fields the caller should not be able to set, error messages that reveal schema internals, and field-level authorisation that exists on the query path but not on the equivalent mutation. Test it as you would REST — as multiple roles and multiple tenants — and add depth, batching and introspection to the checklist.
Why APIs Fail Differently From Web Pages
A web page hides its logic behind a rendered interface; an API publishes it. Every endpoint states what it accepts, and anything the server forgets to check is directly reachable by anyone who can send a request. That is why the dominant API failure is not injection but authorisation: the caller is authenticated correctly and then handed an object they should never have seen.
The second structural difference is inventory. Applications have pages someone designed; APIs accumulate endpoints — a version left running, an internal service exposed for a migration, a mobile-only route nobody documented. You cannot secure a surface you have not enumerated, and the endpoint that leaks is almost always one that was not on the list.
The Failures That Actually Cause Breaches
Broken object-level authorisation: the endpoint checks that you are logged in, then returns the record whose identifier you supplied. Every enumerable ID is a test case, and this single class accounts for a large share of reported API data exposure.
Broken function-level authorisation: an administrative action reachable by a normal user because the check lives in the UI rather than the endpoint. Mass assignment: a role or plan field accepted from the request body and written straight to the record. Excessive data exposure: the endpoint returns the whole object and expects the client to display only part of it, so the sensitive fields travel to anyone who reads the response.
Then the operational ones: no rate limiting on an expensive operation, no idempotency on anything that moves money or state, and secrets sitting in a response header or a frontend bundle. None of these need a clever attacker; they need a curious one.
What Testing Has to Cover, and Why Scanners Miss It
Meaningful API testing needs at least two accounts and every role you support, because the questions are relational: can this user reach that object, can this role invoke that function, can this tenant see that tenant. A signature-based scanner cannot express any of it — there is no pattern for "this identifier belongs to somebody else", only a business rule that lives in your product.
Coverage also has to start from a real inventory: an OpenAPI or GraphQL schema, traffic observation, or discovery. Testing only documented endpoints tests the endpoints you already thought about. GraphQL adds its own list — introspection left on in production, query depth and batching abuse, and per-field authorisation that has to hold independently of the resolver.
The practical minimum: authenticated multi-role testing of every read and write endpoint, identifier swapping in nested payloads rather than just URLs, rate-limit testing that survives session rotation, and webhook verification for anything that accepts callbacks.
Controls That Are Worth the Effort
Authorise at the object, not at the door. Every handler that returns or mutates a record should verify ownership at the point of access, and the safest implementations make that impossible to forget — a data layer that requires a tenant context rather than a convention that a reviewer has to notice.
Then: allow-list input rather than blocking known-bad; return only the fields the caller needs; rate-limit per identity and per resource rather than per session; require idempotency keys on state-changing calls; and verify webhook signatures with replay protection. None of this is novel, and the reason it keeps being the finding is that it is checked per endpoint and endpoints accumulate faster than reviews.