github juanfont/headscale v0.29.7

3 hours ago

Minimum supported Tailscale client version: v1.80.0

Security

This is a security release. It fixes findings from Anthropic's oss-scanner project and
the Tailworm report. None are critical, but some can cause denial of service in
Headscale. We recommend that all users upgrade to Headscale 0.29.7 and Tailscale
v1.104.4 or newer as soon as possible, especially those using Tailscale SSH.

Tailscale v1.104.4 fixes vulnerabilities in SSH forwarding, SSH session handling and
Serve. These fixes run in tailscaled on your nodes; upgrading Headscale alone does
not apply them.

See Tailscale's security bulletins and Tailscale SSH: Findings and fixes.

To disable SSH agent and port forwarding on a node, set
TS_SSH_DISABLE_FORWARDING=1 in the tailscaled service environment and restart
the service. This setting applies to all Tailscale SSH sessions on that node and
is also available in older clients. #3624

This release also fixes the issues that oss-scanner
reported in Headscale: ANT-2026-MLP8ZR5T, ANT-2026-LYVGXVSW, ANT-2026-AWGRB7O1, ANT-2026-QMCAFJ1Q, ANT-2026-RQS7JAPP, ANT-2026-5B6KE87K, ANT-2026-KFCFFM34, ANT-2026-K903ZEUA, ANT-2026-NM50ZP4N, ANT-2026-ZC18AF82, ANT-2026-NWTIBB02, ANT-2026-MX8FKG4K. #3603

Changes

  • Metrics are no longer exposed to unregistered clients through the Noise protocol. They remain available only on the configured metrics listener; an empty metrics_listen_addr disables that listener #3623
  • Update the Tailscale dependency to v1.104.4, which bounds how much of an unexpected DERP HTTP response is read #3577
  • Keep pending registrations and OIDC logins at capacity instead of evicting ones awaiting approval; new requests get a retry response, and registered nodes keep capacity for SSH checks #3586
  • Cap stored pending registration data at 64 KiB, keeping tags and expiry; oversized interactive registrations are rejected #3586
  • Check the OIDC login type before storing anything, accept each OIDC callback only once, and free an SSH check's slot once the client has read its result #3586
  • Stop serving a route that is a single address inside the node IP ranges, such as 100.64.0.11/32 or ::ffff:100.64.0.11/128, because it names a node, not a subnet; the route stays approved and listed, and wider routes are still served #3603
  • Require a valid pre-auth key to re-register an expired tagged node #3603
  • Another user's key or login on a tagged machine now creates a new device for that user instead of re-authenticating the tagged node #3603
  • Fix one node with a stored key expiry outside the years 0 to 9999 in UTC failing the map of every node that can see it; it is now left out of its peers' maps and the startup check names it with the fix command #3603
  • Refuse a key expiry outside the years 0 to 9999 in UTC on registration, on the OIDC token-expiry path and in headscale nodes expire / POST /api/v1/node/{node_id}/expire (HTTP 400); the latest accepted expiry no longer fails node listings on PostgreSQL in a zone east of UTC #3603
  • Keep the first 256 endpoints and 4096 announced routes from client reports; oversized hostnames, requested tags or other metadata return a registration error or HTTP 413 on map updates. Zoned IPv6 endpoints are refused #3603
  • At startup, trim stored hostnames, endpoints and routes to the client-report limits and remove zoned endpoints. Hostinfo exceeding its size or tag limit is dropped until the next valid report #3603
  • Pending interactive registrations and follow-up waits keep only the hostname, OS and requested tags; other device details arrive with the first map request. Reauthentication preserves routes, services and endpoints #3603
  • Fix web reauthentication dropping the discovery key, so peers could not reach the device #3603
  • A stalled request body, or a Noise tunnel with no open request, is closed after 30 seconds #3603
  • A registration follow-up from a machine other than the one that started the registration is refused before it waits #3603
  • Only the newest follow-up waits on a pending registration or SSH check; older ones are answered at once #3603
  • Fix registration locks staying in memory after the registration ends #3603
  • Fix concurrent deletes of one node freeing its addresses and announcing its removal more than once #3603
  • OIDC verifies an email against the document supplying it; an email_verified flag without an address no longer verifies another document's email #3603
  • Fix release builds reporting their version with a +dirty suffix #3584
  • Fix SSH policy acceptEnv having no effect, so allowed environment variables reach SSH sessions. Upgrade SSH destination nodes to Tailscale v1.104.4 or newer before using acceptEnv, because older clients can disclose forwarded values #3569

Upgrade

Please follow the steps outlined in the upgrade guide to update your existing Headscale installation.

Changelog

  • c0a51b2 .gitattributes: mark golden data as generated
  • c9cf210 CHANGELOG: align the 0.29.7 entries with earlier releases
  • 3d9031c CHANGELOG: document SSH acceptEnv fix
  • 5083559 CHANGELOG: document the 0.29.7 security and patch release
  • 8651eb9 CHANGELOG: list the oss-scanner findings for 0.29.7
  • abe807a CHANGELOG: list the pending authentication bounds for 0.29.7
  • 3345493 auth, state: keep only hostname, OS and tags in pending registrations
  • 1b7435c auth: check the follow-up's machine key before it waits
  • 99d10b9 db, state: let only the delete that removed a node free its addresses
  • 151c852 go.mod: pin golang-lru/v2 to main for expirable.Close
  • 718cbc3 go.mod: tidy for Go 1.27
  • 044d8f5 go.mod: update tailscale.com to v1.104.4
  • 37b4237 hscontrol: bound pending authentication without evicting sessions
  • be114c0 hscontrol: refuse a key expiry that cannot be encoded
  • c32bf08 hscontrol: remove unused OIDC user change result
  • 3bb6d3a integration/tsic: drop unused watchIPN
  • fd6547f integration: guard SSH acceptEnv forwarding
  • 15af45c mapper: skip peers whose key expiry cannot be encoded
  • 2d881c5 noise: restrict metrics to the metrics listener
  • bc3ac27 noise: time out stalled bodies and idle tunnels
  • e1c6cb9 oidc: keep email_verified with the address it came with
  • 6e0d520 policy/v2, servertest, hscontrol: add tailnet overlap route captures
  • 02b1528 policy: pin SSH forwarding behavior and recommend upgrades
  • f193207 prek: exempt step captures from the large file check
  • 93340a6 release: reject dirty sources and build artifacts
  • 9318ce4 release: retry existing tags without the Docker downgrade
  • 99cb5c1 servertest: add login, profile, restart and register log helpers
  • c848c5a servertest: add relogin and auth key helpers
  • 7a51c8f servertest: compare router self routes with captures
  • 9ce0b28 servertest: compare user profiles in via captures
  • 4647866 servertest: list passing via captures
  • e56661c state: bound client reports of nodes loaded at startup
  • 4d04361 state: drop registration locks once unused
  • c8fb25d state: give another user's key on a tagged machine a new device
  • e6219cd state: need a valid pre-auth key to re-register an expired tagged node
  • 2852b65 state: never serve a single address inside the node ranges
  • 514979b state: stop the auth cache TTL sweeper on Close
  • 1d11be0 testcapture: record multi-step captures and API error detail
  • d116f2f testcapture: refuse golden captures that name no tool commit
  • a4c0a09 types, auth, noise: let one request wait on each auth session
  • 52ba6a3 types, noise: bound the Hostinfo and endpoints a client reports
  • f20366b types: emit SSH environment capability by default

Don't miss a new headscale release

NewReleases is sending notifications on new releases.