Parameter

Shadow API

Also known as

  • Undocumented API
  • Unmanaged API

A shadow API is an API endpoint, version or host that runs in production but is missing from the organization's inventory and documentation, so it skips the security reviews, gateway policies and monitoring applied to known APIs and often exposes old or unprotected functionality to anyone who finds it.

Category
API security
OWASP
API9:2023 Improper Inventory Management
Last reviewed

What is a shadow API?

A shadow API is any API surface that is live but not in the inventory the security team works from. If nobody knows it exists, nobody tests it, patches it, rate-limits it or turns it off.

The term covers a few related cases that practitioners often separate:

  • Shadow endpoints: routes on a known API that the spec does not list, such as a debug route, a bulk export, or an admin action added in a hurry.
  • Zombie or deprecated versions: /v1/ kept running after /v2/ shipped, with the security fixes applied only to v2.
  • Shadow hosts: whole APIs on hosts outside the main inventory, like beta-api.example, staging-api.example or a partner integration service.
  • Third-party and internal APIs reachable from outside because of a network or gateway change.

OWASP files this under API9:2023 Improper Inventory Management. One of its scenarios is a beta API host that lacked the rate limiting production had, which let a researcher brute-force a six-digit password reset token.

Why do shadow APIs happen?

They are a side effect of normal delivery. Teams ship faster than documentation updates, old versions stay up for one client that never migrated, and non-production environments get public DNS for convenience.

Common origins:

  • Versioning without retirement. A new version ships, and the old one stays up with no end-of-life date.
  • Frameworks that auto-register routes. A controller method becomes a public route without anyone writing a spec entry.
  • Mobile apps. Old app versions in the wild keep calling old endpoints, so nobody dares remove them.
  • Environments. Staging, QA and preview hosts share production code, sometimes production data, and get less protection.
  • Acquisitions and side projects. An acquired product or a hackathon service runs on a subdomain nobody on the security team owns.

The risk comes from the controls an undocumented endpoint missed: an authorization check, an auth gateway, a rate limit, a patch. Shadow endpoints are a frequent home for broken function level authorization and broken object level authorization, because the checks were added to the documented routes.

How do you find shadow APIs?

Compare what is actually running and reachable against what the inventory says, from several independent angles. Each method finds things the others miss.

  1. Traffic analysis. Export request logs from the load balancer, CDN or service mesh for a representative period. Normalize paths (/v1/projects/project_1043 becomes /v1/projects/{id}) and list every distinct method and path pair. Anything receiving traffic that is not in a spec is a candidate.
  2. Gateway and ingress logs and configs. List every route the API gateway or ingress controller forwards, and every backend service behind it. Look for wildcard or catch-all routes that forward whole prefixes to a service, since everything behind them is exposed whether documented or not.
  3. Spec diffing. Generate a route list from the code or framework (most frameworks can print their routing table) and diff it against the published OpenAPI spec. Routes in code and not in the spec are shadow endpoints. Routes in the spec and not in code are stale docs.
  4. JavaScript bundle and mobile app analysis. Download the web app's JS bundles and search for URL patterns, API base URLs, and path strings. Decompile the mobile app and do the same. Clients often reference endpoints, versions and hosts the docs never mention, including admin routes shipped to every user.
  5. DNS and certificate transparency for API hosts. Enumerate subdomains from public DNS data and from certificate transparency logs, which publicly record TLS certificates as they are issued (RFC 9162 describes the protocol). Search for names like api, api-v1, beta, staging, internal, partner, graphql. Every host that answers is a candidate API to probe. Hosts whose DNS points at deprovisioned cloud resources are a separate risk, subdomain takeover.

Then probe what you found:

  • Request common spec and schema paths on each host: /openapi.json, /swagger.json, /v2/api-docs, /graphql (with an introspection query).
  • Try older and newer versions of every known path: /v1/, /v2/, /v3/, /beta/, /internal/.
  • Compare responses between versions and hosts for the same call. A missing 401, missing rate limit or extra fields on the old version is the finding.

This work is the API slice of mapping the attack surface, and it has to be repeated, since new shadow surface appears with every release.

How do you prevent them?

Make the inventory a byproduct of deployment, so a route cannot reach production without appearing in it. OWASP's API9 guidance calls for documenting every host, environment and version, generating documentation in CI/CD, and applying protections to all exposed versions, not only production.

In practice:

  • Generate the spec from code, or fail the build when a route exists without a spec entry.
  • Route all external traffic through one gateway with a default-deny rule, so only registered routes are reachable.
  • Give every version an owner and an end-of-life date, and alert on traffic to deprecated versions.
  • Keep non-production hosts off the public internet, or behind the same auth as production, and never load production data into them.
  • Run the discovery methods above on a schedule and treat new hosts or paths as change events that need review.

A WAF in front of the known API does not help with a host it does not sit in front of.

Written by Parameter · Last reviewed

[ related terms ]

Related terms.

Attack surface

An attack surface is every point where an attacker can try to get into a system, affect it, or pull data out of it: internet-facing hosts, APIs, login pages, cloud services, internal network services, physical access and the people who can be tricked.

Broken function level authorization (BFLA)

Broken function level authorization (BFLA) is an API vulnerability where an endpoint meant for a higher role, such as an admin or support action, does not check the caller's role, so an ordinary user calls it directly and performs privileged operations like managing users or changing settings.

Broken object level authorization (BOLA)

Broken object level authorization (BOLA) is an API vulnerability where an endpoint accepts an object ID from the client and returns or changes that object without checking the caller owns it, so an attacker swaps in another user's or tenant's ID and reads, edits or deletes their records.

Subdomain takeover

A subdomain takeover is a vulnerability where a DNS record still points to a deprovisioned cloud resource, letting an attacker register that resource and serve their own content from a subdomain the organization still owns, such as a dangling CNAME to a deleted host.

GraphQL introspection

GraphQL introspection is the built-in GraphQL feature that lets any client query a server's schema through the __schema and __type fields, returning every type, field, argument and mutation; left enabled in production, it hands an attacker a complete map of the API to probe for authorization flaws.