I run the API gateway in front of a few dozen services, and the endpoint that keeps me up at night is never the one I wrote a test for. It is the one nobody told me shipped. The OWASP API Security Top 10 names that exact failure (Improper Inventory Management, API9:2023), but most teams pin the list to a wall instead of working it as a backlog. These tips are for whoever owns the gateway, the WAF, or the platform, and has to answer a CISO asking "do we even know every API we expose?" Each one is tied to a specific OWASP category, a real breach, or a number you can check. No "rotate your keys" filler.

The tips

  1. Treat the 2023 edition as current and stop waiting for an "API 2025" list. There is no 2025 edition of the OWASP API Security Top 10. The "OWASP Top 10 2025" you keep seeing referenced is the general web-application list, a separate project. The API list's newest edition is 2023, which merged Excessive Data Exposure and Mass Assignment into Broken Object Property Level Authorization (API3) and renamed Improper Assets Management to Improper Inventory Management (API9). Map your controls to the 2023 categories now, not to a draft that does not exist.
  1. Find shadow and zombie APIs with runtime discovery, not your OpenAPI spec. Audits routinely put 30 to 40% of an organization's real API footprint in shadow (undocumented) or zombie (deprecated but still live) endpoints, and only 15% of orgs say they trust their own inventory (AppSec Santa, 2026). Your spec file describes what you meant to ship, not what is listening. eBPF-based discovery captures close to 100% of calls at the kernel for 1 to 3% CPU overhead and no code changes (Invicti, 2026). On Kubernetes, Pixie gives you a fast read of live HTTP routes:
   px run px/http_data -o json | jq -r '.req_path' | sort -u

Diff that against your spec. Every path in the first set and not the second is a finding.

  1. Test BOLA by replaying user A's request with user B's token. Broken Object Level Authorization is API1:2023 for a reason: it shows up in roughly 40% of all API attacks (Salt Security). It is also cheap to test. For every endpoint that takes an object id, fire the request as user A, then replay it byte-for-byte with user B's token and assert a 403 or 404.
   # expect 403/404, not 200
   curl -s -o /dev/null -w "%{http_code}" \
     -H "Authorization: Bearer $USER_B_TOKEN" \
     https://api.internal/v1/invoices/$USER_A_INVOICE_ID

A 200 means you have a BOLA, and a generic scanner will often miss it because the response looks valid. Put this in CI so it fails the build, not in a quarterly pentest.

  1. Give every endpoint a deprecation TTL so zombies cannot rot for years. The 2022 Optus breach exposed 9.8 million customers through a public API that had been internet-facing since 2020, carrying an access-control coding error introduced as early as 2018 (2022 Optus data breach). That is a zombie endpoint that lived for four years. Tag routes with a sunset date in gateway metadata and alert when one passes it with live traffic.
   # Envoy/Gateway route metadata
   metadata:
     sunset: "2026-09-01"
     owner: billing-team

Anything past sunset still serving traffic is a ticket, not a maybe.

  1. Lock down object properties at both ends to close API3:2023. Broken Object Property Level Authorization is the merge of over-exposing response fields and accepting fields you should not (mass assignment). Do not serialize your whole ORM model. Define an explicit response allowlist, and reject unknown keys on input so an attacker cannot set "role":"admin" by guessing field names.
   class InvoiceOut(BaseModel):
       id: str
       amount: int
       # no internal_notes, no owner_id

   class InvoiceIn(BaseModel):
       model_config = ConfigDict(extra="forbid")  # reject unknown fields
       amount: int
  1. Rate-limit by business flow, not just per-IP, for API4 and API6. Unrestricted Resource Consumption (API4) and Unrestricted Access to Sensitive Business Flows (API6) are not stopped by a flat "100 req/min per IP." An attacker scalping concert tickets or brute-forcing OTPs spreads across hundreds of addresses. Limit the costly flow on its business key: OTP verifications per account per hour, password resets per user per day, checkout attempts per session. The counter belongs on the identity, not the network address.
  1. Make the gateway default-deny on auth, because one missing check is the whole breach. The Optus endpoint required no authentication at all. Configure the gateway so a route with no auth policy is rejected at deploy time, not served. In an Istio or Envoy Gateway setup, attach a RequestAuthentication plus an AuthorizationPolicy, set the cluster default to deny, and fail CI lint if any route lacks one. A new route inherits "deny" until someone explicitly opens it.
  1. Allowlist outbound destinations to stop SSRF (API7:2023). Server Side Request Forgery became its own category in 2023 because so many APIs fetch user-supplied URLs (webhooks, image imports, link previews). If your service can be told to fetch http://169.254.169.254/, it is now a cloud-metadata exfiltration tool. Resolve the host and block private, link-local, and loopback ranges before the request leaves your process.
   import ipaddress, socket
   ip = ipaddress.ip_address(socket.gethostbyname(host))
   if ip.is_private or ip.is_link_local or ip.is_loopback:
       raise ValueError("blocked SSRF target")

Resolve once and connect to that resolved IP, or a DNS rebind will slip past you between the check and the fetch.

  1. Distrust the APIs you consume, not only the ones you expose (API10:2023). Unsafe Consumption of APIs covers the third-party responses your code swallows without checking. A partner's compromised API can hand you a malicious redirect, an oversized payload, or injected data you pass straight to your database. Set timeouts, cap response size, and validate the response schema the same way you validate inbound requests. A vendor's 200 is untrusted input.
  1. Fail the build when a live route is missing from the spec. This operationalizes API9 (Improper Inventory Management). In CI, hit the running service's route table and diff it against the committed OpenAPI file. An undeclared route fails the pipeline. This is the single control that turns shadow APIs from a quarterly audit surprise into a pull-request comment, and it is the one I would ship first.

Wrap-up

If you do only one of these, do number 10: make undocumented routes fail the build. Every breach above started as an endpoint someone forgot, and you cannot defend an API you do not know is running. Here is the order I would work it, with the trigger that fires each step:

  1. This week, run eBPF discovery and diff against your spec (tip 2). If shadow plus zombie endpoints exceed 10% of your live routes, freeze new API merges until the gap is documented. The industry baseline is 30 to 40%, so crossing 10% means you are already losing track.
  2. Add the BOLA replay test to CI (tip 3). If any object-id endpoint returns 200 for another user's token, it is a release blocker, not a backlog item. BOLA is 40% of real attacks.
  3. Wire the spec-vs-runtime diff into the pipeline (tip 10). If even one live route is missing from the spec, fail that build the same day.
  4. Tag every route with a sunset date and default-deny auth (tips 4 and 7). If a route passes its sunset still serving traffic, or ships with no auth policy, page the owner. Optus is the price of a four-year-old miss: 9.8 million records.

Sources

  • https://owasp.org/API-Security/editions/2023/en/0x04-release-notes/
  • https://salt.security/blog/api1-2023-broken-object-level-authentication
  • https://www.invicti.com/blog/web-security/api-discovery-kubernetes-runtime
  • https://en.wikipedia.org/wiki/2022_Optus_data_breach
  • https://appsecsanta.com/research/api-security-statistics