API Attack Paths
Why individually minor API weaknesses can combine into critical exposure.
Demonstration content
The code, requests, and findings in this article come from an intentionally vulnerable demonstration application built by Veyra for research purposes. They do not describe, and must not be read as describing, any real company, customer, or disclosed incident.
Security tools rank findings individually because findings arrive individually. Attackers do not experience an application as a list. They experience it as a graph, and they are looking for a route through it.
Four findings nobody prioritized
The demonstration application produced these four results across a normal scanning pass. Each was rated medium. Each sat in the backlog for a quarter, which is the correct outcome given how they were presented.
User enumeration on password reset
The reset endpoint returns a different response for a known address than an unknown one.
No rate limiting on token validation
The reset-token endpoint accepts unlimited attempts from a single source.
Short numeric reset tokens
Tokens are six digits and valid for 60 minutes.
Verbose error responses
Errors distinguish "expired" from "invalid", leaking token state.
Read the list again as a sequence rather than a set.
The path
Enumeration establishes which addresses have accounts. Six-digit tokens define a keyspace of one million. No rate limiting means the keyspace can be traversed. Verbose errors confirm when a guess is structurally right. The four together are not four medium problems — they are one complete account takeover.
# 1. confirm the target has an account (M-1)
POST /api/auth/reset {"email":"cfo@target.example"}
200 {"message":"Reset link sent"} ← unknown addresses return 404
# 2. trigger a reset, then traverse the keyspace (M-2 + M-3)
POST /api/auth/reset/verify {"email":"cfo@target.example","token":"000000"}
400 {"error":"invalid_token"}
...
POST /api/auth/reset/verify {"email":"cfo@target.example","token":"493117"}
200 {"reset_session":"eyJhbGciOi..."} ← 493,117 attempts · 11 minutes
# M-4 made it faster: "expired" vs "invalid" revealed which window was live
Eleven minutes against a single unremarkable endpoint. The account belonged to a finance role with access to billing exports — which is the second half of the point. Impact is not a property of the endpoint. It is a property of what sits behind it.
Why individual scoring fails here
Each finding, in isolation, was rated correctly. Enumeration on its own leaks the existence of an account, which is genuinely medium. The failure is not in the scoring of any one item. It is that nothing in the pipeline was responsible for looking at them together.
This is a structural property of how most security tooling works. A scanner evaluates one artifact and reports what it matched. It has no model of the application, so it cannot reason about sequences. The result is a backlog where the four findings that chain into a critical are indistinguishable from the forty that do not.
What path-aware analysis requires
- A graph of the application, not a list of files: routes, the data they reach, the boundaries between them, and what an authenticated session can do at each hop.
- Reachability: whether an entry point is genuinely accessible from the internet, or theoretically vulnerable but unreachable.
- Asset value at the destination: an account takeover of a read-only trial user and of a finance administrator are not the same event.
- Escalation across hops: whether the privileges gained at one step unlock the next.
HOW VEYRA DETECTS THIS
- Veyra API inventories the reset endpoints, records that neither enforces a rate limit, and identifies the token parameter as an authentication secret.
- Veyra Code establishes the token generation function: six digits, sixty-minute validity, and a comparison that returns distinguishable errors.
- Veyra Intelligence walks the graph from an unauthenticated entry point and finds a traversable path to authenticated session issuance.
- Severity is recalculated on the path, not the individual nodes. Four mediums become one critical, and the four originals are grouped beneath it rather than duplicated.
- Remediation is ordered by which single fix breaks the chain most cheaply — here, rate limiting, which costs an afternoon and severs the path immediately.
The token length should also be fixed. But knowing which fix to ship first is most of the value when the team has one afternoon.
Fixing a chain
Chains have a useful property: breaking any link defeats the path. That means you can triage by cost rather than by severity label.
- Rate limit token validation. Per account and per source, with exponential backoff and lockout. Cheapest fix, breaks the chain immediately.
- Use cryptographically random tokens. At least 128 bits, single-use, and invalidated on the first successful reset. Removes the keyspace problem permanently.
- Return uniform responses. The reset endpoint should respond identically for known and unknown addresses, and validation should never distinguish expired from invalid.
- Shorten the window. Sixty minutes is generous; fifteen is usually plenty and cuts the exposure window by 75%.
- Alert on volume. Hundreds of failed token validations against one account is not an anomaly to investigate later — it is an attack in progress.
What to take away
If your security tooling cannot express the sentence "these four findings are one problem," it will systematically under-report your real risk. Not because its individual severity ratings are wrong, but because the question it is answering is smaller than the question you need answered.
Assess paths. Rank by what an attacker can reach, not by what a scanner matched.
Does this exist in your application?
A baseline assessment answers that question against your own authorized code, APIs, and external surface.