BrokenApp
Back to blog
ResearchJan 18, 20266 min read

Step-skip and replay: detecting business logic flaws automatically

Business logic flaws are the class of vulnerability that no traditional scanner catches. They don't show up in dependency audits, they don't match regex signatures, and they aren't in the CVE database. They're the bugs that exist because a developer assumed users would follow the happy path — and attackers don't.

BrokenApp's business logic module detects two specific patterns: step-skip vulnerabilities in multi-step flows, and replay attacks that exploit idempotency failures. Both are common in production applications, both are trivially exploitable, and both are invisible to conventional tooling.

What step-skip vulnerabilities look like

A step-skip vulnerability exists when a multi-step process — a checkout flow, an onboarding wizard, an approval chain — allows a user to jump directly to a later step without completing the required intermediate steps. The classic example is an e-commerce checkout where the payment step can be bypassed entirely by navigating directly to the order confirmation URL.

These flaws are surprisingly common. Any application that uses client-side routing to manage wizard state is a candidate. The server receives a request for step four and processes it, never validating that steps one through three were completed. The order gets created, the inventory gets decremented, the confirmation email gets sent — all without a payment being processed.

The same pattern appears in KYC flows where identity verification can be skipped, in approval workflows where manager sign-off is bypassed, and in registration processes where email verification is never enforced.

Building directed graphs from view transitions

BrokenApp detects step-skip vulnerabilities by constructing a directed graph of view transitions during the crawl phase. Every time the scanner navigates from one view to another — following a link, submitting a form, clicking a button that triggers a client-side route change — it records the transition as an edge in the graph.

Once the crawl completes, the scanner analyzes the graph topology to identify linear chains: sequences of views where each view has exactly one predecessor and one successor. These chains are candidate multi-step flows. A four-step checkout produces a chain of four nodes with three edges.

The scanner then tests each chain by attempting to access later steps directly, without traversing the preceding edges. It replays the session cookies from the crawl but navigates straight to step three or step four. If the server returns a 2xx response with content that matches the expected step (rather than a redirect back to step one), the scanner flags a step-skip vulnerability.

# Detected linear chain during crawl
/checkout/cart
/checkout/shipping
/checkout/payment
/checkout/confirm
# Step-skip test: direct access to /checkout/confirm
VULN Step-skip: /checkout/confirm accessible without /checkout/payment
CWE-840 Business Logic Error — step validation missing

Replay attacks and idempotency failures

The second class of business logic flaw BrokenApp detects is the replay attack. A replay vulnerability exists when a state-changing request — a payment submission, a vote, a transfer — can be sent multiple times and the server processes each duplicate as if it were a new request.

BrokenApp identifies replay candidates by filtering for POST and PUT requests observed during the crawl that returned 2xx status codes. It then resends each request with the identical headers, cookies, and body. If the server returns another 2xx response, the scanner compares the response body against the original using structural similarity scoring. A high similarity score indicates the server processed the duplicate request successfully rather than rejecting it.

The scanner applies additional heuristics to reduce false positives. It checks for idempotency tokens in the original request (CSRF tokens, nonces, request IDs) and verifies whether the replayed request was processed with the same token. If the application uses idempotency keys correctly, the replayed request should be rejected or return a cached response. If it processes a fresh transaction, the vulnerability is confirmed.

# Replay detection on payment endpoint
POST /api/payments/charge → 200 (original)
POST /api/payments/charge → 200 (replay)
Body similarity: 0.94 — duplicate charge created
# Expected behavior
POST /api/payments/charge → 409 or 422 (replay rejected)

Real-world examples from production scans

During our beta testing period, the business logic module identified step-skip and replay vulnerabilities in a significant percentage of scanned applications. The most common findings fell into three categories.

Payment bypass was the most severe. Several e-commerce applications allowed direct navigation to the order confirmation page, creating orders without any payment being processed. The server-side logic checked whether a cart existed in the session but never verified that a payment intent had been fulfilled.

Duplicate transactions appeared frequently in applications that handled payments, voting, or resource allocation. One application allowed a single coupon redemption request to be replayed indefinitely, generating unlimited discount codes. Another processed duplicate wire transfer requests, each creating a real transaction in the banking integration.

Registration bypass was less severe but still impactful. Several SaaS applications allowed users to skip email verification and access the dashboard directly, bypassing the intended onboarding flow and any associated rate limiting or abuse prevention.

Why traditional scanners miss these

Traditional web application scanners operate on a request-response model. They send a request, inspect the response for known vulnerability signatures, and move on. They don't model the intended flow of an application. They don't understand that step three should only be accessible after step two. They don't know that a POST request should only succeed once.

SAST tools analyze source code but can't detect these flaws either, because the vulnerability isn't in any single function — it's in the absence of a check that should exist somewhere in the request lifecycle. There's no code to flag; the bug is the missing code.

BrokenApp takes a different approach by building a behavioral model of the application during the crawl and then testing violations of that model. The directed graph of view transitions encodes the developer's intended flow. Step-skip and replay tests are violations of that flow — accessing states that should be unreachable or repeating actions that should be one-time.

Running business logic tests with the CLI

Business logic testing is enabled by default in BrokenApp scans. The scanner automatically identifies candidate flows and replay targets during the crawl phase. You can also scope the tests to specific paths using the TOML configuration file.

# brokenapp.toml
[modules.business_logic]
enabled = true
step_skip = true
replay = true
replay_methods = ["POST", "PUT"]
chain_min_length = 3

Findings are mapped to CWE-840 (Business Logic Error), CWE-841 (Improper Enforcement of Behavioral Workflow), and CWE-799 (Improper Control of Interaction Frequency). Each finding includes the full request/response pair, the detected flow chain, and a recommended remediation.