Repository navigation
fix(scanoss): drop the API key on a cross-host redirect - #123
Conversation
net/http strips only its own auth and cookie headers when a redirect changes host, so a 3xx from the API sent x-api-key, x-Session and every Config.Headers entry to the host it named. New now wraps the HTTP client, the SDK's or the caller's, in a copy whose CheckRedirect deletes those headers once a redirect leaves the API's host:port. Same-host redirects keep them, and a caller's own CheckRedirect still runs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The redirect check compared only URL.Host against the first request. An https to http redirect on the same host kept x-api-key and sent it in clear, and a chain that left the API and came back got the key again, because net/http re-copies the original headers on every hop. Keep the identifying headers only while every hop shares the API's hostname (case-insensitive) and effective port, allowing an http to https upgrade on the default ports. An explicit :443 now counts as the same origin. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Independent review: PASS+NOTES (head 287cfa5) The PR handled the plain cross-host case, but two leaks remained. Both are fixed in 287cfa5.
The headers are now kept only while every hop in the chain shares the API's hostname (case-insensitive) and effective port.
Dismissed: transport re-injection. Note: a caller-supplied RoundTripper that adds its own credentials is outside what the SDK can strip. CI is all green and mergeStateStatus is CLEAN. |
Why
net/http strips only its own auth and cookie headers (
Authorization,Cookie,Proxy-Authorization, ...) when a redirect changes host. It copies every other header to the next hop. The SDK puts the API key inx-api-keyandx-Session, and callers put identifying headers such asX-Scanoss-Client-InstanceinConfig.Headers. So a 3xx from the API, whether from a misconfigured upstream or from anhttp://API URL under MITM, sent the customer's key and instance id to whatever host it named. This is finding M8 of the client-identification security audit.Scope
Newwraps the HTTP client in a shallow copy whoseCheckRedirectdeletesx-api-key,x-Sessionand everyConfig.Headersname once a redirect leaves the API'shost:port.Config.HTTPClientalike, so the fix sits in one place. The caller's client is not mutated, and its ownCheckRedirectstill runs after the strip. With none, the copy keeps net/http's 10-hop limit.Tradeoffs
Authorization, and a hop that needs the key fails with a 401 instead of leaking it.Authorization. A different port can be a different service.api.example.comredirecting toeu.api.example.comloses the key, which is the safe default.Blast Radius
Only requests that get a redirect change behavior. Same-host redirects keep every header. No public API change.
Verification
TestCrossHostRedirectDropsIdentity(SDK client and caller's client),TestSameHostRedirectKeepsIdentityandTestRedirectHonorsCallersPolicyuse twohttptestservers and a 307.X-Api-Key = "secret" reached the other host, and the same forX-SessionandX-Scanoss-Client-Instance.go vet ./...,go test ./...and golangci-lint v2.14.0 (built with go1.27.3) pass with 0 issues.Release
Needs a v0.14.1 release after merge. Earnie pins scanoss.go v0.14.0. Earnie's identity transport strips the same headers on its own, so the Earnie fix does not wait on this release, but Earnie should bump once v0.14.1 is out.
🤖 Generated with Claude Code