What Is Tailcat? The Encrypted Netcat That Trades a Tailnet for a Token
Tailcat is Tailscale's account-free encrypted netcat. Understand the token trade-off, direct-versus-relay path, and why it is not a tailnet.

Tailcat is an open-source Go CLI from Tailscale that gives two machines an encrypted point-to-point TCP connection without a Tailscale account, without a tailnet, and without root, route, or DNS changes on either host. One machine runs a listener, prints a short connection token, and hands that token to the other machine out of band. The second machine passes the token to its Tailcat client and the two ends exchange data over an encrypted path. The project describes it as “a remix of Tailscale open source pieces to act like netcat, but over Tailscale’s data plane, without Tailscale’s control plane.” That sentence is the whole product. Everything else is the consequence of taking it literally.
This guide is for operators deciding whether to use Tailcat for a short-lived task. It draws on an ABS canonical dossier distilled from Marvin’s frozen, independently QA-verified research package and rechecked against the v0.4.0 README, release, and Homebrew formula on 2026-09-01.
The plain-English rule
If you can safely hand a password to the person on the other end, and your task is small enough to outlive a single terminal session, Tailcat is reasonable. If you need recurring access, an identity for every user, an access policy, a device inventory, or an audit trail, you want a managed Tailscale tailnet or a comparable governed mesh, not Tailcat. Tailcat’s own product page says this directly: “If you need ongoing and governable access to multiple users, services, agents, or machines, use Tailscale.”
How a Tailcat connection actually forms
Tailcat reuses three Tailscale data-plane components and leaves the control plane behind:
- Token. The listener prints a case-sensitive
tc…token containing the server’s WireGuard public key, a separate path-discovery public key, and DERP region information. Possession of the token is the default connection capability. Treat it like a password; do not paste it into tickets, chat, screenshots, shell transcripts, or DNS records. - DERP rendezvous. The client uses the DERP region embedded in the token to reach Tailcat’s encrypted relay. WireGuard is initiated across this rendezvous.
- WireGuard handshake. The server is authenticated against the public key inside the token. Payload traffic is encrypted end-to-end with userspace WireGuard.
- Direct UDP attempt. Tailscale’s magicsock transport uses STUN-based endpoint discovery and UDP hole punching to try a direct peer-to-peer path. This step is opportunistic. Hard NATs, blocked UDP, and some mobile carrier networks keep traffic on DERP.
- DERP fallback. If the direct path fails, encrypted traffic keeps flowing over the relay. The README says the connection “still works, just with rate-limited throughput” when relayed; that is best effort, not a guarantee.
Three architecture details matter:
- WireGuard runs in userspace, so no kernel TUN/TAP, host routes, or DNS are configured. That is why root is not required.
- TCP is terminated inside gVisor Netstack, inside the Tailcat process. The TCP endpoints you see are userspace endpoints, not host sockets.
- The browser/WASM build is relay-only. There is no direct UDP path from a browser until upstream adds WebRTC support, so do not infer native CLI performance from a browser demo.
What Tailcat is not
- Not a tailnet. There is no account, no central identity, no ACL policy, no device management, no audit log. You give a token to a person, a script, or a CI step, and that is the entire authorization story unless you layer saved client keys with a server
--allowlist. - Not netcat. Plain
netcathas no encryption, no NAT traversal, no relay fallback. Tailcat is closer to “encrypted netcat with DERP” than a substitute for netcat on a trusted LAN. - Not a public web tunnel. Tailcat does not hand you a public HTTPS URL like ngrok or Cloudflare Tunnel. Its tokens are opaque capability strings, and browsers lowercase hostnames, so you cannot paste a token into a browser address bar. Use
tailcat socks <token> <command>for CLI tools, or a conventional local forward. - Not durable storage. A
tailcat recvdirectory is a write-only drop box for one listener. It is not a backup target, not an object store, not a substitute for S3.
When it fits and when it does not
It fits when the task is narrow and temporary: piping a build artifact to a colleague for a quick test, exposing one localhost port for a demo, sending a single file through a drop box, or troubleshooting why a service behind NAT cannot be reached. The default ephemeral server key gives you per-process capability expiry, which is the safe default for these cases.
It does not fit when you need persistent access for a person, a service account, or a fleet; when a security policy must enforce who-can-reach-what over time; when the connection needs to outlive a process restart without the token becoming a long-lived secret; or when the deployment requires an uptime or throughput commitment. Public Tailcat DERP is free, rate-limited, best effort, has no SLA, and may be revoked. Treat it like an experimental relay, not infrastructure.
A few operator disciplines close most of the safety gap:
- Use
--key=new(the default) for one-off work and stop the listener when finished. - For a stable endpoint, treat saved client keys and server
--allowlists as an advanced key-lifecycle project. They can narrow access to named client keys, but they are not a replacement for user identity, policy, or auditing. - Prefer
tailcat serve 22(proxies to your real SSH daemon with its own authentication) overtailcat serve no-auth-sshfor any host you would not publish a password to. - Use
tailcat recvfor write-only intake and the defaulttailcat serve filesmode for a read-only directory. The rooted file service uses Go’sos.Rootso paths cannot escape the served directory; a no-auth shell does not have that confinement.
Failure modes operators should expect
- Browser hostname lowercasing. Mixed-case tokens placed in a URL hostname slot are silently downcased, so the connection fails in a way that retrying will not fix.
- Saved-key reuse. A saved server key keeps the same token alive across restarts, which means anyone who ever saw that token can connect again unless the server is using
--allow. - SOCKS plus allowlist misconfiguration. Early public builds presented a fresh ephemeral key for
tailcat socks, ignoring the saved client key, so a server with--allowquietly timed out instead of refusing. Pin v0.4.0 or newer, which contains the fix. - Public DERP rate limits and revocability. A long-running workflow pinned to a single DERP region can degrade or disappear if the region changes or access is revoked. The repository has an open issue tracking multi-region registration for static tokens.
- Documentation drift. The README at the repository’s default branch has, during launch week, shown commands that did not match the latest release binary. Pin the version and re-check before re-publishing instructions.
Done means
You stop the Tailcat listener. With the default ephemeral key, the in-memory key and its token are discarded when the process exits, and any copy of the token is no longer useful. If you generated saved keys, rotate them and update any --allow lists that referenced them.
What this article does NOT cover
- Installing Tailcat on production hosts, unattended services, or shared infrastructure.
- Reproducible Docker, Nix, Arch, or Go install commands outside the macOS test boundary described below.
- Self-hosted DERP sizing, DNS, TLS, monitoring, capacity, or abuse handling.
- Browser/WASM performance, since the browser build is relay-only and is not a benchmark for the native CLI.
- Any independent security audit; none was identified in the cited sources.
Related guides
- Cloudflare Tunnel: a public HTTPS route is a different tool
- Hermes vs OpenClaw: choosing a durable agent path
- Start Here: local AI and agents
Sources / what we ran
- Tailcat README, pinned to
v0.4.0: raw.githubusercontent.com/tailscale/tailcat/v0.4.0/README.md, retrieved 2026-09-01. - Tailcat release v0.4.0 (published 2026-08-31): github.com/tailscale/tailcat/releases/tag/v0.4.0, retrieved 2026-09-01.
- Tailcat product page (token handling, hosted-relay boundary): tailscale.com/tailcat, retrieved 2026-09-01.
- Tailscale DERP reference: tailscale.com/docs/reference/derp-servers, retrieved 2026-09-01.
- Tailscale direct/relay connectivity reference: tailscale.com/docs/reference/device-connectivity, retrieved 2026-09-01.
- Homebrew formula (version 0.4.0): formulae.brew.sh/formula/tailcat, retrieved 2026-09-01.
- Arch package availability: aur.archlinux.org/packages/tailcat-bin, retrieved 2026-09-01.
- WireGuard protocol context: wireguard.com/protocol/, retrieved 2026-09-01.
- gVisor Netstack reference: gvisor.dev/docs/architecture_guide/networking/, retrieved 2026-09-01.
- Rooted file-service semantics: pkg.go.dev/os#Root, retrieved 2026-09-01.
- Upstream fix separating node and discovery keys: github.com/tailscale/tailcat/commit/cb1e0d753e9ace2ebc5bff147ccf1eee6ccdd463, retrieved 2026-09-01.
- Reproducible SOCKS plus allowlist failure and fix: github.com/tailscale/tailcat/issues/24, retrieved 2026-09-01.
- macOS release-asset decision: github.com/tailscale/tailcat/issues/58, retrieved 2026-09-01.
What we actually ran for this guide is the local narrow test boundary recorded in the dossier: a Homebrew v0.4.0 Apple Silicon Tahoe bottle was extracted without a global install, tailcat version reported v0.4.0, and v0.4.0’s help surface plus the stdin/stdout pipe, one localhost TCP port, fixed-token SOCKS plus curl, no-auth SSH remote command, and recv/cp upload were exercised against Tailcat’s local test DERP (TS_DEBUG_TAILCAT_LOCAL_DERP=1, --derpmap-url=none) on a single machine. We did not run public DERP, NAT traversal, two-machine transfers, Linux/Windows execution, Docker, Go compilation, Nix, or Arch; commands and caveats that depend on those paths are documented but not tested by us. Recheck commands against the then-current release before re-publishing.



Submit a take
Have a different read on this? Drop a comment below — your email isn't published, and I read every one. Nothing leaves the site until I approve it.