Tailworm: the Tailscale bugs that only bite if you let them in first
Eleven Tailscale and headscale findings, most of which need Tailscale SSH switched on and a machine already compromised, plus the checks that tell you whether yours is exposed.
If you use Tailscale to reach a couple of VPS boxes, the word "worm" in a security headline is not what you want with your Sunday coffee. The Tailworm report, published on 24 October by Erica Windisch of Cyberdione Labs, lists 11 findings against the Tailscale client v1.104.2 and the self-hosted headscale control server v0.29.5, and none of them has a CVE or a fix in any released version yet. One fix has been merged into Tailscale's source code, but it hasn't shipped in a release. Having read the report in full and checked the main claims against the Tailscale and headscale source, our view is that the findings are real but the headline oversells them for most readers. The serious ones need Tailscale SSH switched on, plus an attacker who already controls one of your machines.
What Tailworm actually found
Most of the report concerns Tailscale SSH, the optional SSH server built into tailscaled. Unlike OpenSSH, which drops to your user account before it handles any port forwarding, tailscaled runs as root and does Unix-socket forwarding (ssh -L and ssh -R pointed at a socket path) as root too. The researcher says a user with an ordinary, unprivileged Tailscale SSH session can therefore talk to root-only sockets such as Docker's API, replace sockets that belong to system services, and use a timing race to get past the list of directories forwarding is meant to stay within. In her lab, she says, that meant root on the target machine, the capture of a key that enrols new devices, and an extra machine joined to the tailnet under the victim's identity.
Our own read of the v1.104.2 source supports the mechanism: the path checks and the later file operations happen as separate steps in the root process, which is the same class of bug Dropbear fixed as CVE-2025-14282 by dropping privileges first. The lab timings, including the claimed sub-second hop from machine to machine, have not been reproduced by anyone else.
The rest is narrower:
- App connectors (the experimental conn25 mode): a device entitled to use one app can, according to the researcher, make the connector forward traffic to any destination, including the cloud metadata service and the connector's own LAN. Windisch ranks this second only to the SSH escalation, calling it "the one that really worries me" in terms of impact, but it only matters if you have deployed app connectors in conn25 mode, mostly through the Kubernetes operator.
- headscale: an unauthenticated attacker who can reach the server can run its memory up or flood the registration cache so that new devices can't join, which is a denial of service and nothing more.
- DERP client: a hostile relay can exhaust a client's memory, which needs someone able to change your relay map.
tailscale serve: a TCP forward pointed attailscaled's own socket hands peers its admin API (this only happens if you configure it yourself), and a race let app permissions leak between mounts on one HTTP/2 connection.
The researcher's "worm" is the SSH chain run automatically from one machine to the next. It can only reach machines your SSH policy already lets the compromised device log in to, which the report itself concedes.
flowchart TD A[Foothold on an approved device
malware, stolen laptop, supply chain] --> B[List peers
quieter on hosted Tailscale] B --> C{SSH policy allows
this device to that one?} C -->|No| Z[Stops here] C -->|Yes, accept or check passed| D[Tailscale SSH session
device identity, no password] D --> E{Forwarding allowed
for this rule?} E -->|No| Z2[Session without socket forwarding] E -->|Yes, always for headscale accept| F[Socket forwarding runs
inside root tailscaled] F --> G1[ssh -L dials as root] F --> G2[ssh -R replaces sockets as root] F --> G3[Race beats the path allowlist] G1 --> H[Root-only sockets
Docker, systemd, tailscaled API] G2 --> H G3 --> H H --> I[Root on target, auth key capture,
rogue node if Tailnet Lock is off]
What Tailscale says
Mike Shaver, Tailscale's VP of Engineering, responded on Reddit that the company had already been investigating with outside help and is not recommending that everyone disable Tailscale SSH. In his words, most of the issues "concern what happens after someone has been authorized to connect", chiefly Unix privileges and SSH forwarding. His precautions are to review SSH policies, remove forwarding, consider check mode, and enable auto-updates, with an advisory and patches to follow. A Tailscale engineer also pointed out on Hacker News that the hosted control plane hides peers from each other when no rule connects them, so the report's claim that every node sees every other node mostly describes headscale.
Who is affected
Exposed:
- Anyone with Tailscale SSH enabled on a server and an SSH rule that lets other devices in, especially broad rules such as all members to every tagged server, or rules that allow
root. A compromised web panel on one box becomes root on the next. - headscale users with SSH rules. In headscale v0.29.5 and v0.29.6 an
acceptrule always grants local and remote forwarding, and the only way to get a session without forwarding is acheckrule. Treat every headscale SSH accept rule as root on the target. - headscale servers reachable from the internet, for the denial of service.
- Tailnets running app connectors in conn25 mode.
Not exposed:
- Default installs. Tailscale SSH is off by default, but it can be switched on later with
tailscale set --sshor pushed out by fleet configuration, so checkRunSSHon each node rather than trusting how you installed it. Plain OpenSSH reached over the tailnet is not affected by any of this. - Exit nodes, subnet routers, and Xray or VLESS boxes that merely run
tailscale, as long as Tailscale SSH and serve are off, since the proxy itself isn't involved. - Funnel on stock headscale, which can't grant it at all.
Partial:
- Nodes running
tailscale serve: you're only affected if you forwarded to a Unix socket or rely on app-capability headers for access control. - Any tailnet with reusable or non-expiring auth keys, auto-approved routes, and Tailnet Lock off. None of these is a bug, but they decide how much an attacker who captures a key can do with it.
Read-only checks
These change nothing, and you can run them on each node:
tailscale version
tailscale debug prefs | grep -E '"RunSSH"|"AdvertiseRoutes"|"ShieldsUp"|"RouteAll"'
tailscale serve status
tailscale funnel status
tailscale lock status
"RunSSH": true means Tailscale SSH is on and the rest of this piece applies to that node. If serve status shows anything pointing at unix:/run/tailscale/tailscaled.sock, remove it today. On headscale, list your SSH rules and look for "action": "accept".
What to switch off
If you don't need Tailscale SSH, turn it off and use OpenSSH over the tailnet instead, which none of these findings touch:
sudo tailscale set --ssh=false
If you keep it, narrow the policy to named pairs and an unprivileged account, and drop any rule that grants root:
"ssh": [
{
"action": "accept",
"src": ["you@example.com"],
"dst": ["tag:vps-a"],
"users": ["deploy"]
}
]
Note that the researcher says an unprivileged target account alone doesn't stop the forwarding bugs, so treat this as damage limitation. On headscale, switching such rules to "action": "check" removes forwarding entirely. That is damage limitation rather than a full fix, because it doesn't limit what the session itself can do, and it does nothing about the findings that have nothing to do with SSH, such as the denial of service against the control server. On hosted Tailscale, there is no documented per-rule switch for forwarding. Narrow each SSH rule to named users and specific tags or hosts, log in as a non-root user on the target (damage limitation again), or turn Tailscale SSH off on nodes that don't need it, and watch for the advisory.
A few cheap extras limit what a stolen key is worth. On nodes that don't need incoming connections, sudo tailscale set --shields-up=true blocks them. On VPS boxes, sudo tailscale set --accept-routes=false stops them picking up other nodes' subnets. If you don't need serve or Funnel, sudo tailscale serve reset and sudo tailscale funnel reset clear them. In the admin console, delete autoApprovers you don't need, issue one-off auth keys with short lifetimes, keep key expiry on for tagged servers, and consider tailscale lock init if you can manage the signing keys. Self-hosters should keep headscale off the open internet where possible, or put it behind a reverse proxy that rate-limits registration, with MemoryMax= and Restart=on-failure in its systemd unit.
If you suspect a node was compromised, delete it in the admin console or with headscale nodes delete. Reinstalling the machine doesn't revoke a copied state file.
What's fixed so far
Not much has shipped yet. Tailscale merged a fix for the serve permission leak on 25 October, along with a batch of Tailscale SSH hardening changes, but no release contains them and the security bulletins page has no Tailworm entry; the newest, TS-2026-013, covers the eMudhra certificates. Turning on auto-updates (sudo tailscale set --auto-update) means the fix arrives without you having to watch for it.
headscale did publish v0.29.6 on 24 October, and it is a security release, but for other problems: it distrusts the compromised eMudhra certificates and updates Go libraries with HTTP/2 and gRPC denial-of-service fixes. It changes nothing in the Tailworm findings, and SSH accept rules still grant forwarding. Upgrade for the certificate fix; it leaves the Tailworm findings untouched.
Windisch says on Hacker News the findings were reported to Tailscale but not coordinated, so they went public before any fix was ready. Whether skipping coordination was reckless is a fair debate, but it doesn't change what you should do this week.
Verdict
This is a real privilege-escalation problem in Tailscale SSH, and a bad one if you've enabled it fleet-wide with generous rules, because it turns one compromised panel into root everywhere that rule reaches. For the typical reader with Tailscale SSH off, it's a reason to run five read-only commands, not to rip out Tailscale. headscale users have the least room to manoeuvre, since accept rules can't be stripped of forwarding, so either switch to check rules, which removes forwarding but not the other risks, or turn Tailscale SSH off until a patched client ships.
Until then, wait for the advisory and the patched client, and check whether they address the forwarding bugs before you switch anything back on.