fix(shared,host-service): constrain proxy/tunnel upstream before attaching the host secret (GHSA-8qrv-53x7-hh4p, GHSA-h894-rmgp-jv6m)
Summary
The sandbox gate built its upstream from the request path, so a // path forwarded the workspace host secret to an arbitrary origin; the tunnel client could send HOST_SERVICE_SECRET to a relay-selected origin. A bypassable relay-side check was also found.
Fix (well-factored)
New shared packages/shared/src/upstream-url.ts guard constrains the origin before the secret is attached; gate, tunnel client, and the relay's bespoke check all consolidated onto it.
Proof
Gate exploit forwarded the real Bearer secret to https://evil.example pre-fix; blocked post-fix. Tests: gate 2 pass/5 fail → 8/0, tunnel 4 fail → 19/0, shared 1114 pass; typecheck 8/8; biome + sherif clean. One client-side reachability sub-claim is PARTIAL. Pre-existing unrelated failure verified on a clean tree.
Write-up: https://app.superset.sh/page/p1-b-host-secret-disclosure-to-an-attacker-selecte-yhe08o
Merge note
Squash-merge only (earlier commits held local repro artifacts, now untracked).
Summary by cubic
Fixes a host-secret disclosure where a crafted request target could move the upstream origin and carry the host secret with it, in the sandbox gate (GHSA-8qrv-53x7-hh4p) and the tunnel client (GHSA-h894-rmgp-jv6m).
- The gate resolved its upstream via
new URL(path, claims.target), so a protocol-relative//path replaced the ticket target and sent the workspace secret to the attacker's host; the tunnel client concatenated a relay-supplied path onto the loopback origin, where a leading@turned that origin into userinfo andHOST_SERVICE_SECRETfollowed, past the relay'sstartsWith("//")check, which missed tab- and newline-smuggled protocol-relative forms. - All three sites now use the shared
resolveUpstreamUrl/isOriginFormTargetinpackages/shared/src/upstream-url.ts, which refuse anything not in origin-form and re-check the resolved origin against the base before any secret is attached; refusing call sites return 400 instead of proxying.
Summary by CodeRabbit
- Bug Fixes
- Requests with malformed or off-origin paths are now rejected instead of being forwarded to an unintended destination.
- Invalid ticket targets now receive a clear 400 response.
- Tests
- Added coverage for request forwarding, WebSocket handling, and invalid path and target scenarios.