Skip to content

Security model

  1. The box is private. It binds to loopback and is published only inside your tailnet — there is no public surface to attack.
  2. First account must prove console access. The one-time box code printed on the box console gates account creation, so reaching the address is never enough to own the box.
  3. Sessions are real bearers. Sign-in mints a random 256-bit session token, held in the phone’s secure keystore, required on every call.
  4. Consequential actions gate on you. Approvals are enforced server-side.

Sign-in is the email + 6-digit code flow, throttled hard on the box (per-email and per-IP limits, 5 attempts per code, 10-minute expiry — see Sign in). The current app does not offer WebAuthn passkeys. Separately, Me → Privacy → Require Face ID locks the app itself on-device.

The first connection to a paired host shows you its fingerprint; confirming pins the key in the box vault. From then on a changed host key is refused, not re-prompted — if a host legitimately changed keys, remove and re-pair it deliberately. No silent trust.

If Activity surfaces a sign-in you don’t recognize, the triage screen’s Lock down & revoke session kills the box-side session immediately — every device drops to the sign-in gate. The action asks for confirmation, runs against the box’s auth endpoint directly, and the alert only resolves if the revoke actually succeeded.

  • 6-digit codes: 10-minute lifetime, 5 attempts, then invalidated.
  • Rate limits per email and per IP on code requests.
  • The box code compares in constant time and is destroyed after first use.
  • Optional Cloudflare Turnstile on the email form (see Configuration reference).

Email security@layergray.com.

Please include reproduction steps; we’ll acknowledge quickly and keep you posted through the fix.