Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion specs/runtime-driver-contract.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,13 +109,14 @@ A denial answers `403` for a destination off the allowlist and `400` for a reque
- Pipelining: the broker never forwards bytes that follow the first framed request unless it has judged them as a new request. This holds for bytes that arrive before the first response too.
- Request smuggling: ambiguous framing is refused, never forwarded or reinterpreted. That covers `Content-Length` together with `Transfer-Encoding`, duplicate or differing `Content-Length` values, a `Transfer-Encoding` whose final coding isn't `chunked`, and obs-fold or whitespace before a header colon.
- Upgrade: the broker refuses a plain request with an `Upgrade` header (WebSocket or `h2c`), or it treats the `101` reply as a new tunnel and judges it like CONNECT. The connection never becomes an unjudged byte pipe.
- Malformed host: a present `Host` value must contain one nonempty host with an optional port, after trimming surrounding spaces and tabs. A comma-separated list, userinfo, path, query, fragment, internal whitespace, control byte, invalid percent escape, or malformed IP literal gets `400`. Names use ASCII URI registered-name syntax with valid percent escapes. Commas are refused. IPv6 and IPvFuture literals require brackets. Ports follow the numeric rule above. This applies to origin-form, absolute-form, and CONNECT requests before allowlist evaluation: the connection closes and nothing is forwarded. A valid host off the allowlist still gets `403`. The [reference broker and tests](https://github.com/tbhb-dev/agent-orchestration-poc.internal/tree/c42c05fd/wiki/proposals/2026-10-07T2010Z-RFC-37-egress-credential-identity-spikes/findings/r8-container-egress/scripts) cover this rule for [internal #82](https://github.com/tbhb-dev/agent-orchestration-poc.internal/issues/82).
- Duplicate host: every request with more than one `Host` header gets `400`, even when the values agree. Header names are counted case-insensitively. This covers CONNECT as well as origin-form and absolute-form HTTP. The connection closes and nothing is forwarded.
- Mismatched host: if the `Host` header names a different host or port than the absolute-form authority or CONNECT target, the request gets `400`.
- CONNECT after a plain request on one connection is dropped, and nothing is forwarded. The connection closes after the one plain request, so the CONNECT is never judged there. A CONNECT the client resends on a new connection is judged like any other.
- Nested CONNECT: when a tunnel's first client bytes are a plaintext `CONNECT`, the broker closes both sides and forwards none of them. The `200` has already gone out, so this denial is a close, not a `403`.
- Bytes that aren't HTTP, such as the raw TLS ClientHello Claude Code sent into the socket in RFC-37 run 8, close the connection without any response, not a `400`, and nothing is forwarded.

RFC-37 run 11 found that `sandbox-runtime` 0.0.79 reuses one proxy connection across hosts. Run 8's stand-in broker judged only the first request on a connection, so it forwarded a later request to a host off its allowlist ([internal #72](https://github.com/tbhb-dev/agent-orchestration-poc.internal/issues/72)). The reference stand-in broker is at [commit `f074931d`](https://github.com/tbhb-dev/agent-orchestration-poc.internal/blob/f074931d/wiki/proposals/2026-10-07T2010Z-RFC-37-egress-credential-identity-spikes/findings/r8-container-egress.md#later-finding-the-broker-judged-only-the-first-request-on-a-connection). It refuses `Upgrade`, a plaintext CONNECT as a tunnel's first bytes, a mismatched or duplicate `Host`, duplicate `Content-Length`, `Content-Length` with `Transfer-Encoding`, obs-fold, and an allowed host on an unlisted port. It never forwards bytes after one framed request. Its socket tests check what the upstream received in each of those cases. They also cover a second request on one connection, pipelining, and a CONNECT after a plain request. The findings section linked above holds the reproduction.
RFC-37 run 11 found that `sandbox-runtime` 0.0.79 reuses one proxy connection across hosts. Run 8's stand-in broker judged only the first request on a connection, so it forwarded a later request to a host off its allowlist ([internal #72](https://github.com/tbhb-dev/agent-orchestration-poc.internal/issues/72)). The reference stand-in broker is at [commit `c42c05fd`](https://github.com/tbhb-dev/agent-orchestration-poc.internal/blob/c42c05fd/wiki/proposals/2026-10-07T2010Z-RFC-37-egress-credential-identity-spikes/findings/r8-container-egress.md#later-finding-the-broker-judged-only-the-first-request-on-a-connection). It refuses `Upgrade`, a plaintext CONNECT as a tunnel's first bytes, a mismatched, duplicate, or malformed `Host`, duplicate `Content-Length`, `Content-Length` with `Transfer-Encoding`, obs-fold, and an allowed host on an unlisted port. It never forwards bytes after one framed request. Its socket tests check what the upstream received in each of those cases. They also cover a second request on one connection, pipelining, and a CONNECT after a plain request. The findings section linked above holds the reproduction.

Residual risk, recorded in those findings as inference: the broker checks only a tunnel's opening bytes, and it can't parse a tunnel. An inner CONNECT later in an opaque tunnel is forwarded to the allowed endpoint, and so are any request inside TLS and `Host` or SNI routing at a shared front end such as a CDN. So the allowlist must not list forward proxies or open relays. It may list a destination behind a shared front end only if every site that front end routes to is acceptable, until a broker that decrypts the tunnel's TLS can judge inner requests. This repository has no broker yet. [Issue #131](https://github.com/tbhb-dev/agent-hypervisor/issues/131) tracks the tests the broker needs before it merges.

Expand Down
Loading