Report 3: the TS-2026-006 fix (digit-only username rejection) was silently removed after v1.102.0

2026/10/24

Regression: TS-2026-006 control absent from current stable and main

Severity (my assessment): none known standalone today (residual defenses hold — see below), but a security-bulletin fix regressed across patch releases of the same minor without announcement. Reported as a process/regression issue. Date found: 2026-10-24 · Reporter: psn · shared privately with Tailscale 2026-10-24

Summary

The digit-only SSH username rejection deployed for TS-2026-006 (“Tailscale now disallows the use of UIDs or numeric-only usernames via SSH”, commit f368a96e, 2026-06-11) is present in v1.98.9 and v1.102.0, but is absent from v1.102.4 and from main as of 2026-10-24.

Verification

In ssh/tailssh/tailssh.go, clientAuth used to contain, before setInfo:

uidRegex = regexp.MustCompile("^[0-9]+$")
...
if uidRegex.MatchString(cm.User()) {
	return nil, c.errBanner(fmt.Sprintf("rejecting username %q. Usernames that consist of only digits are not allowed as they are ambiguous with numerical UIDs", cm.User()), nil)
}

Checked against raw.githubusercontent.com/tailscale/tailscale/<ref>/ssh/tailssh/tailssh.go:

ref uidRegex present?
v1.98.9 yes
v1.102.0 yes
v1.102.4 no
main (2026-10-24) no

No commit in the public history of ssh/tailssh/tailssh.go advertises removing it; the mid-September 2026 refactoring of that directory (e.g. 664ba588 “split the OS-specific parts of the server into their own files”, 2026-09-15, and neighboring changes) falls in the window. A git bisect start v1.102.4 v1.102.0 -- ssh/tailssh/ will pin it exactly.

Current residual defenses (why no known exploit today)

I could not construct a working root bypass in v1.102.4 that the removed check would have blocked — so this is defense-in-depth loss, not a demonstrated vulnerability. But:

  1. The TS-2026-006 bulletin tells customers the control exists; current stable doesn’t have it. Fleet audits against that bulletin’s claim will mis-assess.
  2. Its removal may interact with future NSS/getent edge cases the original fix was designed to foreclose (numeric ambiguity is exactly where lookup bypasses keep recurring: TS-2026-006, TS-2026-009).

Suggested remediation

  1. Restore the check on main and backport to the 1.102.x release branch (1.102.1+ shipped without it).
  2. Add a regression test pinned to the bulletin number so refactors can’t silently drop it again (the existing fix shipped with a test; the test appears to have been dropped with the check).
  3. Consider a release-process rule: commits touching files that carry security-fix references (bulletin IDs, Fixes tailscale/corp#NNNN) get a second reviewer, and changelogs mention security-fix regressions.

Detection

For fleets: no client-visible signal. An integration test (ssh -o User=0 target must be rejected with the “digits” banner) is the cheapest guard.