This is a security-focused overview of Crosslink’s design. It is not a formal audit report. Crosslink provides transport-layer security primitives; your application must implement application-layer security (input validation, rate limiting, audit logging) independently.
Security principles
Crosslink is built on four principles:
- End-to-end encryption — No intermediary can read or modify traffic
- Forward secrecy — Compromising a long-term key does not expose past sessions
- Trust minimization — Services are untrusted; the client’s browser/OS is the trust boundary
- Capability-based authorization — Declarative, host-authored, no ambient authority
Cryptographic primitives
What the relay and signaling servers see
Authentication flow
Threat model
In scope
Out of scope
Pairing security
Single-use codes
Each pairing code can only be used once. The code is:
- 9 digits (1 billion possible values)
- Valid for 2 minutes
- Tied to the host’s fingerprint
- Bound to specific capabilities
SAS verification
Short Authentication String (SAS) digits are derived from:
- The host’s Ed25519 identity public key
- The client’s Ed25519 identity public key
- The application ID
Both parties must see the same digits. If they don’t, a MITM is detected.
Fingerprint pinning
The QR code includes the first 16 hex characters of the host’s Ed25519 fingerprint. The client verifies this against the actual host public key during pairing.
If the fingerprint in the QR code does not match the host’s actual fingerprint, pairing must be rejected. This is the primary MITM defense during pairing.
Session security
Forward secrecy
Every session uses fresh ephemeral X25519 keys. Compromising the host’s long-term identity key does not expose past session content.
Session binding
Sessions are bound to:
- The specific host identity
- The specific client identity
- The capabilities granted during pairing
- The session’s ephemeral key material
Frame integrity
Every encrypted frame includes:
- A 24-byte XChaCha nonce (random, unique per frame)
- A Poly1305 authentication tag (detects tampering)
- Sequence numbers (detects replay/reordering)
Secret storage security
Host (Node.js)
The SDK tries backends in order:
- keytar — OS keychain (macOS Keychain, Linux libsecret, Windows Credential Vault), if the optional
keytar package is installed by the host application. Crosslink does not depend on it or install it for you.
- Electron safeStorage — Same vaults via Electron bindings
- Encrypted file — AES-256-GCM with scrypt-derived key
- Plaintext file — Requires explicit
allowPlaintextFallback: true
The plaintext fallback is not selected automatically. A host that silently degrades to plaintext is worse than one that refuses to start.
Client (Browser)
The SDK tries backends in order:
- IndexedDB + AES-256-GCM — Non-extractable WebCrypto key
- localStorage — Plaintext fallback
- Memory — Ephemeral, lost on reload
The non-extractable WebCrypto key is not a vault. A script running on the origin can still use the key to decrypt. It prevents copy-and-leave attacks, not code-execution attacks.
Security checklist for production