RelayKey

The detail

How it works, and what it does not protect

The front page is the short version. This is the long one — for anyone deciding whether to put RelayKey on a computer that matters.

What happens when you connect

Three parties, and only outbound connections. Below each one is what it can actually observe — including the part most tools leave out.

Endpoint

Your client

The macOS app, the Windows app, the CLI, or a browser tab. Holds your account key, made on first launch by the OS random source and exportable to an encrypted backup file.

Needs
An outbound WebSocket. No listening port, no inbound rule.

outbound wss ▸

Shared infrastructure — not ours

Relays

Messages pass through relays to find the other computer. Everything is encrypted before it gets there, so a relay only ever carries data it cannot read.

Sees
That a message arrived for someone, when, and how big it was. Not what it says, and not who sent it. Caveat: the timing and size are real — see below.

◂ outbound wss

Endpoint

The machine

A Windows service, a launchd daemon or a systemd unit, as LocalSystem or root. It executes for peers it has paired with and silently ignores everything else.

Needs
An outbound WebSocket. Nothing forwarded to it, ever.

Then it connects directly

Relays are fine for “run this and show me the output” and hopeless for a screen: every message is a signed, double-encrypted envelope that round-trips through a relay. So for anything interactive, the relay channel carries only the WebRTC offer, answer and ICE candidates, and the session itself moves onto a data channel — directly between the two machines wherever the network allows it.

Caveat — when direct fails

Behind strict NAT or CGNAT a direct path may not exist, and the session falls back to a TURN relay. That relay forwards DTLS ciphertext it cannot decrypt — but it does observe both endpoints' IP addresses, when you connect, and how much traffic flows. You can point RelayKey at a relay you control instead: use your own relay.

  1. Open a client and look at your account

    First launch generates your account key. Settings → Account shows your Account ID — the short name for the account, safe to share — and the install command carrying the address machines pair to.

  2. Run one command on the machine

    The client mints a single-use pair code, valid for one hour, and writes the command for you.

    relaykey.exe -install -paircode=abc123xxx
  3. Compare six digits

    Both sides derive the same short authentication string from the code and both keys. If the digits match, the channel is authenticated and the code burns. If they do not, something is between you — do not continue.

Why there is no RelayKey server

“No backend” is not a slogan here, it is a property with three consequences a technical buyer can check.

There is no account database, so there is nothing of yours to leak. Your identity is an account key generated on your device by the OS random source. We do not have it, cannot reset it, and cannot be compelled to hand over a list of your machines, because no such list exists outside your own client.

The rendezvous layer is interchangeable. The message relays are public, accept messages from any account without registration, and there are dozens of them. If one disappears or blocks you, you change a config line. If you would rather not use public ones at all, point the agent at a private one you run.

Nobody's hosting bill is between you and your machines. The one place we do spend money is the shared TURN relay used when a direct connection is impossible, which is why that path is rate-limited and best-effort — and why bringing your own relay is a documented, first-class setting rather than an enterprise upsell.

Caveat — the honest cost

The same property is the reason there is no revocation broadcast. If your client key is compromised you must revoke it on each machine individually (relaykey peers revoke <public ID>, or “Forget machine” in the app). relaykey peers list exists to make that enumerable. A tool with a server would push one revocation and be done; this one cannot.

Read this: it gives full control of a computer

The honest framing, and the one used in RelayKey's own security document, is that this is a remote access tool with the operator's consent, and it deserves to be designed like one — including being clear about what it does not protect against. If you are evaluating it, read this section before the feature list.

What is protected

Command and output confidentiality against relay operators and network observers. Authorisation: only paired peers can execute anything, and that mutual knowledge of each other's public key is the entire authorisation model. And the pairing moment, which is the only point where a secret crosses an untrusted path.

The risky moment: the pairing code

The pair code is 8 characters — short because it has to be typed, pasted into an install command, and sometimes read aloud. Anyone who obtains it while it is live can pair with the machine and thereby gain SYSTEM. That is inherent to having no server to authenticate against, not an oversight, and it is bounded by six layered controls: single use, a one-hour expiry, proof-of-work on the enrolment beacon, a 20-attempt budget after which the agent burns the code and logs loudly, handshake HMACs proving both sides hold the code, and the six-digit string you compare by eye.

Proof-of-work is a cost multiplier, not a wall — someone with a hundred machines gets a hundred times the guesses. The attempt budget is the hard cap. And if the code leaks, the attacker pairs first, and you never look at the machine's console, the machine is compromised. The mitigation is operational: generate the code on the machine, use it immediately, check the digits.

What the relays can see

A relay never sees what you send — that is encrypted, and it has no key. Nor can it tell who sent a message: the sender is not named.

What it can tell is that two computers are talking. Timing and size are real. Someone running a relay and watching sees a message arrive and a reply leave moments later, and can reasonably conclude the two are in a session together. Sizes are padded, which blurs the difference between a keepalive and a big chunk of output, but does not hide it. If that matters to you, run your own relay.

What it does not protect against

  • No forward secrecy. Encryption uses static ECDH between long-term keys. An attacker who records traffic today and obtains a private key later can decrypt what they recorded.
  • No post-compromise security. Once a key leaks, every future message is readable until you re-pair.
  • No revocation broadcast. Revoking is local state on each machine. A stolen client means visiting every machine.
  • No protection against a relay withholding messages. A relay can silently drop; your client sees a timeout. Using several independent relays is the only mitigation.
  • No sandbox. Commands run with the service's full privileges, by design.
  • No metadata hiding at the timing and volume level. See above. Padding everything to a fixed size would make the tool unusably slow on relays that rate-limit by bandwidth.
  • The command denylist is not a security boundary, and the code, docs and CLI help all say so. Anyone who can run one command as SYSTEM can rewrite the config. Its job is to catch a mistake, not an adversary.

Two more things to know

The audit log records full command text, including any secret you paste into a command. That is a deliberate trade — an admin tool with no record of what was run is unauditable — and the log lives in a SYSTEM/root-only directory. Set log.audit: false to log metadata without command bodies.

Remote self-update of the agent is off by default. It requires an explicit config change on the machine and verifies a signature over the release artifact. It is the highest-value target in the system and is treated as such.

Your exported account file is the account. The default export format is passphrase-encrypted (scrypt + XChaCha20-Poly1305, tuned to about a second), export requires re-authentication, and the bundle carries your peer list as well as the key — which is a further reason the whole payload is encrypted rather than just the key. Restoring it on a new machine does not invalidate the old copy: both hold the same key, and both work.