Files
OmniRoute/src
diegosouzapw df23f55c7b fix(relay): strip echoed credentials from relayed upstream responses
GHSA-9m72-44hg-w32g: the standalone bifrost relay copied ALL upstream response
headers via `new Headers(upstream.headers)` and returned non-2xx bodies verbatim,
while its TypeScript sibling routed non-2xx through parseUpstreamError +
buildErrorBody + stripStaleEncodingHeaders.

The relay sends `Authorization: Bearer ${BIFROST_API_KEY}` to the sidecar, so
anything the sidecar or a further upstream echoes back — that header, its own
`set-cookie`, an `x-api-key` — reached whoever holds the relay token. `set-cookie`
matters as much as the credential: it is a session, and a browser would store it
against our origin.

Both fixes:

  - New shared `stripSensitiveResponseHeaders()` in upstreamResponseHeaders.ts,
    built on the `filterUpstreamResponseHeaderEntries` helper that already
    existed there unused. Drops authorization / proxy-authorization / x-api-key /
    x-goog-api-key / api-key / cookie / set-cookie on top of the stale framing
    set. Applied to BOTH relay routes — the TS sibling copied headers wholesale
    too, so fixing only the reported one would have left the same hole next door
    and a second copy waiting to drift, which is the exact failure mode of
    GHSA-v7g9 and GHSA-qv45.
  - The bifrost route normalizes non-2xx through parseUpstreamError +
    buildErrorBody + sanitizeErrorMessage, reaching parity with the sibling and
    Hard Rule #12.

tests/unit/bifrost-relay-response-leak-9m72.test.ts — 6 tests, red before the
fix: the helper's behaviour (including that it does not mutate its input), plus
source guards pinning BOTH routes to the shared strip with a negative assertion
that the wholesale copy has not come back.

Reported by @skeletonsec.

Closes GHSA-9m72-44hg-w32g
2026-09-03 12:53:32 -03:00
..