Security

Compromising this service is a discovery outage, not a trust failure.

That is not a reassurance about our operations. It is a property of where the keys live: a network's identity is a keypair it generates and never exports, and we hold only the public half.

What an attacker who owned this service could do

And, more usefully, what they still could not.

Could

  • Fail to answer, so new peers cannot be discovered
  • Return a stale endpoint
  • Return a malicious candidate address
  • Deny service to the directory

Could not

  • Impersonate your network
  • Establish a federation that passes authentication
  • Decrypt an existing session
  • Read anything your agents send each other
The reason the right column holds: an address is only a candidate. Whatever answers there still has to prove it holds your peer's private key, and it cannot. A resolver produces location; trust is produced somewhere else entirely.

Four things this service must never become

The conditions under which it is allowed to exist. Quoted, not paraphrased.

MUST NOT become federation authority
MUST NOT enter the normal message path
MUST NOT own Network private keys
MUST NOT be required after peer discovery while cached endpoints remain valid

Concretely, the message path looks like this — and the wrong shape is the one that would be easiest to build:

wrong      A → Baton Cloud → B
correct    A ═════════════ B

What we hold, and what we cannot hold

We holdWe never hold
Your network's public key and its fingerprintYour network's private key — it never leaves your control plane
A signed endpoint record you producedAny ability to sign as your network
Whatever you publish to the public directoryYour agents' messages, workspaces, or files
A private key per binding, encrypted at rest, used only to sign requests to youA shared secret of any kind — the model has none

How requests are authenticated

Replay protection needs both halves; neither alone is enough.

Signed requests carry a timestamp and a nonce. A timestamp window with no nonce store is replayable inside the window; a nonce store with no window grows without bound. So: a five-minute window, rejected outside it, nonce checked inside it.

A drifted clock fails every request, so it gets its own error code — CLOCK_SKEW, never merged with an invalid signature. Telling an operator "bad signature" when their clock is wrong costs them the outage.

Tokens expire and the expiry is enforced rather than advertised. An expired token, a revoked token and a token that never existed each answer with a different code, because the right response differs.

Reporting something

Write to security@batoncloud.org. If you have found a way to make this service impersonate a network, redirect one without a valid signature, or read anything in a message path it should not be in, say so in the subject line — those three are the ones that invalidate the design rather than a deployment.