Sequential Abuse: Why Request Order Matters

Malicious actors targeting APIs often follow a recognizable pattern in the order they hit endpoints—whether injecting, scraping, harvesting, or exfiltrating data. These behaviors are frequently invisible to volumetric detection because attackers can deliberately slow their request rate to stay under the radar. The key signal, then, is not volume but sequence. We call this sequential abuse: malicious activity defined by the order of API requests rather than their count. Our challenge is separating these malicious sequences from benign ones.

To approach this, we treat a user’s time-ordered series of HTTP API requests as a session. For example, a banking customer’s session might look like:

Time Order Method Path Description
1 POST /api/v1/auth Authenticates a user
2 GET /api/v1/accounts/{account_id} Displays account balance, where account_id is an account belonging to the user
3 POST /api/v1/transferFunds Containing a request body detailing an account to transfer funds from, an account to transfer funds to, and an amount of money to transfer

The practical goal is to help customers enforce expected behavioral patterns. A desired pattern might be that /api/v1/auth must always precede /api/v1/accounts/{account_id}. But the combinatorial space of possible sessions grows quickly with length—users can check balances, transfer funds, and repeat actions in many orders. Suggesting enforceable rules therefore first requires summarizing past sequential behavior into meaningful patterns, which we call sequences: consecutive endpoints within a session, like /api/v1/accounts/{account_id}/api/v1/transferFunds.

Volume alone is a poor guide for identifying which sequences matter. A sequence like /api/v1/accounts/{account_id}/api/v1/transferFunds may be rare in absolute terms yet still be highly deterministic—it may almost always be preceded by that specific account call. Relying purely on frequency could hide exactly the kind of rule worth surfacing.

Modeling Sessions with Markov Chains

A natural modeling tool for sequential data is the Markov chain, where the probability of the next endpoint depends only on a fixed number of preceding ones. Let’s illustrate with three endpoints:

  • a: /api/v1/auth
  • b: /api/v1/accounts/{account_id}
  • c: /api/v1/transferFunds

The simplest Markov chain estimates the probability of the next endpoint given exactly one preceding endpoint:

Known preceding endpoint in the session Estimated probability of next endpoint in the session
a b c
a 0.10 (1555) 0.89 (13718) 0.01 (169)
b 0.03 (9618) 0.63 (205084) 0.35 (113382)
c 0.02 (3340) 0.67 (109896) 0.31 (51553)

Each table entry corresponds to a two-endpoint sequence. The bracketed counts are raw occurrences, and probabilities are derived from them via maximum likelihood estimation—for example, 169 / (1555 + 13718 + 169) = 0.01.

For identifying important sequences, we move away from point estimates and instead use credible intervals. These give a plausible probability range that reflects how much data supports the estimate. More occurrences narrow the interval; fewer widen it. Applying this to the counts above yields:

Known preceding endpoint in the session Estimated probability of next endpoint in the session
a b c
a 0.09-0.11 (1555) 0.88-0.89 (13718) 0.01-0.01 (169)
b 0.03-0.03 (9618) 0.62-0.63 (205084) 0.34-0.35 (113382)
c 0.02-0.02 (3340) 0.66-0.67 (109896) 0.31-0.32 (51553)

Higher-order chains extend the context. An order-2 model conditions on two preceding endpoints:

Known preceding endpoints in the session Estimated probability of next endpoint in the session
a b c
aa 0.09-0.13 (173) 0.86-0.90 (1367) 0.00-0.02 (13)
ba 0.09-0.11 (940) 0.88-0.90 (8552) 0.01-0.01 (109)
ca 0.09-0.12 (357) 0.87-0.90 (2945) 0.01-0.02 (35)
ab 0.02-0.02 (272) 0.56-0.58 (7823) 0.40-0.42 (5604)
bb 0.03-0.03 (6067) 0.60-0.60 (122796) 0.37-0.37 (75801)
cb 0.03-0.03 (3279) 0.68-0.68 (74449) 0.29-0.29 (31960)
ac 0.01-0.09 (6) 0.77-0.91 (144) 0.06-0.19 (19)
bc 0.02-0.02 (2326) 0.77-0.77 (87215) 0.21-0.21 (23612)
cc 0.02-0.02 (1008) 0.43-0.44 (22527) 0.54-0.55 (27919)

Here, the interval 0.09–0.13 for row ca means: given the last two endpoints were c then a, the probability the next is a lies in that range, regardless of earlier history. An order-0 model represents the unconditional distribution over endpoints:

Known preceding endpoints in the session Estimated probability of next endpoint in the session
a b c
0.03-0.03 (15466) 0.64-0.65 (328732) 0.32-0.33 (165117)

A fixed-order chain, however, has two limitations: we must pick the order N upfront, and every identified sequence has the same length N+1.

Variable Order Markov Chains

Variable order Markov chains (VOMCs) resolve both issues by recognizing redundancy in fixed-order tables. Compare Table 3 and Table 2: in Table 3, the contexts aa, ba, and ca all share a as their suffix, and for each possible next endpoint their credible intervals overlap with the corresponding interval for context a in the order-1 table. This means the extra preceding endpoint provides no statistically discernible information. We can safely collapse those rows into a single row for context a:

Known preceding endpoints in the session Estimated probability of next endpoint in the session
a b c
a 0.09-0.11 (1555) 0.88-0.89 (13718) 0.01-0.01 (169)
ab 0.02-0.02 (272) 0.56-0.58 (7823) 0.40-0.42 (5604)
ac 0.03-0.03 (6067) 0.60-0.60 (122796) 0.37-0.37 (75801)
bb 0.03-0.03 (3279) 0.68-0.68 (74449) 0.29-0.29 (31960)
bc 0.01-0.09 (6) 0.77-0.91 (144) 0.06-0.19 (19)
cb 0.02-0.02 (2326) 0.77-0.77 (87215) 0.21-0.21 (23612)
cc 0.02-0.02 (1008) 0.43-0.44 (22527) 0.54-0.55 (27919)

The result is a model where context length varies—here, between 1 and 2. In general, the learning algorithm works iteratively:

(1) Define the table T containing the estimated probability of the next endpoint in a session, given alternatively 0, 1, 2, …, N_max preceding endpoints in the session. That is, form a single table by concatenating the rows corresponding to Markov chains of fixed orders 0, 1, 2, …, N_max.

(2) is_modified := true

(3) DO WHILE is_modified

(4) D := all contexts in T which are not suffixes of at least 1 other context in T

(5) is_modified = false

(6) FOR ctx IN C

(7) IF length(ctx) > 0

(8) parent_ctx := the context obtained by deleting the leftmost endpoint in ctx

(9) IF is_collapsible(ctx, parent_ctx)

(10) Modify T by discarding ctx

(11) is_modified = true

Here, ctx is collapsible when all its credible intervals overlap with those of its parent context (obtained by dropping the leftmost endpoint), for each possible next endpoint. A context is a suffix of another if the longer one can be formed by prepending zero or more endpoints. The empty context is thus a suffix of every context. This approach is a variant of ideas from Rissanen and Ron et al.

The surviving entries in T are our important sequences. For usability, we rank them via a precedence score from 0.0 to 1.0: the number of times the full sequence occurs divided by the number of times its final endpoint occurs. A score near 1.0 means the endpoint is almost always preceded by the rest of the sequence—exactly the kind of dependency that makes a good enforcement rule.

Scaling Sequence Learning

The sketch above is the conceptual core. In production, Sequence Analytics uses an online algorithm that updates continuously rather than requiring an offline training pass. This sidesteps memory blowup: a naive implementation would explode in table rows as maximum sequence length grows. To handle high-volume APIs without CPU strain, we apply an adaptive sampling strategy upstream—more aggressive sampling for busier APIs—and the learning algorithm consumes those sampled streams.

After onboarding, sequences are assembled and refined over time, with the summary representing a sliding window of roughly the last 24 hours. Results are stored in Clickhouse and exposed through a GraphQL API and the Cloudflare dashboard. Enforcement happens via Sequence Mitigation, which handles distributed rule matching across Cloudflare’s network.

This is a first piece of the sequential-abuse story. The next question—identifying which learned sequences are actually anomalous and therefore worth blocking—builds directly on this foundation.