Tech

Celistra security model

Akshay Sarode

Identity

The daemon accepts two auth paths:

Pairing: cryptographically-random 16-byte tokens minted by the tray, single-use, 600-second TTL, constant-time compared. Discussed in detail in Pair a machine in 30 seconds without SSH keys.

Network

Daemon binds to 127.0.0.1:33120 exclusively — never 0.0.0.0. Off-LAN traffic flows through an outbound bore tunnel to mail.ujex.dev:7000. nginx terminates TLS with Let's Encrypt; CAA pinned to LE plus four other named CAs.

Tunnel admission: Firebase-gated token rotated via Firestore. The frpc binary inside the .app is SHA-256 verified at exec — a swap-attack is refused, not executed.

Sandbox

Every spawned agent is wrapped in sandbox-exec -f <profile> with a Seatbelt profile generated from a capability token bundle. Default policy: workspace-write, read-anywhere, network, subprocess. Per-agent grants in versioned JSON. Linux uses bubblewrap with the same capability mapping. Detailed: Sandboxing Claude Code on macOS.

Audit

Hash-chained log: row.hash = sha256(prev.hash || row.body). Hourly verifier. Tamper-evident by construction. Detailed: The audit log every agent needs.

Revocation

Tray menu → Revoke all sessions calls a Cloud Function that runs admin.auth().revokeRefreshTokens(uid) against the user's Firebase account. Existing ID tokens expire within 1 hour; refresh tokens are immediately dead.

Threat model

In scope: a malicious user on the LAN trying to drive the daemon (blocked: loopback bind + auth). A swapped frpc binary (blocked: SHA-256 check). A prompt-injected agent trying to write outside its workspace (blocked: kernel sandbox). A stolen device (mitigation: revoke-all-sessions).

Not in scope: a compromise of the user's macOS account (game over). A prompt-injected agent making bad commits within its workspace (sandbox is a containment story, not a behavior story). DNS exfiltration via permitted network capability.

Reporting issues

Email security@celistra.dev. PGP key on the page. We respond within 48h.

FAQ

Where does data live?

Metadata in Firestore (your Firebase project). PTY streams in real time, not persisted server-side. 30-day history is local SQLite on the daemon's disk.

Can the daemon be reached over LAN from another box?

No — bound to loopback only. The 'remote daemon' use case (laptop dashboard, Pi daemon) goes via the tunnel.

Is the tunnel relay logged?

nginx access log only. No request bodies, no PTY content.