Skip to content

Out-of-Band Testing

A whole class of vulnerabilities, server-side request forgery, XML external entities, blind injections, LLM-driven HTTP calls, never returns evidence in the immediate HTTP response. The exploit fires asynchronously, from a different process, sometimes seconds later. To detect those reliably, Escape uses out-of-band (OOB) testing: payloads that, if vulnerable, force the target to call back to a public collector we control. This page explains how that collector works, which tests use it, and what you need on your side to keep it reachable.

What "Out-of-Band" Means Here

Most DAST checks are in-band: payload goes in, the response is inspected for evidence, the verdict is decided synchronously. That approach under-detects entire bug classes:

  • Blind SSRF, where the application fetches the URL but never surfaces the response body to the client.
  • XXE, where an external entity is resolved during XML parsing on the server, with no echo back into the response.
  • Stored or reflected XSS that exfiltrates via an attacker-controlled asset URL rather than executing inline.
  • LLM-driven SSRF and command injection, where the model issues tool-calls or shell-outs that complete after the streaming response closes.

OOB testing flips the question: instead of asking "did the response prove it?", we ask "did the target reach a server only the attacker controls?". A confirmed callback is unambiguous evidence that the payload was processed and that the target initiated outbound traffic.

The Escape OOB Collector

Escape operates a public callback service at ssrf.tools.escape.tech. It accepts HTTP and HTTPS on ports 80 and 443, records every request that reaches it, and exposes those recordings through a small read API. The implementation is open source at github.com/Escape-Technologies/http-request-catcher.

Per-probe Identifiers

Every payload Escape emits includes a unique identifier baked into the URL path, so callbacks can be attributed to the exact scan, check, and variant that produced them. For LLM checks, the tag follows the shape llm-<check>-<variant>-<uuid12>; for the BLST SSRF check, it's a freshly minted UUID per probe. The full callback URL looks like:

https://ssrf.tools.escape.tech/<scan-or-probe-id>/<arbitrary-suffix>

The collector doesn't care about the suffix; the identifier in the path is what makes correlation deterministic. There's no shared bucket: two concurrent scans, two concurrent probes within the same scan, all land in disjoint paths.

Capture Specifier

When the collector itself responds to an HTTP request, the response body contains the literal capture specifier H@k3d! (and a base64-encoded form, eyJtZXNzYWdlIjoiSEBrM2QhIn0=). That second signal lets Escape confirm vulnerabilities even when the application echoes the fetched content back into its own response, without needing to round-trip through the collector's read API.

Read API

For a given probe identifier, Escape polls:

curl -s https://ssrf.tools.escape.tech/<probe-id>

The response is shaped like:

{
  "data": [
    { "method": "GET", "headers": {}, "ip": "...", "timestamp": "..." }
  ]
}

A non-empty data array confirms the callback. An unreachable collector (network error, 5xx) is treated as inconclusive, not negative, so infrastructure failures don't silently turn into "no vulnerability found".

Bounded Async Polling

Some payloads land synchronously, where the target fetches the URL inside the request that injected it. Others land seconds later, when an LLM agent processes a tool-call after streaming completes, or when a queued worker picks up the parsed XML. Escape polls the collector four times per probe with backoff (immediately, then +1s, +3s, +6s, for a worst-case wait of about 10 seconds), which covers typical async exploit windows without dragging the scan.

Tests That Use the Collector

Check What it sends
SSRF URL bypasses with https://, http://, scheme-less, and gopher:// payload variants
XXE An XML external entity declaration pointing at the collector
Stored XSS Image and anchor payloads with src / href set to the collector
LLM SSRF Prompts asking the model to fetch a per-probe URL on the collector
LLM command injection Prompts asking the model to invoke curl or subprocess against the collector

Cloud-metadata SSRF (http://169.254.169.254/latest/meta-data) and third-party reachability (https://www.google.com) are confirmed in-band against well-known capture markers rather than via the collector, but they belong to the same SSRF check.

The httpbin Companion

Alongside the collector, Escape runs a public httpbin instance at httpbin.tools.escape.tech. This is not a request catcher: it's a stable HTTP echo server we use where a check needs a known-safe target rather than a callback log. Two production examples:

  • OAuth redirect URIs in authentication recipes: see Expert authentication, where https://httpbin.tools.escape.tech/get stands in as a fixed redirect URI for procedural OAuth flows that need a 200 response and a deterministic URL to read.
  • Auth scheme fixtures: endpoints like https://httpbin.tools.escape.tech/basic-auth/user/pass give Escape's authentication detection a reliable target that returns a real WWW-Authenticate: Basic challenge.

If a check needs to prove "an HTTP request happened", it goes to ssrf.tools.escape.tech. If a check needs to prove "we can speak to a predictable HTTP server", it goes to httpbin.tools.escape.tech.

Firewall and Egress Requirements

The collector only confirms vulnerabilities your application can actually reach. If outbound traffic from your application to ssrf.tools.escape.tech:80 and :443 is blocked at the egress firewall (WAF, proxy, NAT gateway), real SSRF and XXE bugs will go undetected, and Escape will report no callback even when the bug is present.

Allow ssrf.tools.escape.tech on TCP 80 and 443 from any environment Escape scans. The full egress allow-list and current IP details, including a curl connectivity test, lives at Firewall configuration. including a curl connectivity test, lives at Firewall configuration.

Warning

OOB-confirmed checks fail closed: if the collector is unreachable from your application, Escape treats the result as "couldn't tell" rather than "vulnerable". You won't get false positives, but you also won't catch real OOB-only vulnerabilities until egress is open.

Privacy and Data Handling

The collector logs metadata about the requests that reach it (method, headers, source IP, timestamp, body when present) so Escape can prove the callback happened and surface it in your finding evidence. Two properties keep that bounded:

  • Per-probe identifiers scope every recorded request to a single scan run, so callbacks from one customer never appear in another's findings.
  • No customer secrets are sent through the collector by design. Payloads carry inert markers (a probe ID and the capture specifier), not credentials, tokens, or PII from your application.

If a payload that reaches the collector contains data your application should not have leaked (a session cookie reflected back into a URL, a token logged into a header), that data appears in the finding evidence because it is itself the vulnerability you need to see.

Roadmap

The current collector is HTTP-only. We plan to extend OOB confirmation across more channels and detection modes:

  • DNS-based OOB for blind SQL injection and SSRF behind egress proxies that block raw HTTP to the public internet but still resolve arbitrary names.
  • RCE-via-callback templates in the AI Pentesting agent, so blind command execution can be confirmed the same way as blind SSRF.
  • Customer-hosted collectors for environments that cannot allow egress to ssrf.tools.escape.tech and want to run a private http-request-catcher on their own infrastructure.

These are not shipped yet. Today's coverage is the HTTP collector and the checks listed above.