GHSA-G936-7JQJ-MWV8

GHSA-G936-7JQJ-MWV8 is a critical-severity improper authentication vulnerability in github.com/almeidapaulopt/tsdproxy (go), affecting versions < 1.4.4-0.20260603142855-434819b4421e. It is fixed in 1.4.4-0.20260603142855-434819b4421e.

Check whether GHSA-G936-7JQJ-MWV8 affects your applications

Kodem tells you whether this CVE is present, reachable, and actually executing in your application, so you know if it matters.

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

Runtime intelligence. Only the CVEs that actually run in production.

Summary

TSDProxy: Internal proxy auth token forwarded to backend services enables management API escalation

Full technical description

Description

A vulnerability was discovered in TSDProxy where it forwards its internal per-process authentication token to all proxied backend services. When identityHeaders is enabled (the default), tsdproxy injects x-tsdproxy-auth-token into every upstream HTTP request alongside user identity headers. This token is the same secret used by the management HTTP server to trust forwarded Tailscale identity claims. A backend that receives this token can replay it from localhost to the management port with an arbitrary x-tsdproxy-id value, bypassing Tailscale authentication entirely.

The token is forwarded unconditionally: ProviderUserMiddleware always calls WhoisNewContext regardless of whether the user is authenticated. In the ReverseProxy.Rewrite function, WhoisFromContext returns ok=true even for zero-value Whois{} (unauthenticated or Funnel requests). The HeaderAuthToken is set for every request when identityHeaders=true.

The attack requires the backend to reach 127.0.0.1:8080. This holds in: (1) non-Docker deployments where tsdproxy and a backend run on the same host, (2) Docker host-network-mode containers, (3) containers sharing tsdproxy's network namespace.

Affected files

  • internal/proxymanager/port.go:123-132
  • internal/core/admin.go:160-182
// port.go: auth token forwarded regardless of user authentication state
if identityHeaders {
    if user, ok := model.WhoisFromContext(r.In.Context()); ok {
        // ok=true even for empty Whois{} stored by ProviderUserMiddleware
        r.Out.Header.Set(consts.HeaderAuthToken, core.ProxyAuthToken()) // token sent to backend
    }
}

// admin.go: management port trusts x-tsdproxy-id from localhost when token is valid
func ResolveWhois(r *http.Request) model.Whois {
    if IsLocalhost(r.RemoteAddr) {
        return model.Whois{
            ID: r.Header.Get(consts.HeaderID), // attacker-controlled after stealing token
        }
    }
    return model.Whois{}
}

Steps to reproduce

  1. Deploy tsdproxy on a host (non-Docker) with a backend at http://localhost:3000.
  2. Make a request through the Tailscale proxy. The backend receives x-tsdproxy-auth-token in the request headers.
  3. From the host, replay the token to the management API:
# Capture token from backend headers (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',''))")

# Replay from localhost to gain admin access
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

Credits

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

Sponsorship

This audit is from an AI-assisted research agent at sechub.dev. Running it on OSS projects is free for maintainers.

Impact

An attacker with code execution in any backend proxied by tsdproxy (on the same host) gains full management API control: restart or pause all proxied services (DoS), enumerate all proxy configurations and backend network topology, and trigger webhook deliveries (SSRF via configured webhook URLs).

The application does not adequately verify the identity of a user, device, or process before granting access. Typical impact: unauthorized access to functions or data reserved for authenticated parties.

GHSA-G936-7JQJ-MWV8 has a CVSS score of 9.0 (Critical). The vector is network-reachable, no privileges required, and no user interaction. A CVSS score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether this affects your application depends on whether the vulnerable code is present and reachable in your environment. A fixed version is available (1.4.4-0.20260603142855-434819b4421e); upgrading removes the vulnerable code path.

Affected versions

github.com/almeidapaulopt/tsdproxy (< 1.4.4-0.20260603142855-434819b4421e)

Security releases

github.com/almeidapaulopt/tsdproxy → 1.4.4-0.20260603142855-434819b4421e (go)

Kodem intelligence

Severity tells you how bad this could be in the worst case. It does not tell you whether you are exposed. Exploitability and impact are functions of runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A vulnerable package can sit in your dependency tree and never run.

Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter. Kodem's runtime-powered SCA identifies whether this CVE is reachable in your applications.

Already deployed Kodem?

See it in your environmentNew to Kodem? Get a demo →

Remediation advice

Remove HeaderAuthToken from the outgoing backend request, and guard identity-header injection on user.ID != "":

// port.go: only inject headers for actually authenticated users
if identityHeaders {
    if user, ok := model.WhoisFromContext(r.In.Context()); ok && user.ID != "" {
        r.Out.Header.Set(consts.HeaderID, user.ID)
        // HeaderAuthToken should NOT be forwarded to backends
    }
}

Frequently Asked Questions

  1. What is GHSA-G936-7JQJ-MWV8? GHSA-G936-7JQJ-MWV8 is a critical-severity improper authentication vulnerability in github.com/almeidapaulopt/tsdproxy (go), affecting versions < 1.4.4-0.20260603142855-434819b4421e. It is fixed in 1.4.4-0.20260603142855-434819b4421e. The application does not adequately verify the identity of a user, device, or process before granting access.
  2. How severe is GHSA-G936-7JQJ-MWV8? GHSA-G936-7JQJ-MWV8 has a CVSS score of 9.0 (Critical). This score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether it represents real risk in your environment depends on whether the vulnerable code is present and reachable.
  3. Which versions of github.com/almeidapaulopt/tsdproxy are affected by GHSA-G936-7JQJ-MWV8? github.com/almeidapaulopt/tsdproxy (go) versions < 1.4.4-0.20260603142855-434819b4421e is affected.
  4. Is there a fix for GHSA-G936-7JQJ-MWV8? Yes. GHSA-G936-7JQJ-MWV8 is fixed in 1.4.4-0.20260603142855-434819b4421e. Upgrade to this version or later.
  5. Is GHSA-G936-7JQJ-MWV8 exploitable, and should I be worried? Whether GHSA-G936-7JQJ-MWV8 is exploitable in your environment depends on whether the vulnerable code is present and reachable. A CVSS score is a worst-case rating; it does not account for your specific deployment, configuration, or usage patterns. Kodem, an Intelligent Application Security platform, uses runtime intelligence to show which vulnerabilities actually execute in production, so you can focus on the ones that represent real risk. Get a demo
  6. What actually determines whether GHSA-G936-7JQJ-MWV8 is exploitable, and how bad it is? Exploitability and impact are not fixed properties of a CVE. They depend on runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A high CVSS score on a dependency that never runs is not the same as real risk. Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter.
  7. How do I fix GHSA-G936-7JQJ-MWV8? Upgrade github.com/almeidapaulopt/tsdproxy to 1.4.4-0.20260603142855-434819b4421e or later.

Stop the waste.
Protect your environment with Kodem.