a429456987
release / release (push) Successful in 23s
The fetch service only stripped the four X-Weircon-* control headers, so any forwarding header injected upstream (X-Forwarded-For, X-Real-IP, Via, CDN client-IP headers, …) passed straight through to the target — leaking the caller's IP and proxy chain. - Replace stripWeircon with stripIdentifying: removes the control headers plus all standard forwarding/origin-IP headers, with a prefix sweep for any vendor-specific X-Forwarded-* variant. - NPM advanced.conf clears the same headers (defense in depth). - Add TestStripIdentifying covering removal + survival of legit headers. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
59 lines
1.3 KiB
Go
59 lines
1.3 KiB
Go
package main
|
|
|
|
import (
|
|
"net/http"
|
|
"testing"
|
|
)
|
|
|
|
func TestStripIdentifying(t *testing.T) {
|
|
h := http.Header{}
|
|
|
|
// Headers that MUST be removed before the request reaches the target.
|
|
removed := []string{
|
|
"X-Weircon-Random-Ip",
|
|
"X-Weircon-Proxy-Id",
|
|
"X-Forwarded-For",
|
|
"X-Forwarded-Host",
|
|
"X-Forwarded-Proto",
|
|
"X-Forwarded-Port",
|
|
"X-Forwarded-Custom-Vendor", // caught by prefix sweep
|
|
"X-Real-Ip",
|
|
"Forwarded",
|
|
"Via",
|
|
"Cf-Connecting-Ip",
|
|
"True-Client-Ip",
|
|
"Fastly-Client-Ip",
|
|
"X-Original-Forwarded-For",
|
|
"X-Client-Ip",
|
|
}
|
|
for _, k := range removed {
|
|
h.Set(k, "leak")
|
|
}
|
|
|
|
// Headers a crawler legitimately sets — these MUST survive untouched.
|
|
kept := map[string]string{
|
|
"User-Agent": "my-crawler/1.0",
|
|
"Cookie": "session=abc",
|
|
"Accept": "text/html",
|
|
"Accept-Language": "en-US",
|
|
"Referer": "https://example.com",
|
|
"X-Forward": "not-a-forwarding-header", // does not match "X-Forwarded" prefix
|
|
}
|
|
for k, v := range kept {
|
|
h.Set(k, v)
|
|
}
|
|
|
|
stripIdentifying(h)
|
|
|
|
for _, k := range removed {
|
|
if got := h.Get(k); got != "" {
|
|
t.Errorf("expected %q to be stripped, still present: %q", k, got)
|
|
}
|
|
}
|
|
for k, want := range kept {
|
|
if got := h.Get(k); got != want {
|
|
t.Errorf("expected %q to survive as %q, got %q", k, want, got)
|
|
}
|
|
}
|
|
}
|