Skip to content

v0.7.1 — shim CONNECT host validation (security)

Choose a tag to compare

@abruption abruption released this 29 Oct 08:53
· 50 commits to main since this release

v0.7.1 — 2026-10-29

This security release fixes GHSA-84m8-25vr-f74m: the transport shim used the CONNECT host, unvalidated, in local certificate cache paths and certificate identity fields. Severity is Low (CVSS 3.1 AV:A/AC:H/PR:L/UI:N/S:U/C:N/I:L/A:L, 3.7). v0.1.0 through v0.7.0 are affected.

What was wrong

For a CONNECT to port 443, the shim generated a leaf certificate for the requested host and named the cache files after that host. A host containing ../ or an absolute path selected files outside the shim's certs directory. The shim then created those files, or overwrote existing ones with a newly generated random private key. The fixed suffixes .crt, .key, .ext and .crt.csr were always appended, and the parent directory had to exist and be writable by the shim process.

The shim generates the certificate only after the upstream proxy accepts the CONNECT. Whether the Dots platform proxy accepts such a host was not tested.

The listener is bound to 127.0.0.1. However, tailscaled runs with --tun=userspace-networking, which forwards inbound tailnet TCP for the node address to the same port on 127.0.0.1. Tailnet peers whose ACL permits port 18089 can therefore reach the shim, as well as local processes.

This validation found no path to remote code execution, a trusted misissued certificate, or disclosure or replacement of the local CA key. That does not prove these are impossible. In the isolated tests, no crafted host containing / produced a signed certificate, and the existing CA files were not overwritten.

Update

v0.7.0 declares the same Tailscale baseline (1.104.4), so use the ordinary package update. Verify an independent cloud recovery terminal first:

/workspace/.dots-tailscale/dots-ts update check --tag v0.7.1 --proxy http://browser-proxy:8889 --json
/workspace/.dots-tailscale/dots-ts update apply --tag v0.7.1 --proxy http://browser-proxy:8889 --confirm-recovery-terminal --json

update apply replaces the four sources and manifest and restarts only the shim, so the fix takes effect when the transaction completes. Tailscale binaries, node state and SSH keys are not changed.

Packages declaring Tailscale 1.102.4, including v0.6.0, follow the explicit baseline migration directly to v0.7.1.

Until you update: if your tailnet policy allows every port to this node, restrict it to the ports you use, for example SSH on 22. In the isolated test, a policy that allowed only port 22 kept peers from reaching the shim.

Changes and compatibility

  • The shim validates the CONNECT target before dialing upstream. It accepts hostnames (letters, digits and hyphens in each label). It also accepts bracketed IPv6 literals, but not on port 443. Ports must be 1–65535 without leading zeros. Other targets receive 400 Bad Request, and the log does not echo the rejected text.
  • Cached leaf certificates are named by the SHA-256 of the host, so request text never becomes part of a filesystem path. The certificate generator also re-checks the host itself.
  • Hostnames used for Tailscale control and DERP are unchanged. Each cached certificate is regenerated once under its new name after the update. Old host-named files in shim/certs are left in place and are no longer used. The local CA and bundle.crt are unchanged.
  • Of the four executable sources, only shim.py changes. tailscale-setup.sh, dots-ts and dots_proxy.py are identical to v0.7.0.

Validation

  • New regression tests (tests/test_shim_cert_host.py) fail against the v0.7.0 shim and pass with the fix. They cover rejection before upstream dialing, rejection before any file creation, preservation of an existing file outside the certificate directory and of the CA key, and certificate reuse.
  • At the release-candidate commit, the full suite on arm64 Linux ran 364 tests on each of Python 3.11 and 3.13: 363 passed, 1 failed, 0 errors, 0 skipped.
  • The one failure, test_fresh_install_validates_and_places_both_real_version_probes, also fails on unfixed v0.7.0 source in the same environment. The arm64 test host rejects the compiled x86_64 version probes.
  • The 54 shim tests pass on Python 3.8 (0 skipped).
  • GitHub Actions do not run in the private fork. The x86_64 workflow results for the merged release commit are linked from the GitHub Release.
  • In an isolated container, the fixed shim answered crafted hosts with 400 before contacting a fixture upstream that accepts every CONNECT. It wrote no files outside its certificate directory, and an ordinary host still received 200 and a cached certificate.
  • In an isolated tailnet (a private coordination server on a network without external access), a peer reached a loopback-only listener under userspace networking. A policy limited to port 22 blocked that reach.

These checks did not exercise the Dots platform proxy or a live Dots installation.

CVE status

A CVE was requested from GitHub on 2026-10-29 and has not been assigned yet. The number will be added to the advisory and this release when it is assigned.

Final release verification

Release commit: e49fa7b41af495c224590c7bd355075be632f97a.

  • Before merging, the same commit ran on GitHub-hosted x86_64 runners in a temporary private repository. Python 3.11 and 3.13 each ran 364 tests: 364 passed, 0 failed, 0 skipped. ShellCheck, the research checks and the amd64 artifact smoke test also passed.
  • Public workflows on the release commit:
    • Core checks: Linux Python 3.11/3.13 tests, manifest, Bash and ShellCheck.
    • Research checks: recovery and lifecycle tests on Python 3.12/3.13.
    • Official artifact probes: 1.102.4 and 1.104.4 archives, checksums and isolated real CLI/daemon version outputs.

The eight release assets were built from the exact commit. Both source archives match every tracked file (126 files), and the four individual sources match the original manifest and the archive copies. Publishing this release does not deploy it to an existing installation. Apply it with dots-ts update apply --tag v0.7.1 as described above.