Serve deletes client-supplied `Tailscale-User-Login` (and similar) headers
before setting its own. However, `http.Header.Del` only matches the exact
canonical name. A client could send Tailscale_User_Login instead, which
was passed through to the backend.
For Go (and some other) backends, that's not an issue, but backends that
map headers to CGI-style variables (HTTP_TAILSCALE_USER_LOGIN) treat
both names the same. Thus, for Funnel requests (or tagged nodes), where
serve sets no identity headers, the backend could trust the spoofed
value. The same applies to Tailscale-App-Capabilities.
This fixes the issue by also deleting any header whose name matches
case-insensitively after replacing '_' with '-'.
This is similar to how other projects do this:
- Django drops them: https://www.djangoproject.com/weblog/2015/jan/13/security/
- nginx does not allow them by default: https://nginx.org/en/docs/http/ngx_http_core_module.html#underscores_in_headers
- Puma had a CVE and now drops them: https://nvd.nist.gov/vuln/detail/cve-2024-45614Fixestailscale/corp#50821
Signed-off-by: Andrew Dunham <andrew@tailscale.com>
Exposes a local port on the tailnet under a chosen hostname. Raw TCP by
default; --http or --https reverse-proxy with Tailscale-User-* identity
headers from WhoIs, matching tailscaled's serve header conventions.
Useful as a one-shot to put a dev server on the tailnet.
Fixes#19467
Change-Id: I79f63cfbbedf7e40cf0f1f51cbae8df86ae90cdf
Signed-off-by: Fernando Serboncini <fserb@tailscale.com>