Disclosure first: I work at Zscaler, and Tailscale is in the same broad world of "connect users and machines without the old VPN." So read this with that in mind. I'm writing about it anyway because the bug is a great example of a debate I have with customers every week.
What Happened
Tailscale has shipped version 1.104.4 to fix a set of issues in Tailscale SSH and tailscale serve, published as bulletins TS-2026-014 through TS-2026-017. Erica Windisch of Cyberdione Labs reported them in a write-up called "Tailworm," published October 23.
The main one: when a permitted SSH session forwarded a socket, tailscaled did the forwarding as root. It checked the socket path first, but a timing trick let an attacker swap the path after the check. In Windisch's testing, that turned an ordinary SSH session into a root shell through the Docker socket. Other issues let a permitted session crash tailscaled by exhausting memory, let a serve forward reach the local API, and, with TLS serve and multiple mounts, leak one mount's permission headers to another.
Credit Where It's Due
The conditions matter, so let's be fair about them:
- The attacker already needs a device your policy allows to SSH to the target, with forwarding allowed. This isn't "anyone on the internet gets root."
- Nobody has reported exploitation, and the proof of concept isn't public.
- The fix is the right kind of fix. Forwarding now runs as the logged-in user and relies on normal OS file permissions, instead of a root process trying to check paths correctly.
- Tailscale moved fast. Windisch published without coordinated disclosure, and Tailscale says it got the report about two hours before it went public.
Windisch called it "wormable." Tailscale disagrees and calls it lateral movement limited to connections policy already allows. Both are describing the same thing from different ends.
The Real Lesson
"Policy already allows it" is the part I'd underline. A lot of networks, mesh or not, treat "this device is allowed to reach that device" as the security decision. Once that's true, whatever the session can do is assumed to be fine. Tailworm is what happens when the session can do more than anyone meant it to.
That's the zero trust argument in one bug. Connectivity isn't authorization. The question isn't only "can user A reach server B?" It's "what exactly can A do on B, as whom, and what happens when that turns out to be more than we thought?" Every product in this space, Zscaler included, has to answer that, and every one of us will ship bugs where the answer is briefly wrong. The design goal is to make the blast radius small when it happens.
Windisch's own testing backs that up: single device-to-device rules and TPM-bound device keys limited how far it could spread. Tight policy did its job.
What To Do
- Update to Tailscale 1.104.4 or later on every node running Tailscale SSH (Linux and the open-source macOS build).
- Can't update yet? Set
TS_SSH_DISABLE_FORWARDING=1in thetailscaledservice environment and restart. SSH keeps working without forwarding. Check mode is still worth having on sensitive systems, but as The Hacker News points out, it doesn't stop these particular bugs, because the forwarding happens inside a session you already approved. - Running Headscale? It isn't patched as of its latest release, and forwarding can't be disabled by policy there. Windisch's advice is to treat every SSH grant as a root grant until that changes.
- Tighten your rules. Replace broad "this group can SSH everywhere" grants with specific device-to-device rules. That's good advice whatever you run.
- If a server might be compromised, delete the device at the control plane. Reimaging doesn't revoke its key.
Bottom Line
Tailworm isn't a story about a bad product. It's a story about what "allowed" should mean. Reaching a server and owning a server are different things, and your access model, whatever vendor builds it, should keep them different.
Sources: The Hacker News, Help Net Security, and Tailscale security bulletins