API Security

API Security Best Practices: Patterns From Real-World Breaches

The recurring patterns behind reported API breaches — broken object-level authorization, unrestricted resource consumption, inventory drift — and what actually prevents them.

Author
CyberGuards Security Research Team
Published
Updated
Read
13 min read

A note on examples

What follows is a synthesis of recurring patterns we see across reported API incidents and across our own engagements. Specific company names are not necessary to make the patterns useful — the same flaws show up across industries, with the same root causes and the same fixes. If you want to map this to a specific publicly-disclosed incident, the OWASP API Top 10 supplementary materials and a few public breach databases catalog real cases for each category.

Pattern 1: Broken object-level authorization

The shape. An API endpoint accepts an identifier — user ID, account ID, document ID — and returns the corresponding object. The endpoint authenticates the caller (so the caller must be a logged-in user), but it does not verify that the caller is authorized to read this specific object. Result: any logged-in user can read any object by guessing or enumerating identifiers.

Why it keeps happening. The fix lives at the data-access layer. Frameworks make it easy to put the auth check at the controller and trust that the query returns "the right thing" — which it does, until an identifier is supplied that the user should not access. The query returns the object; the controller never re-checks.

What prevents it. Authorization at the data-access layer, scoped to the caller's identity. Row-level security in the database. ORM scopes that automatically filter by tenant or owner. Default-deny query patterns where the query without an explicit identity filter returns nothing.

Pattern 2: Unrestricted resource consumption

The shape. An API endpoint performs expensive work — search, export, aggregation, image processing — without per-caller limits. An attacker (or a buggy client) submits requests in volume and the service degrades or fails entirely. In other variants, the cost is financial: each request triggers a paid third-party call, and the bill arrives at the end of the month.

Why it keeps happening. Rate limits exist on login but not on internal expensive operations. Pagination has no maximum. Background jobs are triggered synchronously. The system is sized for normal load and folds under malicious load.

What prevents it. Per-identity and per-endpoint rate limits at the gateway. Hard caps on pagination. Async processing with quotas for any operation that costs real money or significant compute. Cost annotations per endpoint so the gateway knows what is expensive.

Pattern 3: API inventory drift

The shape. An old API version, a staging endpoint, or an internal API ends up reachable from the public internet. The old version has weaker auth, missing fixes, or different security posture than the current version. An attacker discovers the old endpoint via DNS, certificate transparency logs, or directory enumeration, and uses it as the entry point.

Why it keeps happening. APIs accumulate. Versions deprecate slowly. Staging hosts persist after they are no longer needed. Documentation diverges from production reality.

What prevents it. Maintain an explicit inventory of API endpoints and versions, with sunset dates. Guard staging with auth at the network or gateway layer. Monitor certificate transparency for hostnames you did not expect to be public.

Pattern 4: Mass assignment via excessive input trust

The shape. A user updates their profile by submitting a JSON object. The backend accepts the entire object and applies it to the database record. The user submits an extra field — role: "admin", verified: true, balance: 99999 — and the backend processes it because it never explicitly rejected unknown fields.

Why it keeps happening. ORMs and frameworks default to permissive input handling. The schema for the response is the same as the input, which makes it easy to accept fields you intended only to return.

What prevents it. Explicit input allow-lists per endpoint and per role. DTOs separate from database models. Response shapers that strip output fields not authorized for the caller.

Pattern 5: Server-side request forgery

The shape. An API accepts a URL — for image fetching, webhook delivery, link previews, file imports — and the server makes the request. An attacker supplies a URL pointing to internal services, cloud-metadata endpoints, or sensitive paths behind the perimeter, and the server's response leaks internal data.

Why it keeps happening. Outbound HTTP feels like a trusted operation; the input is "just a URL". Cloud-metadata services reachable from compute instances make SSRF disproportionately dangerous in cloud environments.

What prevents it. Allow-list of permitted destinations. Strip credentials from outbound requests. Cap or disable HTTP redirects. Use a separate egress proxy with policy enforcement.

Pattern 6: Broken authentication and identity

The shape. Authentication mechanisms are implemented incorrectly. JWT alg confusion. Refresh tokens that work indefinitely after device replacement. Password resets that rely on guessable tokens. Federated login flows that downgrade to weaker local auth. Each is a small mistake that becomes the entry point.

Why it keeps happening. Auth is built once and rarely revisited. Edge cases (recovery, device replacement, federation downgrade) get less attention than the happy path.

What prevents it. Use a well-known auth library; do not roll your own. Validate JWT alg parameters. Rotate refresh tokens on use. Single-use, time-bound reset tokens. Test the full identity surface, not just the login form.

Practical best-practice checklist

Twelve items that, if applied consistently, prevent most of what we see in real engagements:

  1. Authorization at the data-access layer, not at the controller.
  2. Default-deny query patterns scoped to caller identity.
  3. Explicit input allow-lists per endpoint and per role.
  4. DTOs separate from database models for both input and output.
  5. Per-identity and per-endpoint rate limits at the gateway.
  6. Hard maximums on pagination and batch operations.
  7. Inventory of API endpoints and versions with sunset dates.
  8. Allow-list of outbound URLs; strip credentials; disable redirects.
  9. Well-known auth library; validate JWT alg explicitly.
  10. Single-use, time-bound password-reset tokens.
  11. Audit logs for sensitive operations, with tamper-evidence.
  12. Annual third-party API penetration testing scoped to OWASP API Top 10 plus business-logic abuse cases.

The honest summary: most reported API breaches do not exploit novel categories of bug. They exploit the same handful of patterns repeatedly. The fix list is short and well-known. The work is making it consistent across every endpoint your team has shipped, including the ones from two years ago that nobody reads anymore.

Preparing for your first pentest? Download the SMB Pentest Readiness Checklist →

FAQ

API breach patterns — common questions

What is the most common cause of API breaches?

In reported incidents and in our own engagements, broken object-level authorization (BOLA) is the most common technical cause. The user calls an API endpoint with an identifier and the endpoint returns data without verifying the caller is authorized to access that specific identifier.

Are public APIs more breached than internal ones?

Public-facing APIs receive more attention from researchers and adversaries, so reported incidents skew toward them. Internal APIs are not safer — they are usually less tested and tend to have larger blast radius when something does go wrong.

Does an API gateway prevent these breaches?

A gateway helps with rate limiting, schema enforcement, and request inspection. It does not enforce object-level authorization, business logic, or tenant isolation — those are application concerns the gateway cannot reason about.

Should we follow OWASP API Top 10 for prevention?

Yes, as a checklist. The 2023 list maps almost one-to-one to the patterns behind reported breaches. The categories are abstract; the application of them to your code is what matters.

How do we test for these patterns?

Authenticated API testing with two accounts per role per tenant, walking every endpoint against every role and tenant. Plus rate-limit testing, mass-assignment tests, SSRF probes, and inventory checks for old API versions.

Want a credible answer when a customer, auditor, or your board asks how secure you are?

A quick scoping call with the senior tester who would run your engagement. No slides, no pitch — we look at what you have, tell you what we would test first, and give you a fixed scope, price, and date.