SReverseby Simpa Labs

Replay diagnosis

Why the same request works once and then fails

The first send returned data and the identical second send returned an error. That pattern is narrow enough to test directly, and the result decides how your client has to generate each request.

Two sends answer the first question

Capture a request that succeeded, send the captured bytes again immediately with no edits, and record both responses.

  • The first send passes and the immediate second fails. The server accepts the request once and refuses the repeat. A single-use value or a rotation is in play.
  • Both sends fail. The captured request was already consumed or has expired, and nothing you can change in the replay will revive it. You need a freshly generated request.
  • Both sends pass. The endpoint is not enforcing uniqueness on that call, and the failure you saw earlier came from somewhere else in the flow.

When both sends fail, sign a new request with a current timestamp and a new nonce and send it twice. That step separates expiry from replay protection, because a request that works when fresh and fails on its second send points at a one-time value rather than a short window.

Separate a nonce from an idempotency key

Both make a second send fail, and they mean different things for your client. A nonce protects the server from a repeated request. An idempotency key protects an operation from running twice. The distinction shows up in what the request does.

Run the test against a read-only endpoint. If a GET succeeds once and then fails, the server is rejecting a repeated request, which is replay protection and has nothing to do with side effects. If reads repeat without trouble and only a write fails on the second attempt, the value is an idempotency key tied to that operation. For a write, generating a new key means creating a second object, so the right behaviour depends on what the flow is for.

Look for a value that rotates in the response

One-time tokens are common in mobile flows: a code, a challenge, a refresh token, or a session value that the server replaces on every response. The first request works because the value is current, and the second fails because the server moved on.

Read the response to the first successful send and compare it with the request that follows in the app. When the app takes a value out of a response and puts it into the next request, your client has to do the same. A captured header that worked once will fail on the second send even though every other byte is identical.

Cookies behave the same way. A server that rotates a session cookie invalidates the previous value, so a client that stores headers but ignores the cookie jar fails on the next call. Preserve the cookie jar across requests and let it update from each response.

Check for a sequence requirement

Some failures come from state rather than from the request. The endpoint may require a call that opens a session, registers a device, or creates a context object before it will answer. The first request in your test may have benefited from state the app established earlier, and the second send happened after that state changed.

  • Replay the flow prefix and then the target call. If the target works after the prefix and fails without it, ordering is enforced and your client has to reproduce the sequence.
  • Repeat the target call twice after a single prefix. If the second fails, the state is consumed per call rather than established once.
  • Compare the token in the target request with the token issued in the prefix response. A mismatch means the flow rotates credentials between steps.

What each result changes in the client

The test results map onto three client behaviours. A freshness check means generating a timestamp per request. A uniqueness check means generating a nonce per request and keeping it unique across retries. A rotation means reading a value from the previous response and threading it forward.

Retry logic has to respect all three. Retrying the same bytes on a network timeout is safe only when the request carries no one-time value, and a retry with a new nonce can duplicate a write. Build the client so that read calls regenerate per attempt and write calls follow the rules of the flow. Diagnosing 401 and 403 replay failures covers the status codes these checks produce, and stateful workflow reconstruction covers the flow around them. A Python client is where the rebuilt behaviour ends up.

Reviewed 28 September 2026 · SReverse research desk

Start your full APK reconstruction

Send the full APK

Projects start at $120. Choose WhatsApp or email, then attach the APK in the app that opens. We reply within one hour with the next step and send the fixed quote after review.

Want us to contact you?