deniz.in

Markets

Weather

Loading weather

· via dev.to (home feed)

Tailscale fixes four Tailworm SSH and Serve flaws in v1.104.4 that enabled root-level access

Tailscale has published four security bulletins with fixes in v1.104.4 for the Tailworm flaws in Tailscale SSH and Serve, where a root daemon checked paths as the connecting user and then acted as root.

Tailscale fixes four Tailworm SSH and Serve flaws in v1.104.4 that enabled root-level access

Tailscale released version 1.104.4 on October 28, closing four vulnerabilities disclosed under the name "Tailworm" and documented in security bulletins TS-2026-014 through TS-2026-017. According to a dev.to analysis of all four bulletins, three of the bugs share a single root cause: tailscaled runs as root, it checked permissions as though it were the connecting user, and then it acted with root's authority.

The timeline was compressed. Concerns about Tailscale SSH circulated on October 23, prompting an investigation with external specialists; the researcher delivered the report on the morning of Saturday, October 24 and published it two hours later. Tailscale posted interim mitigations on October 26, followed by its findings post, written by Mike Shaver, and the four bulletins on October 28. The dev.to author verified on GitHub that v1.104.4 shipped that day at 01:05 UTC.

Root-level socket forwarding (TS-2026-014)

The most severe bulletin concerns Tailscale SSH's TCP and Unix socket forwarding. The SSH server runs inside tailscaled, which runs as root, and it validated Unix socket paths lexically — by inspecting the path string — before performing the operation as root. The bulletin lists three consequences: privileged dials through local forwarding (ssh -L) reaching sockets the local user could never touch; socket replacement through remote forwarding (ssh -R), unlinking root-owned sockets to bind others in their place; and a race condition in which the kernel re-resolves the path after validation, so the checked path is not necessarily the path that gets used. The bulletin names the Docker socket and the tailscaled local API socket as the targets that matter; either amounts to control of the machine. The fix is architectural rather than a harder check: forwarding is now performed on behalf of the authenticated user instead of as root.

Serve flaws (TS-2026-016)

tailscale serve, which proxies tailnet connections to local Unix socket backends, had two weaknesses. TCP forwards to Unix sockets had no guard and dialed the target as root, letting raw bytes be fed into the local API socket using the daemon's own permissions — an impact the bulletin describes as full node takeover. Separately, the symlink check for HTTP proxies ran at configuration reload rather than per dial, so replacing a benign backend path with a symlink after reload bypassed the guard entirely. The fixes restrict TCP forwards to the tailscaled socket and revalidate the backend target on every dial.

Memory exhaustion and capability leaks

TS-2026-015 is a denial-of-service issue. An authenticated peer could send continuous window-change messages and environment-variable appends within a session, causing unbounded memory growth in tailscaled, with allocations persisting after the peer disconnected. Sustained pressure would let the OOM killer terminate tailscaled, and since the daemon carries the node's entire networking state, every Tailscale connection on that node dies with it. Session memory is now bounded and released on disconnect.

TS-2026-017 is a concurrency bug in Serve over HTTP/2. All streams on a connection shared a single serveHTTPContext: the handler wrote AppCapabilities per request while the reverse proxy read them through a shared hook, so capabilities from one mount could bleed into a request for another. Applications that authorize peers by inspecting Tailscale-App-Capabilities — which the dev.to write-up notes is the documented approach — could make that decision using another application's capabilities. Capabilities are now derived from a per-request context.

The original researcher report also carried five findings for Serve and Funnel: three were genuine bugs and are fixed in 1.104.4, while two described behavior working as designed. A sixth, in the unreleased Conn25 app connectors, was already known to Tailscale; the stable connectors are unaffected.

Scope and limits

None of the four issues is reachable by an unauthenticated attacker, as both Tailscale and the dev.to analysis emphasize. Exploitation requires a foothold on an authorized peer, SSH access already permitted by policy, and specific conditions such as forwarding enabled or Serve configured with Unix backends. Despite the name, "Tailworm" is not a worm: there is no self-replication, only lateral movement along connections a policy already allows, with the privilege boundary on the destination machine drawn wrong.

Why it matters

The premise of Tailscale SSH's per-user mapping is that a peer admitted under one identity does not gain another's privileges, and these bugs broke exactly that promise. The underlying pattern is broadly instructive: a privileged daemon that validates carefully and then acts with ambient authority the user never had. Tailscale's response is the part worth copying — the fixes drop privilege rather than add validation, forwarding as the user, revalidating at dial time and keeping capabilities per request.

What to do

Upgrade to v1.104.4 or later; all four bulletins close with that instruction. Operators who cannot upgrade immediately and depend on Tailscale SSH can set TS_SSH_DISABLE_FORWARDING=1 in the tailscaled service environment and restart the service, which disables forwarding — and TS-2026-014's route to root — without turning SSH off entirely. The dev.to write-up also recommends reviewing the SSH section of the policy file, since every one of these bugs needed a policy-permitted connection to stand on.

  • #tailscale
  • #ssh
  • #security
  • #networking
  • #vulnerabilities

Related posts