GHSA-pqg7-v6wh-3pfp: TsDProxy: X-Forwarded-For header injection allows IP spoofing in proxied requests to backend services
Description
The HTTP reverse proxy handler in tsdproxy does not strip the X-Forwarded-For (or X-Real-IP) header from incoming requests before calling r.SetXForwarded(). This allows an authenticated Tailscale user to inject arbitrary X-Forwarded-For values that are forwarded verbatim to backend services.
// internal/proxymanager/port.go -- Rewrite function
Rewrite: func(r *httputil.ProxyRequest) {
r.SetURL(pconfig.GetFirstTarget())
r.Out.Host = r.In.Host
// Strips tsdproxy identity headers (correct)
r.Out.Header.Del(consts.HeaderID)
r.Out.Header.Del(consts.HeaderRemoteUser)
r.Out.Header.Del(consts.HeaderXForwardedUser)
// ... other identity headers deleted ...
// X-Forwarded-For is NOT deleted before SetXForwarded!
// X-Real-IP is NOT deleted at all!
r.SetXForwarded() // APPENDS client IP to attacker-controlled XFF list
},
Per Go's httputil.ProxyRequest.SetXForwarded() documentation:
If the inbound request has an existing X-Forwarded-For header, SetXForwarded appends the inbound request's remote address to the list.
Result when attacker sends X-Forwarded-For: 127.0.0.1:
- Backend receives: X-Forwarded-For: 127.0.0.1, <real-tailscale-client-ip>
- If backend reads first element as "original client", attacker appears as 127.0.0.1
X-Real-IP is not handled at all -- if the attacker sets X-Real-IP: 127.0.0.1, it is forwarded to the backend verbatim without any overriding or stripping.
Many backend applications trust the first element of X-Forwarded-For (or X-Real-IP) for:
- IP-based access control (admin panels restricted to 127.0.0.1)
- Rate limiting tied to source IP
- Audit logging
- Geo-blocking or network-segment restrictions
This is particularly impactful in tsdproxy's intended use case where the backend service is only accessible through tsdproxy -- making the proxy's header handling the sole enforcement point.
CVSS
CVSS v3.1: AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:H/A:N = 7.7
Severity
High
Affected Code / Files
- internal/proxymanager/port.go -- newPortProxy Rew
Details
Original advisory: https://github.com/advisories/GHSA-pqg7-v6wh-3pfp
More from GitHub Security Advisories
- mediumGHSA-jr6p-8pjj-mfx6: Capsule has an incomplete fix of CVE-2026-22872: TenantResource RawItems and Generators s…2026-07-31
- mediumGHSA-68cj-mvg9-rgm2: Capsule: CapsuleConfiguration NodeMetadata regex fields lack webhook validation, allowing…2026-07-31
- mediumGHSA-ff84-5f28-78qj: re2: Out-of-bounds heap read in `exec`/`test`/`match` via attacker-influenced `lastIndex`…2026-07-31
- mediumGHSA-6hxr-mr5r-9836: re2: Global `String.prototype.match` with an empty-matchable pattern never advances → inf…2026-07-31
- mediumGHSA-x83g-979r-f5fh: Sylius Mollie Plugin has unauthenticated IDOR that leaks order token and customer PII2026-07-31