Skip to content

fix(vm): clamp attacker-controlled HTTP status codes to avoid a gateway crash - #519

Merged
taubyte0 merged 1 commit into
mainfrom
fix/http-status-code-clamp
Aug 8, 2026
Merged

taubyte0 merged 1 commit into
mainfrom
fix/http-status-code-clamp

Conversation

@samyfodil

Copy link
Copy Markdown
Contributor

What

net/http's WriteHeader panics for a status code < 100 or > 999. For a gateway-fronted substrate function, that panic runs on the gateway's response-forwarding goroutine (p2p/streams/tunnels/http Frontend's go func()), which has no net/http per-request recover — so an out-of-range code crashes the shared gateway process. It's reachable two ways:

  • a tenant's WASM function via the event ABI (eventHttpRetCode / eventHttpRedirect), and
  • any peer speaking the http-tunnel protocol (a bad Code in a headers frame).

Fix

  • eventHttpRetCode / eventHttpRedirect (pkg/vm-low-orbit/event/{code,redirect}.go) — reject a code outside 100..999 with errno.ErrorHttpWrite before it reaches WriteHeader / http.Redirect.
  • tunnel headersOp (p2p/streams/tunnels/http/handler.go) — clamp an out-of-range wire code to 500 before WriteHeader. This is the single choke point for any code arriving over the tunnel (a forwarded guest code or a raw peer).
  • Frontend goroutinerecover a residual panic on that untrusted-frame path into an error instead of crashing the process (defense in depth).

The predicate is byte-identical to net/http's own (code < 100 || code > 999), so 100 and 999 pass and nothing legitimate is over-clamped.

Tests

Regression tests for each site, each verified to fail on the pre-fix code with the exact WriteHeader panic:

  • pkg/vm-low-orbit/event/status_test.goeventHttpRetCode / eventHttpRedirect reject 0, 99, 1000, …; a valid 418 passes through.
  • p2p/streams/tunnels/http/status_test.goheadersOp clamps 0, 99, 1000, -1, 2000000 to 500; a valid 404 passes through.

The default no-retcode flow (body-only, implicit 200) and valid 100..999 codes are unchanged; the existing pkg/vm-low-orbit/tests wazy harness (incl. TestRedirect) stays green.

…ay crash

net/http's WriteHeader panics for a status code < 100 or > 999. For a
gateway-fronted substrate function, that panic runs on the gateway's
response-forwarding goroutine (p2p/streams/tunnels/http Frontend), which has no
net/http recover — so an out-of-range code crashes the shared gateway process.
It is reachable two ways: a tenant's WASM function via the event ABI, and any
peer speaking the http-tunnel protocol.

- eventHttpRetCode / eventHttpRedirect: reject a code outside 100..999 with
  errno.ErrorHttpWrite before it reaches WriteHeader / http.Redirect.
- tunnel headersOp: clamp an out-of-range wire code to 500 before WriteHeader —
  the single choke point for any code arriving over the tunnel.
- Frontend goroutine: recover a residual panic on that untrusted-frame path into
  an error instead of taking down the process (defense in depth).

Regression tests for each, verified to fail on the pre-fix code with the exact
WriteHeader panic. The default no-retcode flow and valid 100..999 codes are
unchanged (existing wazy harness still green).
@taubyte0
taubyte0 merged commit f65f9a4 into main Aug 8, 2026
23 checks passed
@taubyte0
taubyte0 deleted the fix/http-status-code-clamp branch August 8, 2026 19:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants