P.K. SHARMA

Cyber security intelligence, AI governance, practitioner analysis

Tailworm claims 11 flaws in Tailscale and headscale: no CVE or fixed release, 18 code changes merged (read 25 Oct 2026)

A researcher's Tailworm report claims root on Tailscale SSH servers from one permitted device, with no CVE, no bulletin and no fixed release at 25 October. Tailscale says it is working on fixes, and its public code shows 18 SSH and serve changes merged in a day.

By Parminder Kumar Sharma · · 36 min read

No bulletin, no CVE, no fixed release, and 18 code changes since Saturday evening

At 21:01 GMT on Sunday 25 October 2026, the newest Tailscale release is v1.104.2, published on 21 October at 02:55 UTC. That is the version the Tailworm report says it tested, so a customer on the latest release is, on the report's terms, in scope (derived from the GitHub releases list). Tailscale's security bulletin page lists 13 bulletins for 2026, TS-2026-001 to TS-2026-013. The newest is dated 21 October and concerns leaked certificate keys; none mentions this report, and none of the 13 carries a CVE id (derived). The National Vulnerability Database returns no record for the words tailworm or cyberdione. Yet in Tailscale's public code repository, 18 pull requests about SSH, serve and the SSH library were merged between 18:32 UTC on Saturday 24 October and 18:31 UTC on Sunday 25 October (derived count, from the pull request records). None is in a tagged release.

That sequence does not establish that the 18 changes answer the report. None of their 18 descriptions cites it, and Tailscale says its own engineers and outside specialists were already looking at the same areas. It does not establish that the report is right: nobody has publicly reproduced it, and Tailscale has not confirmed its specific claims. It does not show that anyone was attacked, how many tailnets allow SSH forwarding, or when a fixed release will ship. All of the report's results come from one lab, one researcher and one three day test window, 22 to 24 October (derived: three calendar days inclusive).

What the record does show is a vendor answering on two layers at once. In public, a Tailscale vice president of engineering wrote on Reddit that the company is working on fixes and is "not recommending that everyone disable Tailscale SSH". In code, one merged change matches finding 11 of the report in function, field and remedy, and five open pull requests describe a monitor process whose children do the forwarding as the logged in user, never as root, which is the kind of separation the report asks for. Neither layer says which of the eleven findings is confirmed. The reader is left with a security advisory that has been promised and not written.

Everything here was read between 20:31 and 21:01 GMT on 25 October 2026 (UK clocks went back at 02:00, so GMT and UTC agree). The first full reads were at 20:31, with further full reads at 20:46, 20:58 and a last one at 21:01. A bulletin, a release or a merge can appear in minutes, so each claim of that kind carries its read time. The Hacker News report was read from an Internet Archive capture taken at 20:20 UTC, because the site's own page returned a browser check that this site did not try to pass. The Reddit pages also returned a browser check, so the Reddit posts were read from Reddit's own public Atom feeds. The report, Tailscale's pages, the GitHub records and the source files were read directly. This briefing names no individual: the people involved are described by role.

What the report claims: eleven findings in five components

The report, published at tailworm.com under the name of a researcher at Cyberdione Labs Corporation, runs to more than 7,000 words (derived from the saved page text). It states a testing window of 22 to 24 October 2026 and says all findings "were verified by reproduction in a lab environment on unmodified, released software", Tailscale v1.104.2 and headscale v0.29.5. Its opening note says the researchers were not employed or paid by Tailscale and calls Tailscale's security marketing into question, so it is a technical report and an argument about design in one document. Its severity labels are the researcher's own. The report prints no CVSS vector or score, and there is no CVE id to carry one.

Counted by the report's own labels (derived), six findings are High, one Medium High, two Medium, one Medium with Low to Medium elsewhere, and one a configuration note. Grouped by component (this site's grouping): four are in Tailscale SSH, five in serve and funnel, one in the experimental conn25 app connector, and one in headscale with a client side relay problem. The story that travelled is the SSH group, findings 1 to 3 and the chain built on them. The researcher told The Hacker News that the app connector finding "may be more impactful to some organizations". The last column below is what this site found in the vendor's public record. It is based on the titles of the 40 pull requests opened in Tailscale's repository from 21 to 25 October and on the full text of the eight that touch SSH and serve. It is not a review of every line of code.

The 11 findings as the Tailworm report numbers and labels them (tailworm.com, read 25 October 2026), with the vendor record from Tailscale's and headscale's public repositories read at 21:01 GMT. Severity labels are the report's own.

Finding and the report's labelWhat the report says it needsVendor record, 25 Oct 21:01 GMT
1. Local socket forwarding is dialled as root (High)Tailscale SSH on the target, a rule that accepts the device, local forwarding allowed. No sudo or Docker group needed.Open pull request 21942 moves the dial to the logged in user. Nothing merged.
2. Remote socket forwarding replaces root owned sockets (High)As finding 1, with remote forwarding allowed.Open pull requests 21941 and 21942 create listeners as the user. Nothing merged.
3. A time of check to time of use race beats the path allowlist (High)As findings 1 and 2, plus a racing process inside the session.Open 21942 keeps the list as coarse policy and says the kernel permission check is the boundary. Nothing merged.
4. conn25: a user entitlement lets a client choose any destination (High)The experimental feature configured, and an ordinary app entitlement.No matching change found. The source names the feature experimental in two node attributes.
5. A held session exhausts memory in the root Tailscale process (High)An authenticated SSH session.Open pull request 21945 (opened 20:47 UTC) updates the SSH library for "resource exhaustion fixes"; its description holds only a tracker reference. A gliderssh update for a data race on timeouts merged earlier (21933), a different subject.
6. headscale 0.29.5: memory exhaustion, plus a client response bomb (Medium High)Internet reach to the headscale server for the cache part, an authenticated insider for the relay part.No headscale statement or issue found. Release 0.29.6 lists certificate, dependency and performance changes.
7. serve forwards TCP to the Tailscale local API socket (High)An operator sets the forward, and a permitted peer uses it.No matching change found. Bulletin TS-2026-005 (3 June) covered a different serve socket case.
8. The serve socket guard checks once, at configuration time (Medium)Local write access to a directory on the configured path.No matching change found.
9. Funnel entitlement is enforced by the command line, not the daemon (Medium)A raw local API call. headscale cannot grant the capability.No matching change found.
10. A non default knob exposes serve listeners outside the tunnel (configuration note)The knob set, which the report says upstream acknowledges and the Kubernetes operator sets.Not a defect claim.
11. Capabilities bleed between serve mounts over HTTP/2 (Medium, Low to Medium elsewhere)Serve over TLS, two mounts with different accepted capabilities, one connection, a peer holding the capability.Merged 25 Oct 00:39:53 UTC (21931). The description names the same shared structure and the same remedy.

Two details in the table matter for how far to trust it. First, only finding 11 has a merged change whose description matches the report's mechanism, and it is the lowest rated of the technical findings. Finding 5 has an open one that matches only by its title. The pull request for it was opened 2 hours 25 minutes after the first Reddit thread about the report and merged 39 minutes later (derived). Second, the five open pull requests are not described as fixes for findings 1 to 3. They describe a design change, and this site's link to the report is an inference from what they say.

Finding 4 gets its own paragraph because the researcher says it may matter more than the SSH chain. The report says an ordinary user entitlement to an app connector lets that user's device choose where the connector sends traffic, including the connector's own network, a cloud metadata service and, in Kubernetes, the cluster's services, because the destination a client names is checked for address family and not against the app's approved destinations. It adds that this is not a new capability, since a subnet router gives the same reach, and that the flaw is the path to it: a user level trigger, no approval step and no policy check on the real destination. The report calls conn25 experimental in 1.104.2, and Tailscale's source names the two node attributes that switch it on (block 8 below). It is also the easiest of the eleven to check for: one search of the policy file shows whether the feature is switched on.

How the claimed chain works, at the level a defender needs

Tailscale SSH is not OpenSSH with keys. Tailscale's documentation says the server already knows who the remote party is and takes over, "not requiring the SSH client to provide further proof", using the SSH authentication type none. A policy rule that names the source and the destination is the whole authorisation. The process that serves it is tailscaled, which runs as root. Tailscale's own bulletin TS-2026-004 for an earlier flaw in the same area says the attack is possible "because Tailscale runs as root and so has access to the privileged destination". The report's argument is that port forwarding, which an ordinary session may ask for, makes that root process open, replace or race local sockets on the target, and that this crosses from an ordinary session to root. The diagram follows the report's stages. This site omits the commands, the socket paths and the race timing the report prints.

Drawn from the Tailworm report (tailworm.com), read 25 October 2026. The report's lab results at defender level; exploit details are left out.

The chain only works if every condition below is true at once. The table sets out each condition, where it comes from, and the check it implies. Nothing here is a ranking of how common any condition is, because no source says.

Conditions for the SSH chain, from the report and Tailscale's documentation, read 25 October 2026. The last column is what a defender checks.

ConditionSourceCheck
A foothold on one device the rules let inReport: web application, build dependency, phishing, stolen credentials. Tailscale does not create it.Which devices are SSH sources, and what runs on them?
Tailscale SSH switched on for the targetDocs: "You still need to opt in a destination device."Run tailscale debug prefs on the host and read RunSSH (derived).
A rule that accepts that source for that targetDocs: rule shape with action, src, dst, users. The default rule lets a user reach their own devices in check mode.List every ssh rule. Is src a user, a group, a tag or autogroup:member?
Forwarding allowed on that ruleReport: per rule on the hosted service. headscale 0.29.5 source: always on (read from the code).Hosted service: confirm the field with Tailscale. headscale: assume yes.
A root only socket service on the targetReport: container platform, init system, kubelet and the Tailscale control socket named. SELinux enforcing blocked file reads in one test.Which hosts run Docker, Kubernetes or similar?
For the last step: Tailnet Lock offReport: the join worked end to end only without it. Docs: not on by default.Run tailscale lock status.

Three reliability points come from the report itself and bear on the word wormable. Finding 1 is reported as working in "0 s" measured elapsed time, with no race. The race based paths are reported as intermittent: for one of them the report gives a delivery rate of 0 to 4 percent. And the spread claim, "under a second per hop", appears in the summary. This site searched the page text for hop, spread and propagate: the findings sections describe single session results, and no section gives a host count, a hop count or a topology for the spread test. That does not mean the test was not run. It means the report as published does not let a reader judge it.

What Tailscale and headscale have said, and what their public code shows

Tailscale's statement is a Reddit post by its vice president of engineering, first made as a reply in a thread about the report at 00:34 UTC on 25 October and then posted on its own at 00:41 UTC (from the Atom feeds). Tailscale sells the hosted service and has a commercial interest in how widely the problem is read, which is why the specifics matter more than the tone. The post says the company has the report, that its "engineering and security teams had already been investigating independently, with help from external security specialists", and that this "work has identified issues we're working to fix". It adds that most of what it has found concerns what happens after someone is authorised to connect, and that "a session may be able to do more than the configured local user should be allowed to do". The post also says this "isn't the same as an unauthenticated attacker being able to connect to arbitrary machines", which matches the report's own precondition of a foothold on a permitted device. That is a concession about the class of problem. It is not a confirmation of any of the eleven findings.

The post says the company will publish a security advisory with confirmed findings, affected configurations, actions and available patches, and a more detailed technical write up. It gives no date and no version. Neither Tailscale's blog feed (newest post 19 October) nor its changelog (newest entry 21 October) has an entry about it at 21:01 GMT. Its precautions are to review SSH access policies, review forwarding permissions, consider check mode, enable automatic updates and, for sensitive systems, tighten SSH policies temporarily. It says check mode "won't fix privilege escalation issues", and that agrees with the report, which says the same. Where the two sides differ is the advice to disable. The report's author advised users to disable Tailscale SSH (as The Hacker News reports it), and Tailscale says it is not recommending that everyone does.

A forum commenter who identified themselves as a Tailscale employee said at 01:38 UTC on Hacker News, the Y Combinator forum and a different site from The Hacker News, that the hosted control plane trims each device's list of peers so that a device with no access to another never sees it. The report says every node receives the full peer list. The two claims may describe different control planes, because the commenter suggested the report's observation may be a headscale difference. They are also less different than they look: Tailscale's documentation says an unmodified default policy grants access to all devices, and trimming removes nothing there. The identity of the commenter was not verified.

The repository tells a faster story than the statement. The table lists the 18 merged pull requests, in merge order. Fourteen of them were merged on Saturday between 18:32 and 23:08 UTC. That is after the report file's last modified time of 17:38:43 GMT, and twelve of the fourteen were merged before the first Reddit thread about the report appeared at 21:35 UTC (derived). The titles are Tailscale's own, copied as printed. Some are plainly hardening (a numeric user id treated as root, key file permissions, an environment variable denylist) and some are features (recording the raw client command, recording file transfer sessions). None of the 24 descriptions this site read (the 18 merged and the six in the monitor stack) mentions the report or its researcher, and every one cites the same internal tracker item.

The 18 pull requests merged into tailscale/tailscale between 24 October 18:32 UTC and 25 October 18:31 UTC that are about SSH, serve or the SSH library, from GitHub's search results and records read at 21:01 GMT. Titles as printed, with hyphens replaced by spaces by this site; merge times are UTC.

Pull requestTitle as printedMerged (UTC)
21914ssh/tailssh: record the raw client command in session recordings24 Oct 18:32:33
21915ssh/tailssh: make acceptEnv pattern matching linear time24 Oct 19:13:06
21917ssh/tailssh: extend dangerous env var denylist, re check child side24 Oct 19:41:58
21918util/osuser: validate 'id' input, reject corrupt getent passwd output24 Oct 20:05:03
21921ssh/tailssh: quote the auditd acct field24 Oct 20:10:03
21919ssh/tailssh: treat numerically zero uids as root in isRootUser24 Oct 20:23:22
21920ssh/tailssh: write private host keys with 0600 permissions24 Oct 20:30:42
21922ssh/tailssh: pin rejection banner content to policy derived facts24 Oct 20:52:26
21923ssh/tailssh: hand the agent forwarding dir to the user, remove it on session end24 Oct 20:52:38
21924ssh/tailssh: refuse direct exec fallback for non root users as root24 Oct 20:52:48
21925ssh/tailssh: validate accepted env values, deny GLIBC_TUNABLES, cap names24 Oct 20:55:36
21926ssh/tailssh: fix off by one and clamp c2n SSH username hint cap24 Oct 21:10:25
21928ssh/tailssh: unify defaultPathForUser to use isRootUser24 Oct 21:54:15
21929ssh/tailssh: record sftp sessions and honor recording failure policy24 Oct 23:08:18
21931ipn/ipnlocal: fix serve app caps leaking across mounts25 Oct 00:39:53
21933go.mod: update gliderssh to remove data race on timeouts25 Oct 14:53:00
21936ssh/tailssh: drain the sftp test helper's stderr copier25 Oct 16:10:30
21930tsnet: authorize ListenSSH peers, fix PTY emulation and session queue bound25 Oct 18:31:40

Several descriptions describe privilege problems in Tailscale's own words, which is worth noticing because none of them has a bulletin. The description of 21924 says a root tailscaled "could therefore run" a session as root when a helper path was empty. The one for 21919 says an alternative spelling of the user id let a session "run as root", which is the same kind of flaw as bulletin TS-2026-006 in June (inference: this site compared the two descriptions and did not test either). The one for 21923 says every local user could reach other users' agent sockets. These are Tailscale's statements about code defects it fixed on Saturday, in the same area the report is about, and they are public evidence that the area had more to fix. They are not evidence that the report is right.

Five pull requests from Sunday afternoon are still open. Opened between 15:56 and 17:26 UTC, they build a separate privileged monitor process for each SSH connection and move the work that the report is about into children that run with the logged in user's credentials. Tailscale's own description of the forwarding change reads: "never by root tailscaled". That is close to the privilege drop the report recommends, for which it points to OpenSSH and Dropbear as examples. One pull request in the stack, 21939, closed without merging, and the reason is not stated. The internal tracker item they all cite, tailscale/corp#50380, is not public.

One of the open pull requests also describes a separate gap. Its text says the old check "only canceled live session contexts", and that a revoked user kept the connection, so that new forwards on it ran with the old action. Tailscale's documentation says changing the policy stops existing SSH connections. If the pull request is right, that is not true for every kind of use of a connection, and a rule change is not the same as ending a session. Ask Tailscale before relying on it.

headscale has said nothing this site could find. No issue or pull request in its repository names the report by 21:01 GMT, its list of published security advisories on GitHub is empty, and its newest release, 0.29.6, was published on 24 October at 10:29 UTC, during the report's testing window. The release notes list a Go update to reject compromised certificate chains, container base images and three dependency updates for HTTP/2 denial of service and text processing, and performance changes. They mention no change to forwarding, relays or the onboarding cache, and the only SSH line is a dependency update for JSON compatibility in SSH check responses. Whether 0.29.6 behaves differently from 0.29.5 for the report's findings is not stated by anyone this site read. headscale's changelog shows SSH check mode arriving in 0.29.0 on 17 June 2026, so it is a young feature there.

The clocks: what was told when, and what the versions say

The report prints no date for telling Tailscale or headscale. Its opening note says it is the researcher's opinion that "infrastructure is vulnerable today". The Hacker News reports that the report and the proof of concept were sent to Tailscale's security contact on the Saturday before publication, and quotes the researcher's own description of the disclosure as "reported but not coordinated". Both statements come from the researcher, by way of a secondary report and a forum comment. The earliest public trace this site found is a Reddit submission at 21:35:04 UTC on Saturday 24 October, 3 hours 56 minutes after the report file's last modified time. So the date the report is public depends on the time zone: The Hacker News says 25 October, and in UTC the first public trace is Saturday evening.

Dated events in UTC from the report's headers, GitHub, Reddit's Atom feeds, the Hacker News API and Tailscale's pages, read 25 October 2026. Intervals are derived.

When (UTC)WhatSource
28 Jul, 23:02Tailscale 1.98.10 released. Its changelog says it carries the fix for TS-2026-004, the earlier SSH Unix socket forwarding flaw. The bulletin says 1.98.9 or newer.GitHub, changelog, bulletins
13 Oct, 13:05headscale 0.29.5 released.GitHub
21 Oct, 02:55Tailscale 1.104.2 released: the newest stable release at 21:01 GMT on 25 October.GitHub
22 to 24 OctThe report's stated testing window (3 days).tailworm.com
24 Oct, 10:29headscale 0.29.6 released, inside the window.GitHub
24 Oct, 17:38:43Last modified time of the report page on the server (an HTTP header; it does not prove publication).tailworm.com headers
24 Oct, 18:16 to 23:08First SSH pull request created at 18:16:09, 37 minutes after the report file's last modified time. 14 SSH and user lookup pull requests merged from 18:32:33 to 23:08:18.GitHub
24 Oct, 21:35:04Reddit submission titled Tailworm: the earliest public trace found.Reddit Atom feed
25 Oct, 00:00 to 00:40Serve pull request 21931 created at 00:00:45 and merged at 00:39:53.GitHub
25 Oct, 00:41:19Tailscale's vice president of engineering posts. First reply in the other thread at 00:34:04.Reddit Atom feeds
25 Oct, 00:59:48Hacker News submission (18 minutes 29 seconds after the post).Hacker News API
25 Oct, 02:34A commenter reported by The Hacker News to be the researcher writes that it was reported but not coordinated.Hacker News
25 Oct, 14:53gliderssh update merged.GitHub
25 Oct, 15:56 to 17:26Five pull requests for the privileged monitor opened and still open at 21:01 GMT.GitHub
25 Oct, 20:47Pull request 21945, update gliderssh for resource exhaustion fixes, opened (missed by the 20:46 read, found at 20:58).GitHub
21:01 GMTNo bulletin, CVE or release naming the report.Bulletins feed, NVD, releases

The versions complete the picture. The Tailscale client tested is the newest stable one, so there is no newer release to point customers to. The headscale server tested, 0.29.5, is one release behind 0.29.6, and the newer one was out for the last day of the test. The earlier fix for the same family of socket forwarding flaw, TS-2026-004, shipped in 1.98.10 according to Tailscale's changelog, 84 days and 7 stable releases before 1.104.2 (derived). Tailscale's bulletin page has four 2026 entries whose descriptions begin with Tailscale SSH, from June and July, so this report arrives in code with a recent record. The bulletin dates and the release dates do not line up: TS-2026-004 is dated 3 June on the bulletin page, while the changelog dates its fix 28 July.

On the word zero day: neither the report nor The Hacker News uses it. If it means public before a fix exists, the record at 21:01 GMT fits, with Tailscale told one day earlier by the researcher's account. If it means exploited before disclosure, nothing this site read says so. No fixed release is the plainer way to say it, and it is what the title says.

Seven friendly names, and what each one does not control

A comforting label is not a control. These are the labels around this story, with what the documents say each does and does not do.

Labels from the report, Tailscale's documentation and the vendor post, read 25 October 2026. The third column is what the record says.

LabelWhat it suggestsWhat the record says
SSHThe hardened login system you know.Tailscale SSH is Tailscale's own server. The docs call its method none: the device is identified, the rule decides. It runs as root. The docs say it may not suit machines with outbound SSH where you do not trust the code running on them.
Non root users onlyA session cannot become root.The report says limiting rules to unprivileged accounts "does not mitigate" the findings, which run from unprivileged accounts. Tailscale's own post says a session may do more than the local user should.
Check modeA person approves every login.It gates the start of a session. Forwarding happens inside an approved session. Tailscale's post and the report agree it does not fix this. The docs say one approval covers other check mode destinations for 12 hours by default.
Path allowlistForwarding is limited to safe folders.The report calls the list of home, /tmp and /run/user "not a security boundary". Bulletin TS-2026-004 said the earlier check was lexical only, and the open pull request drops one of its checks in favour of kernel permissions.
Tailnet LockA stolen key cannot add a machine.Not on by default. Docs list it for Personal and Enterprise plans. The report says it stopped only the final join in its test, and that the lock related secrets were captured in transit.
Hardware bound keysStolen state cannot be reused.On Linux and Windows, since 1.92.5, node state encryption with a TPM is opt in. The report says it held the identity theft back. It says nothing about default settings.
WormableIt spreads on its own.The report's word for a lab measurement of under a second per hop. No host or hop count is printed, and some researchers dispute the word, as The Hacker News reports.

The word lab belongs on the list too. It is one lab, with unnamed hosts, and the report says its identifiers are redacted. One distribution is named as SELinux enforcing, where host file reads were blocked. That detail suggests that outcome depends on the system underneath, and the report does not say how many systems it tried.

Stated and not stated

The right column is what could not be found in the report, the vendor posts or the repositories, all read at 21:01 GMT. It does not mean the information does not exist.

What each party states and what is missing, from the Tailworm report, Tailscale's Reddit post and bulletins page, The Hacker News (secondary) and the repositories, read 25 October 2026.

TopicStatedNot stated
Root from one deviceReport: reproduced in a lab on 1.104.2 and 0.29.5. Tailscale: issues it is working to fix, sessions may exceed the local user.Tailscale's confirmation of any specific finding. Any independent reproduction. How many setups meet the conditions.
SpreadReport: under a second per hop in a lab. Per pair rules stopped it.A host count, a hop count, or the test's design.
AttacksNobody read says the findings are exploited.Any search for exploitation. Absence is not proof.
Which setupsTailscale: depends on SSH configuration. Report: forwarding is per rule on the hosted service and always on in headscale 0.29.5.The hosted service's default for a rule that says nothing about forwarding. The docs pages read list no forwarding field.
The fixTailscale promises an advisory, patches and a write up. Pull requests are open.A version, a date, or which finding each change answers.
IdentifiersNo bulletin. No CVE. None of the 13 Tailscale bulletins of 2026 has a CVE id.Whether Tailscale or anyone will request one.
DisclosureResearcher: reported but not coordinated. The Hacker News: sent the Saturday before.An agreed timeline. A notice date in the report. headscale's notice.
Proof of conceptThe Hacker News: not public, given only to Tailscale's security contact. The report prints a hash.Whether anyone else holds the code.

Technical details

These are the artifacts the primary sources publish, copied exactly and attributed in each caption, with the date and time read. Each block is explained in plain words above it. Anything this site worked out is marked derived. The report prints command lines, socket paths and race timing for its demonstrations, and this site does not reproduce them, because they would make the attack easier than the report already has. It also prints no domain, address or log line, and one hash. Tailscale and headscale print no indicator for these findings. This briefing does not invent any. Where the report's text contained em or en dashes, this site replaced them with a comma or the word to, and the caption says so.

Block 1 is the shape of a Tailscale SSH rule, from Tailscale's documentation. Each rule names an action, sources, destinations and the local users the session may become. The comments are Tailscale's. This is the rule you search your policy file for. The docs page lists no field for forwarding. Source: Tailscale's documentation page for Tailscale SSH, read 25 October 2026 at about 20:36 GMT.

json
[PRE]
{
  "action": "check", // "accept" or "check"
  "src": [list-of-sources],
  "dst": [list-of-destinations],
  "users": [list-of-ssh-users],
  "checkPeriod": "20h", // optional, only for check actions. default 12h
  "acceptEnv": [ "GIT_EDITOR", "GIT_COMMITTER_*", "CUSTOM_VAR_V?" ] // optional, allowlists environment variables that can be forwarded from clients to the host
},
SSH access rule shape as printed on Tailscale's documentation page for Tailscale SSH (last validated 5 January 2026 by the page), read 25 October 2026.

Block 2 is the default rule the same page says new tailnets get: any member may reach their own devices, in check mode, as root or not. If your policy still has it, a compromised device of a member can ask for SSH, as root, to that member's other devices. It is a check mode rule, which is the case the report says forwarding rides on. Block 3 is the narrowest example the page prints. Source: the same documentation page.

json
"ssh": [
  {
    // any user can use Tailscale SSH to connect to their own devices
    // in check mode as a root or non-root user
    "action": "check",
    "src": ["autogroup:member"],
    "dst": ["autogroup:self"],
    "users": ["autogroup:nonroot", "root"]
  },
]
Default SSH access rule as printed on Tailscale's documentation page for Tailscale SSH, read 25 October 2026.
json
  "ssh": [
    {
      "action": "accept",
      "dst": ["autogroup:self"],
      "src": ["autogroup:member"],
      "users": ["autogroup:nonroot"]
    }
  ]
The page's example for letting a user SSH only to their own devices as a non root user, as printed on the same page, read 25 October 2026.

Block 4 is where the forwarding permissions live in Tailscale's code: three flags on the action the control plane sends to each machine. A flag that is absent counts as false. The report says the hosted service sets them per rule, and Tailscale's post tells customers to review forwarding permissions. The documentation pages read name no policy file key for them, so confirm the key names with Tailscale before editing a policy. Source: tailcfg/tailcfg.go on the main branch of tailscale/tailscale, read 25 October 2026 at 20:36 GMT.

go
	// AllowAgentForwarding, if true, allows accepted connections to forward
	// the ssh agent if requested.
	AllowAgentForwarding bool `json:"allowAgentForwarding,omitempty"`

	// AllowLocalPortForwarding, if true, allows accepted connections
	// to use local port forwarding if requested.
	AllowLocalPortForwarding bool `json:"allowLocalPortForwarding,omitempty"`

	// AllowRemotePortForwarding, if true, allows accepted connections
	// to use remote port forwarding if requested.
	AllowRemotePortForwarding bool `json:"allowRemotePortForwarding,omitempty"`
Fields of SSHAction in tailcfg/tailcfg.go (main branch, tailscale/tailscale), lines 2782 to 2784 and 2805 to 2811, read 25 October 2026. Gap between them is this site's.

Block 5 is the headscale code behind the report's claim that forwarding cannot be turned off in 0.29.5. Both the accept rule and the answer given after an SSH check is approved set all three flags to true. It also shows that a policy with no ssh rules gives clients an empty list, so a headscale server with no ssh section grants no Tailscale SSH access. Source: headscale at tag v0.29.5, read 25 October 2026 at 20:36 GMT. This site read the code and did not run it.

go
// hscontrol/policy/v2/filter.go, accept rules
var sshAccept = tailcfg.SSHAction{
	Reject:                    false,
	Accept:                    true,
	AllowAgentForwarding:      true,
	AllowLocalPortForwarding:  true,
	AllowRemotePortForwarding: true,
}

// hscontrol/noise.go, the answer to an approved SSH check
	action := tailcfg.SSHAction{
		AllowAgentForwarding:      true,
		AllowLocalPortForwarding:  true,
		AllowRemotePortForwarding: true,
	}

// hscontrol/policy/v2/filter.go, no ssh rules in the policy
	// Never nil: clients read a nil SSHPolicy as "keep the previous
	// rules", so revoked access would stay. SaaS sends "rules":[].
	if pol == nil || len(pol.SSHs) == 0 {
		return &tailcfg.SSHPolicy{Rules: []*tailcfg.SSHRule{}}, nil
	}
Lines from headscale v0.29.5 (hscontrol/policy/v2/filter.go lines 220 to 226 and 272 to 276, hscontrol/noise.go lines 489 to 493), read 25 October 2026. File headings and the gaps are this site's.

Block 6 is the setting to look for in a node. RunSSH is the preference that switches Tailscale SSH on, and it prints with the command shown. The command is a debug interface that Tailscale does not promise to keep stable, so treat the output as a check and not as an inventory system. The line from the source is below it. Source: ipn/prefs.go and cmd/tailscale/cli/debug.go at tag v1.104.2, read 25 October 2026.

go
	// RunSSH bool is whether this node should run an SSH
	// server, permitting access to peers according to the
	// policies as configured by the Tailnet's admin(s).
	RunSSH bool

# derived by this site, run on each host, read the RunSSH line
tailscale debug prefs
RunSSH in ipn/prefs.go at tag v1.104.2 (lines 137 to 140), read 25 October 2026, with a check command derived by this site (debug prefs exists in the same version, usage text: tailscale debug prefs).

Block 7 collects the commands Tailscale's documentation prints for the settings this story turns on. The first three switch Tailscale SSH on, off and block all inbound tailnet connections, and generate new node keys. The last two are the node state encryption flag and the Tailnet Lock status check. Each is copied from the page named. Tailscale warns that switching SSH off can lock you out of a host, so keep another way in. Sources: the Tailscale SSH, Secure node state storage and Tailnet Lock pages, read 25 October 2026.

bash
# Tailscale SSH page: switch Tailscale SSH on, then off
tailscale set --ssh
tailscale set --ssh=false

# same page: block inbound connections from the tailnet, including Tailscale SSH
tailscale set --shields-up

# same page: generate new node and SSH host keys
tailscale up --ssh --force-reauth

# Secure node state storage page: on Linux, pass this flag to tailscaled and restart it
--encrypt-state

# Tailnet Lock page: check the trusted signing keys on a node
tailscale lock status
Commands as printed in Tailscale's documentation, one per page named in the comments, read 25 October 2026. Arrangement is this site's.

Block 8 is the pair of node attribute names that switch the experimental app connector feature on in the client, from Tailscale's source. If your policy file has a nodeAttrs entry with either name, finding 4 is relevant to you. The source file's own header comment says the feature is at an early stage. Source: feature/conn25/conn25.go at tag v1.104.2, read 25 October 2026.

go
	AppConnectorsExperimentalAttrName        = "tailscale.com/app-connectors-experimental"
	AppConnectorsExperimentalIPPoolsAttrName = "tailscale.com/app-connectors-experimental-ippools"
Lines 702 to 703 of feature/conn25/conn25.go at tag v1.104.2 (tailscale/tailscale), read 25 October 2026.

Block 9 is Tailscale's own description of the one merged change that matches a Tailworm finding, and of the design that is still open. The first is the description of pull request 21931, merged at 00:39:53 UTC on 25 October. The second is the opening sentence of 21942, open at 21:01 GMT. The third is the sentence from 21944 about revocation. These are public and unmerged text, and they may change. Source: GitHub, read 25 October 2026.

Text
21931, merged 2026-10-25T00:39:53Z
`serveWebHandler` wrote each mount's accepted app capabilities into the connection-scoped serveHTTPContext. Concurrent h2 streams of one TLS serve connection share that struct, so a request to a mount accepting no capabilities could be proxied carrying another mount's `Tailscale-App-Capabilities` header, letting backends that trust the header authorize the wrong mount.

This change fixes that issue by storing accepted capabilities per-request via a context value instead of a field on the shared struct.

21942, open
Route tailssh's forwarding through the per-connection ssh-monitor, so on unix forwarded sockets are dialed and bound by children with the authenticated local user's credentials, never by root tailscaled.

21944, open
The old checkStillValid only canceled live session contexts. A revoked user kept the connection, and fresh shells, sftp, and forwards on the same conn ran with the old action, the old localUser, and the old recorder config. Forwarding-only conns were never checked at all.
Descriptions from tailscale/tailscale pull requests 21931 (merged), 21942 (open) and 21944 (open), as printed, read 25 October 2026 from the GitHub API. Gaps are this site's.

Block 10 is the report's own defender text: the sensors it says to deploy while unpatched, and what to do on suspicion. It is copied from the page. The report also lists a rename rate detection and notes that a socket with mode 0755 where 0600 is expected is a sign of a won race. This site describes those two in words and omits the report's race figure. The advice to delete the device at the control plane, and not only to reimage the host, fits Tailscale's secure node state storage page, which says node state holds the node keys. Source: tailworm.com, read 25 October 2026.

Text
Socket-lifecycle auditing. auditd rules on unix-socket unlink/bind/chmod in the
   forwarding-allowed directories (/tmp, homes, /run/user) and on the agent's own socket
   paths, object-scoped (watch the path and operation), not syscall-name-scoped.

Cross-identity endpoint analytics. Baseline each device identity's network endpoint;
   alert when one endpoint begins serving a second node identity (site-independent, catches
   same-machine impersonation that location-change analytics cannot), and when a machine key
   appears from a new network/ASN (catches stolen state used elsewhere; note this detects
   cross-site use only, same-site reuse of stolen identity remains blind to it).

Enrollment and key monitoring. Alert on authkey issuance and use outside change
   windows; alert on any node joining with a previously unseen key under a tagged identity;
   treat an unrequested Tailscale authentication prompt reported by a user as an incident.

Control-plane health. headscale: monitor resident memory (it retains peak RSS after
   attack), registration-cache churn, and registration latency; alert on deviation.

Containment on suspicion or incident:

Delete the device at the control plane, reimaging alone is not containment. A
    node's identity is key material stored in its state file; an attacker with root on the
    host can have copied that file off-box (demonstrated in this report: the copied state
    file re-creates the node's identity on other hardware, accepted by the control plane).
    Reimaging wipes only the compromised host's copy, it does not revoke stolen keys, which
    remain valid until the device is deleted or its keys expire. Assume exfiltration after
    any root compromise; delete the device (which invalidates both its machine and node
    keys), then rotate any authkeys and credentials reachable from the affected host; if a
    Tailnet Lock signing node was compromised, rotate the lock; review policy history via
    your GitOps trail for unauthorized diffs (routes, DERP map, approvers, key scopes).
Detection and containment text from the Tailworm report, as printed (tailworm.com, read 25 October 2026), with the rename rate item left out and dashes replaced by this site.

Block 11 is the report's interim mitigation text for operators, in the order it prints it. Note the headscale line: treat any SSH grant as root equivalent. The sentence on the hosted service tells you to set forwarding flags to denied per action. Source: tailworm.com, read 25 October 2026.

Text
Inventory and restrict Tailscale SSH rules. List every node advertising SSH and every
   ssh rule in policy. Rewrite rules as per-pair grants (specific source to specific
   destination); remove identity-wide and tag-wide accept rules; never allow privileged
   target accounts (root, or accounts with passwordless sudo). On headscale, assume every
   SSH grant includes all forwarding, treat any SSH grant as root-equivalent and restrict
   the rule set accordingly. On SaaS, set forwarding flags to denied per action unless a
   documented need exists.

Audit and constrain the serve configuration. On every node running tailscale serve,
   grep the configuration for TCP forwards targeting unix sockets
   (serve --tcp <port> unix:<path>) and remove any that target the agent's own socket or
   other privileged paths (finding 7).

Harden self-hosted control planes. headscale: set systemd memory limits (MemoryMax)
   sized to survive the documented growth rates, enable restart supervision, place a
   rate-limiting reverse proxy in front of the registration endpoints, and restrict network
   exposure (control-plane reachability from an admin network or VPN only, not the open
   internet).

Give identities a clock. Enable node-key expiry on server fleets (opt out of the
   no-expiry default for tagged devices) and enable TPM/Secure-Enclave-bound agent state
   where hardware allows, so stolen identity material does not persist indefinitely.
Interim mitigations from the Tailworm report, as printed (tailworm.com, read 25 October 2026), first parts of each item, dashes replaced by this site.

Block 12 is the one indicator the report prints. It is a SHA 256 hash that the report gives for the script of its first demonstration, "shipped byte exact for hash continuity with the previously published commitment". The script is not public, according to The Hacker News, so this is a value to recognise if the file appears, not something you can fetch. No domain, address, package name or log line is given for any of the findings. Source: tailworm.com, read 25 October 2026.

Text
Reproduction: poc-docker/tailscale-privesc.sh
sha256: c84d461603a2b48023606149b6808e3dfc0733abc6cc38d4b52e0618c3851a2d
The hash line and filename as printed in finding 1 of the Tailworm report, read 25 October 2026. This site has not seen the file.

What a defender can hunt for, as inference from the above and not from a primary: a Tailscale SSH session that opens a forward soon after it starts, forwards that target sockets owned by root, new nodes joining under a tagged identity outside a change window, and a user who reports a Tailscale sign in prompt they did not start. The first two need session logs or recordings that this site has not seen described by a primary; the last two are in the report's own list.

What to do, in the order worth doing

Nothing here needs a patch. The order puts finding out what you have first, then shrinking what a foothold can reach, then the controls the report says held, then detection. Where the vendor and the report differ, both are given.

Take this with you

Defender actions, in order

  • Find every control plane and client: each hosted tailnet, each headscale server (note the version, 0.29.5 or 0.29.6), and each machine running Tailscale. Record the client version with tailscale version.
  • Find where Tailscale SSH is on. Run tailscale debug prefs on servers and read RunSSH, and list nodes in the admin console. If it is off on a host, the SSH findings do not apply to it, on the report's terms.
  • Export the policy file and list every ssh rule. For each, note the source (a user, a group, a tag or autogroup:member means many devices), the destination, the users allowed, and whether root is allowed. Mark every rule that reaches a host running Docker, Kubernetes or similar root only socket services.
  • Rewrite broad rules as narrow ones: one named source group, one destination, one unprivileged user. Remove tag wide and member wide accept rules. The report says this one change stopped the spread in its own test.
  • On the hosted service, switch forwarding off per rule where you do not need it, and confirm the field names with Tailscale first, because the documentation pages read do not list them. Test it from a spare device: a forward should be refused.
  • On headscale 0.29.5 or 0.29.6, treat every SSH grant as root on the target. Delete ssh rules you do not need. With no ssh section, the code read grants none. For the control server findings, keep the server on an admin network, set a systemd memory limit, enable restart supervision and put a rate limiting proxy in front of registration, as the report advises.
  • Decide on disabling Tailscale SSH host by host. Tailscale does not recommend that everyone does, and the report's author does. If a server runs root only socket services, accepts SSH from many devices and you cannot narrow the rule today, switch Tailscale SSH off there after you have another way in.
  • Turn on node key expiry for server fleets, and on Linux with a TPM 2.0 pass the encrypt state flag to tailscaled (block 7 shows it). It has been opt in since 1.92.5. The device posture attribute node:tsStateEncrypted shows which nodes have it on the hosted service; headscale's documentation says device postures are not supported.
  • Enable Tailnet Lock if your plan allows it (the docs list Personal and Enterprise), store the disablement secrets offline, and check tailscale lock status. The report says it stopped only the last step.
  • Remove the app connector capability from devices that do not need it, and search your policy for the node attributes in block 8. In Kubernetes, apply default deny egress to the connector namespace.
  • Find serve forwards to unix sockets: on each node with tailscale serve, list the configuration and remove TCP forwards that target the agent's own socket or other privileged paths.
  • Add detection: audit rules for socket bind, unlink and chmod in home directories, /tmp and /run/user and on tailscaled's own socket paths; alerts on sockets with a looser mode than expected; alerts on auth key issue and use outside change windows; alerts on a new node under a tagged identity.
  • Write the response rule now: delete the device at the control plane, do not only reimage it; rotate auth keys; rotate Tailnet Lock if a signing node was touched; review policy history for changes you did not make. Treat a sign in prompt nobody started as an incident.
  • Ask Tailscale in writing whether a rule change ends forwards on an open connection, because an open pull request describes a case where it did not. Restart tailscaled on sensitive hosts after changing rules until you have the answer.
  • Subscribe to Tailscale's bulletin feed, the Tailscale and headscale release pages and the Tailscale changelog. Read them again each morning this week. Version 1.104.2 or later is not stated to fix any of this.

What could not be verified

  • The findings themselves. Nothing was tested. This site read the report and compared it with the vendors' public code and documents. No proof of concept was seen, and the report says none is public.
  • The Hacker News page. Its site returned a browser check, which this site did not try to pass. It was read from an Internet Archive capture of 25 October at 20:20 UTC, and its claims were checked against the report, the Reddit feeds, the Hacker News API and the repositories.
  • Reddit and the forum comments. Read from Reddit's public Atom feeds, which carry the first part of each thread. Comment authors were not verified. A commenter's claim to be a Tailscale employee was not confirmed.
  • Dates of notice. The Saturday notice rests on The Hacker News and on the researcher's forum comment. Tailscale has not said when it received the report. The Hacker News also says the researcher raised design concerns with Tailscale's chief executive earlier; that was not verified.
  • Which pull requests answer the report. Only finding 11 has a matching description. The link between the open stack and findings 1 to 3, and between 21945 and finding 5, is inference. Descriptions, not code, were read for all of them, and the description of 21945 holds only a tracker reference.
  • The hosted service's forwarding default and key names. The documentation pages read do not list them.
  • The report's lab. Number of hosts, systems and test runs are not stated. Lab identifiers are redacted.
  • X and other social posts. Not read. The thread comments mention a rumour on social media before the report; it was not checked.
  • Whether the CVE record exists elsewhere. CVE.org's search page needs a browser. The NVD API was queried instead and found nothing.
  • Exploitation. None found in anything read. Absence is not proof.
  • Time stamps. Read 20:31 to 21:01 GMT on 25 October 2026. A bulletin, a release, a merge or a statement could appear within the hour.

The question that exposes the gap

If one device your rules already trust is taken over tonight, which of your servers does your SSH rule set let it reach as root, and could you list them without asking the vendor?

Key facts

Sources

  1. PrimaryThe Tailworm security assessment report: 11 findings, their labels, the testing window 22 to 24 October 2026, the chain, the mitigation and detection text, the researcher's note on disclosure. Read in full; the page's file time was 24 October 17:38:43 GMT.Cyberdione Labs Corporation (researcher's report)accessed 2026-10-25
  2. PrimaryThe researcher's organisation home page, used to say what the organisation sells (two products).Cyberdione Labs Corporationaccessed 2026-10-25
  3. PrimaryTailscale's security bulletins page and its RSS feed: 13 bulletins for 2026, TS-2026-013 newest (21 October), TS-2026-004 on SSH Unix socket forwarding fixed in 1.98.9. Nothing about Tailworm at 20:33 and 21:01 GMT.Tailscaleaccessed 2026-10-25
  4. PrimaryTailscale's statement of 25 October 2026 at 00:41 UTC: received the report, working on fixes, not recommending that everyone disable Tailscale SSH, precautions, an advisory promised. Read through Reddit's Atom feed.Tailscale (vice president of engineering, on Reddit)accessed 2026-10-25
  5. PrimaryTailscale release list: v1.104.2 published 21 October 2026 02:55:49 UTC is the newest stable release; v1.98.9 on 20 July. Read through the GitHub API.Tailscale (GitHub)accessed 2026-10-25
  6. PrimaryTailscale changelog: v1.104.2 entry (21 October), and the v1.92.5 entry that made state file encryption opt in on Linux and Windows. Read through the changelog feed.Tailscaleaccessed 2026-10-25
  7. PrimaryPull request 21931, 'ipn/ipnlocal: fix serve app caps leaking across mounts', merged 25 October 00:39:53 UTC: the description that matches the report's finding 11.Tailscale (GitHub)accessed 2026-10-25
  8. PrimaryPull request 21942, 'route SSH forwarding through the privileged monitor', open at 21:01 GMT: forwarded sockets dialled and bound with the user's credentials, never by root tailscaled. Read with 21937, 21941, 21943 and 21944 from the GitHub API.Tailscale (GitHub)accessed 2026-10-25
  9. PrimaryPull request 21944, open at 21:01 GMT: describes that the old check only cancelled live session contexts and a revoked user kept the connection.Tailscale (GitHub)accessed 2026-10-25
  10. PrimaryPull requests created from 24 October 2026 in tailscale/tailscale: the 18 merged and the open stack, counted from GitHub's search results at 21:01 GMT.Tailscale (GitHub)accessed 2026-10-25
  11. Primarytailcfg.go on the main branch: the SSHAction struct with the three forwarding flags, quoted in the technical details.Tailscale (source)accessed 2026-10-25
  12. Primaryconn25.go at tag v1.104.2: the experimental node attribute names, quoted in the technical details.Tailscale (source)accessed 2026-10-25
  13. Primaryprefs.go at tag v1.104.2: the RunSSH preference.Tailscale (source)accessed 2026-10-25
  14. PrimaryTailscale SSH documentation, last validated 5 January 2026: authentication type none, the rule shape, the default rule, check mode, limitations, the commands to switch SSH on and off.Tailscale (documentation)accessed 2026-10-25
  15. PrimarySyntax reference for the tailnet policy file, last validated 8 April 2026: the ssh section; no forwarding field is listed.Tailscale (documentation)accessed 2026-10-25
  16. PrimaryTailnet Lock documentation, last validated 2 December 2025: what it protects, not enabled by default, Personal and Enterprise plans, disablement secrets.Tailscale (documentation)accessed 2026-10-25
  17. PrimarySecure node state storage, last validated 12 January 2026: TPM based encryption, opt in on Linux and Windows from 1.92.5, the encrypt state flag for tailscaled, the posture attribute.Tailscale (documentation)accessed 2026-10-25
  18. Primaryheadscale releases: v0.29.5 on 13 October 2026 and v0.29.6 on 24 October at 10:29:04 UTC, with the 0.29.6 notes (Go certificate distrust, dependency updates, performance changes).headscale (GitHub)accessed 2026-10-25
  19. Primaryfilter.go at tag v0.29.5: sshAccept sets all three forwarding flags true, and a policy with no ssh rules compiles to an empty list. Read with hscontrol/noise.go at the same tag.headscale (source)accessed 2026-10-25
  20. Primaryheadscale policy documentation: no policy loaded means all traffic is allowed; device postures are not supported.headscale (documentation)accessed 2026-10-25
  21. PrimaryNVD keyword searches at 20:37 GMT: tailworm 0 results, cyberdione 0, headscale 2 (a 2023 record and a 2026 record for a third party web interface), tailscale 11, none a 2026 Tailscale client record.NIST National Vulnerability Databaseaccessed 2026-10-25
  22. Reported byThe Reddit thread that titles the report, submitted 24 October at 21:35 UTC: the earliest public trace found, with the same Tailscale statement at 00:34 UTC. Read through the Atom feed; comments are unverified.Reddit (r/Tailscale)accessed 2026-10-25
  23. Reported byHacker News submission of the report at 00:59:48 UTC on 25 October 2026 and its comments, read through the Hacker News API: the researcher's 'reported but not coordinated' and a Tailscale employee's note on peer list trimming. Identities unverified.Hacker Newsaccessed 2026-10-25
  24. Reported byCoverage of 25 October 2026 used as a pointer and for the researcher's statements on disclosure and the proof of concept. Read from an Internet Archive capture of 20:20 UTC because the site returned a browser check. Secondary.The Hacker Newsaccessed 2026-10-25

Share this briefing

Know someone who owns this problem? Send it to them.

Related briefings

The briefing, in your inbox

Practitioner analysis of cyber and AI security news. No vendor noise.

How often

Every new briefing in one email, at 7am, or at 7am, 12:30pm and 6pm. Nothing is sent when nothing is new. Unsubscribe any time.