Your Mesh VPN Agent Is Root on Every Box. Tailworm Is the Reminder.

A researcher showed one hacked Tailscale node reaching root on other servers through Tailscale SSH forwarding. No patch yet. Here is why mesh VPN agents deserve the same suspicion as any privileged daemon.

A padlock resting on a laptop keyboard, circled by colorful light trails
Photo by FlyD on Unsplash

I like Tailscale. I have recommended it, and the WireGuard engine underneath it is excellent. But this weekend's Tailworm report is a good moment to say something I have believed for a while: a mesh VPN agent is not "just the VPN." It is a privileged daemon on every machine you install it on, and you should treat it that way.

What was actually found

Erica Windisch of Cyberdione Labs published Tailworm on October 25. It lists 11 findings against Tailscale 1.104.2 and the self-hosted headscale 0.29.5 control server, all reproduced in her lab between October 22 and 24. The headline issue is in Tailscale SSH, the SSH server built into the tailscaled agent.

That agent runs as root. According to the report, when a connecting device is allowed to use SSH port forwarding, Unix socket forwarding (ssh -L and ssh -R) is carried out by the root process instead of by the logged-in user. In the lab, an ordinary session used that to talk to a root-only Docker socket, got uid=0, and read /etc/shadow. Other variants replaced root-owned sockets and raced the path checks. One chain captured an enrollment key and joined a rogue machine to the tailnet, end to end only where Tailnet Lock was off. With Lock on, the researcher captured the material needed to disable it but didn't complete that step.

The preconditions matter, so here they are plainly:

  • The attacker already controls one device in your tailnet. Tailworm does not get them in. The report itself says that foothold comes the usual ways: a vulnerable web app, a poisoned package, phishing, stolen credentials.
  • That device has an SSH rule that lets it reach the target, with forwarding allowed. Windisch says on Hacker News that forwarding is on by default. On headscale 0.29.5 the code turns it on for every accepted session.

So this is not remote code execution from the internet. It is privilege escalation and lateral movement inside a tailnet. The report calls it "wormable" because, in the lab, spread to every device the policy allowed took under a second per hop. Some readers on Hacker News pushed back hard on that word and on the report's length, and a Tailscale engineer there noted that its hosted control plane trims each node's peer list to what ACLs allow, which may differ from headscale. The report also covers app connectors reaching destinations the ACLs never approved (in the experimental conn25 feature), a tailscale serve path to the local admin API, and memory exhaustion bugs in headscale and the relay client.

Where Tailscale stands

As of this writing there is no Tailscale security bulletin, no CVE and no fixed release for these findings. The latest release is still 1.104.2. Windisch wrote on Hacker News that the issues were "reported but not coordinated," so they went public before a fix existed. I think that was the wrong call, but it does not make the bugs less real.

To Tailscale's credit, the response was fast. Mike Shaver, Tailscale's VP of engineering, wrote on Reddit, according to The Hacker News, that the company was already looking at these areas with outside specialists, is working on fixes, and is "not recommending that everyone disable Tailscale SSH." The code backs that up. An open pull request, #21942, routes SSH forwarding through a helper that spawns a child process per operation, so sockets are dialed and bound with the logged-in user's credentials, "never by root tailscaled." That is a similar privilege-drop approach to OpenSSH's. It targets a stacked development branch, not main, so it is still a work in progress. A separate fix for one of the serve findings is already merged on the main branch. Neither has shipped in a release yet.

It is also not the first time this exact area has bitten. Tailscale's own bulletins list TS-2026-004, where SSH Unix socket forwarding could be steered to a privileged socket through a symlink, and TS-2026-005, where Serve could be used by a non-root operator to proxy privileged sockets. Both were fixed in 1.98.9. Tailworm is, in large part, the next round of the same problem.

To be fair about what this is: nobody broke WireGuard and nobody broke the crypto. This is a feature built on top of the tunnel, running with too much privilege. Which is exactly my point.

The real lesson: the agent is the attack surface

Look at what a modern mesh VPN agent does on every node. It runs as root or SYSTEM. It can be an SSH server, a port forwarder, a subnet router, an exit node, a web proxy and a file sharing tool. It takes its orders from a coordination server you probably do not run. It can update itself. Every one of those features is useful, and every one of them is code running with full privilege on your most important machines.

Now add the typical policy. Many tailnets start with "everyone can reach everything" and never get tightened, because it works and nobody complains. Put one compromised web server into that network and the mesh does the attacker's routing for them. One foothold plus a permissive ACL equals lateral movement. Tailworm just measured how fast.

The convenience that makes these tools great is the same thing that makes them a perfect pivot. That is true of Tailscale, and it is true of every product in this category.

What I would do now

  1. Turn off Tailscale SSH where you do not need it. Run tailscale set --ssh=false on those hosts. Tailscale's own docs warn you to make sure you have another way in first, so do that before you lock yourself out. Plain OpenSSH over the tunnel still works fine.
  2. Kill forwarding where you keep it. The report says forwarding can be denied per rule on Tailscale's hosted service, but Tailscale's public policy docs don't document such a setting yet. Until they do, the host-side switch below or turning off Tailscale SSH is the dependable route. The 1.104.2 source has a TS_SSH_DISABLE_FORWARDING environment switch that blocks TCP and Unix socket forwarding in both directions, plus agent forwarding. It is read once at startup, so set TS_SSH_DISABLE_FORWARDING=1 in /etc/default/tailscaled and restart the service. Because it is set on each node, it also works under headscale, where it is the only way to block forwarding. It is not in the public docs, so test it first.
  3. Write least-privilege ACLs. Per-pair SSH rules, one named source to one named destination, were the single control that stopped the spread in the lab. In practice, per-pair means a dedicated tag per server. Drop identity-wide and tag-wide accept rules, and never let a web server reach your management hosts just because it can.
  4. Disable features you do not use. Subnet routing, exit nodes, app connectors and serve forwards each add code paths with root behind them. If a node does not need a feature, turn it off on that node. The report also says to remove any tailscale serve --tcp forward that points at a Unix socket, especially tailscaled's own.
  5. Do not lean on check mode for this. The Hacker News says Tailscale suggests enabling SSH check mode, but the report notes it does not stop the forwarding attacks, because forwarding happens after the session is approved.
  6. Keep the agent off critical infrastructure. If a site-to-site link or a management path can be a plain WireGuard tunnel terminated on a router or firewall, do that. I like RouterOS or VyOS for this. The tunnel ends on a box whose only job is routing, with a firewall policy you wrote, and no third-party daemon running as root on the servers behind it. That router then becomes the critical device to patch, and its management should stay off the WAN.
  7. Consider self-hosted control where it fits. Headscale keeps the coordination server under your own roof. Tailworm is a reminder that self-hosting is not a free pass, since headscale had its own findings and fewer knobs, so harden and patch it like any other exposed service.
  8. Treat the agent like privileged software. Inventory where it runs, watch its version, update it promptly, enable node-key expiry, and if a node is compromised, delete it at the control plane. The report notes that reimaging alone does not revoke keys an attacker already copied.

Mesh VPNs solved a real problem, and I am not telling anyone to rip them out. I am saying: stop thinking of the agent as plumbing. It is root on every box, with its own features, its own bugs and its own boss. Give it the least privilege and the fewest features it needs, and keep it away from the machines where one bad day would hurt the most.

Sources: Tailworm report (Erica Windisch, Cyberdione Labs), Tailscale security bulletins, tailscale/tailscale PR #21942, tailscale/tailscale PR #21931, Tailscale SSH documentation, Tailscale policy file reference, Tailscale auto-update docs, Hacker News discussion, The Hacker News.