OutOfBits
The OAST listener that talks back.
DNS & HTTP callbacks captured. Mutate the response with Python. Sandboxed. Audited. Replayable against any past interaction.
Platform vital signs · last 30 days
What you can do
Confirm a blind callback
Generate a one-shot host, plant the URL, watch it land.
# in any vulnerable parameter: http://a8x2.ooast.net/probe # on /interactions (live, ~1s after firing): GET /probe 200 OK DNS A query NOERROR
Mutate the response
Sandboxed Python that runs on every callback. Change status, add headers, rewrite the body.
def handle_http(ctx): if ctx.request.path == "/admin": ctx.response.status_code = 401 ctx.response.headers["WWW-Authenticate"] = \ 'Basic realm="x"' return ctx
Pipeline & audit
Compose modifiers in order. Per-stage input/output snapshots — see exactly what each step did.
pipeline "tarpit" · http ├─ add-trace-header ok 12 ms ├─ canned-401 ok 3 ms └─ log-source-ip ok 5 ms on_error: stop total: 20 ms
Persist state between callbacks
Per-modifier ctx.state and per-user ctx.shared. DNS rebinding in four lines — nothing else in the OAST space does this.
def handle_dns(ctx): n = ctx.state.get("count", 0) + 1 ctx.state["count"] = n ip = "127.0.0.1" if n % 2 else "127.0.0.2" ctx.response.answers = [{ "name": ctx.request.qname, "type": "A", "ttl": 0, "data": ip, }] return ctx
Triage with tags new
Confirmed vs. dupe vs. background noise — tag interactions and filter the list down to what matters. Free-text notes per row for the story you'll forget by tomorrow.
# on /interactions: 17:42:03 dns a8x2 a8x2.ooast.net [confirmed][ssrf] 17:42:11 http a8x2 GET /probe [dupe] [note] 17:43:01 dns a8x2 noise.a8x2... [background]
Webhooks new
Skip the polling. Point a webhook at your own URL; we push a signed JSON envelope on every captured callback. Per-host or firehose, with HMAC + retries + auto-disable.
# headers on every delivery: X-OOB-Event: interaction.captured X-OOB-Delivery: 42 # idempotency key X-OOB-Timestamp: 1748817225 X-OOB-Signature: sha256=a8d2... # HMAC over "<ts>.<body>"
Five layers of sandbox.
Modifiers are arbitrary user code. So they run in a fresh subprocess, blocked from doing anything they shouldn't.
- AST allowlist — no
import, dunders,open,eval. - Restricted builtins — only a curated subset of
__builtins__. - rlimits — 1s CPU · 100 MiB · NPROC=0 · 32 FDs.
- seccomp — networking, ptrace, mount, kexec, modules — all EPERM.
- Landlock — kernel-enforced filesystem isolation. No paths.
Want the full picture? User guide.
Built by Carl Sampson.