Skip to content

security

A shell in a browser deserves paranoia.

You are considering exposing a terminal to the internet. That is a serious thing to do, so here is exactly how mtmux is built, what it protects against, and what it does not.

Everything on this page is implemented today in @repo/crypto. Where something is a design intention rather than shipped code, it says so.

Data path

tmux server

Unix socket, your uid. mtmux reads it as a normal client would.

mtmux CLI

Seals every frame for the paired browser. Config and token live at ~/.mtmux/config.json, mode 0600.

broker (untrusted)

Sees ciphertext, sizes and timing. No key, no plaintext, no pairing secret.

your browser

Derives the same keys from the pairing run, and keeps a device key to reconnect without a new code.

Guarantees

Pairing is a balanced PAKE

CPace over ristretto255, ciphersuite CPACE-RISTR255-SHA512, implemented against draft-irtf-cfrg-cpace-13 and checked over the draft's own test vectors.

The broker never sees the secret

The code splits into a 2-digit routing slot and a 6-digit secret. The slot routes; the secret is the PAKE password and is never transmitted, not even as a hash. Only the first two digits reach our servers.

One wrong guess ends it

Each side proves it derived the same key before anything is sent. A failed confirmation destroys the pairing, so an online guesser gets exactly one attempt at a million — and the machine says so, and slows down.

Keys are derived, never sent

An HKDF-SHA256 schedule over the CPace transcript produces one key per direction plus a confirmation key. Nothing derived from them crosses the wire.

Frames are sealed and counted

AES-256-GCM with a per-direction nonce and a monotonic counter, so a replayed or reordered frame fails authentication instead of being decrypted.

The QR keeps the code off the wire

The code rides in the URL fragment, which browsers never send to a server — so scanning it does not hand the code to whoever serves the page.

Nothing to port-forward

The CLI dials out to the broker. There is no firewall hole to open, no sshd exposed, and no reverse proxy to misconfigure.

Revocation forgets a key

Reconnecting a known browser is a signed Ed25519 challenge, so mtmux devices revoke on a device id is enough to lock it out permanently.

What we defend against

  • A hostile or compromised broker reading or injecting session traffic.
  • A broker that knows the whole code and tries to pair your CLI to its own browser.
  • Passive network capture on hotel, café or cellular networks.
  • Someone who watches you scan and captures the code after it is spent.
  • Replay or reordering of captured frames, via the per-direction nonce counter.
  • A lost phone: revoke its device id and its key is worthless.

What we don't

  • A compromised machine. If your box is owned, so is the session.
  • An unlocked, already-paired phone in someone else's hands.
  • Traffic analysis — the broker can infer when you are typing from frame timing.
  • Malicious browser extensions on a paired desktop.
  • Anything your allow-list lets a paired browser read on disk.
  • A weak or shared machine account: mtmux runs as you, with your permissions.

Don't trust the broker? Don't use it.

Two escape hatches. --local serves your LAN and loopback and contacts no broker at all — it is not a degraded mode, it is the same server without the tunnel. Or run the broker yourself and point the CLI at it.

mtmux start --local
MTMUX_API_URL=https://mtmux.internal mtmux
mtmux devices # device ids + last seen

Disclosure

Report anything you find to [email protected]. We acknowledge within one business day, ship fixes for critical issues as fast as we can, and credit reporters in the changelog unless asked not to.

CLI & client source
MIT, on GitHub
Pairing suite
CPACE-RISTR255-SHA512
Transport
AES-256-GCM
Third-party audit
none yet
Session frames
never stored

No independent cryptographic audit has been performed. The CPace implementation is verified against the draft's published test vectors, which proves the group maths and encoding are right — it does not prove the surrounding protocol wiring is. Read it yourself before you trust it with something that matters.