Skip to content

Repository files navigation

Meowshell

CI NuGet License: MIT

A remote shell you can drop into any .NET app — Android included — in one line, with no server to run, no port to open, and no keys to manage by hand.

Meowshell packages tailscale/tailcat (netcat over Tailscale's data plane, without its control plane) together with meowshell, a companion launcher that fixes up the shell environment tailcat hands a session so it works on Android too, not just desktop. Add the Meowshell package, call one method, and you have a real interactive shell — PTY, tab completion, job control — reachable from anywhere, torn down on your own schedule.

var options = MeowshellOptions.Create(TimeSpan.FromMinutes(5)) with
{
    AuthorizedKeys = "alice@github", // fetches alice's SSH keys from GitHub
};
await using var server = await MeowshellServer.StartAsync(options);
Console.WriteLine(server.Address); // tailcat ssh <address>, from anywhere

AuthorizedKeys is the mode to reach for by default. InsecureNoAuth exists for when the address itself is the only credential you want — pair it with AllowClientKeys so a leaked address alone isn't enough to get a shell.

That one call is the common case. The same package is a lot more than a shell:

  • No system ssh/scp/sftp anywhere. Every client operation — interactive sessions, SFTP, file transfer — is a native Go implementation under the hood, not a wrapper around a binary your platform may not even have. That's what makes any of this possible from inside an Android app sandbox in the first place.
  • One login, everything multiplexed. MeowshellAgentConnection opens a single connection and shares it across a shell, the full SFTP verb set (Upload/Download/Mkdir/Rename/Chmod/Symlink/...), and -L/-R/-D port forwarding — instead of a fresh process and handshake per operation.
  • It's also a real SSH client, not just a tailcat one. That same connection type reaches a general SSH host by hostname, with real host-key verification (known_hosts, trust-on-first-use), ProxyJump chaining, and password/keyboard-interactive/certificate auth — including keys backed by Android's Keystore, where the private key never leaves secure hardware and never touches your process memory.
  • A SOCKS5 proxy and TCP port forwarding, loopback-restricted by default with optional token auth, and available over a Unix domain socket instead of TCP on platforms where "every other app on the device can reach your loopback port" is a real threat model, not a hypothetical.
  • Typed results and real errors, not scraped stdout. Addresses, ping results, file listings, and environment diagnostics all come back as real C# types; every failure is one TailcatException carrying the actual diagnostics, not a bare non-zero exit code to guess at.
  • Orphan-proof by construction. Every long-lived session arms parent-death protection (a Job Object on Windows, PDEATHSIG on Linux/Android) before it ever starts listening, so a crashed, OOM-killed, or force-stopped host process can't leave an unauthenticated shell running behind it — the exact failure mode that matters most on Android, where the OS kills app processes far more readily than a desktop or a server ever would.
  • A shell isn't the only thing you can serve, either. Forced-command sessions, an SFTP-only file service, and an "exit node" mode that lets an authorized client reach any port the host machine can dial are all one option away — combine or use standalone.

Also one-shot operations for key management, address parsing/resolution, and connectivity checks (tailcat ping, genkey, printpub). See dotnet/README.md for the full surface, every option, and the one thing (a console-attached ssh client, as opposed to a programmatic session) an Android app sandbox can't run.

What's in this repo

  • Meowshell — the .NET library above (dotnet add package Meowshell): shell/SFTP/forced-command sessions, a SOCKS5 proxy, port forwarding, and one-shot key/address/file operations. See dotnet/README.md for the full API.
  • Meowshell.Runtime.{linux,windows,android} — the native tailcat and meowshell binaries for each platform, pulled in automatically as a dependency of Meowshell.
  • Meowshell.Demo — a real, installable Android app: one button generates a throwaway shell address.
  • Meowshell.AndroidProbe — a minimal app that only proves the packaged binaries are found and run on a real device; what CI checks.
  • meowshell, the CLI — a standalone launcher/shim around tailcat, for use outside .NET (Termux, adb shell, scripts).

Supported platforms

Platform Architectures
Android arm64-v8a, armeabi-v7a, x86_64, x86
Linux amd64, arm64, armv7, 386
Windows amd64, arm64

Building from source

./build.sh                     # every target the toolchain allows
PLATFORMS=linux ./build.sh     # just one

Clones tailscale/tailcat, builds it alongside this repo's meowshell, and writes binaries to dist/. Android needs the NDK (ANDROID_NDK_HOME, r19+) for cgo-based DNS resolution; Linux and Windows are pure Go. See ./verify-binaries.sh and e2e/ for how CI checks the result.

Security

This isn't an unreviewed pile of process-spawning code: a full security review found and fixed eleven real issues, from an unencrypted HTTPS proxy path to release builds tracking a mutable upstream branch. See SECURITY_REVIEW.md for the current threat model, findings, accepted risks, and verification status. The accompanying REVIEW_MAP.md groups every first-party file by runtime boundary and records the order and focus of the repository review.

License

MIT for this repo's own code. The vendored/patched tailscale/tailcat source it builds against is upstream's own, BSD-3-Clause-licensed work.

About

Meowshell — A remote shell you can drop into any .NET app (Android included ) — in one line, with no server to run, no port to open, and no keys to manage by hand.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages