How we secure remote Claude Code
Remote vibe coding means routing commands to Claude Code on your machine. That power demands an architecture where security is the foundation, not an afterthought.
Three pillars of trust
Zero-Trust Relay
The cloud relay is treated as an untrusted intermediary. It routes encrypted payloads it cannot decrypt. A fully compromised relay learns nothing about your code.
Least Privilege
Tools are only auto-approved if your existing Claude Code settings allow them. Everything else requires explicit human approval from your phone.
End-to-End Encryption
Your prompts, code, and tool calls are encrypted on your device and only decrypted on the other. Private keys never leave the device they were created on — the relay sees only opaque bytes.
End-to-end security architecture
Complete system diagram showing encryption boundaries, trust zones, and data flow between all components. For the full system architecture and tech stack, see the architecture overview.
Hardened authentication layer
Multiple layers of authentication protect user accounts and device registration.
🔑 Password Security
- Industry-standard adaptive hashing with per-user salts
- Minimum password strength validation via zod schemas
- Password changes invalidate all existing sessions
- Account enumeration prevention (identical responses for existing/new accounts)
🎫 JWT Token Management
- Algorithm pinned to prevent downgrade attacks
- Short-lived access tokens with refresh rotation
- Atomic refresh token rotation
- Refresh token reuse detection triggers session revocation
🔗 OAuth Security
- OAuth with CSRF state parameter validation
- Timing-safe state comparison prevents bypass
- No automatic account linking by email (prevents hijack)
- OAuth tokens never stored or logged on relay
📡 Device Tokens
- Unique device tokens for each BeachViber agent
- Tokens scoped to specific user account
- Registration requires authenticated API call
- Tokens validated on every WebSocket connection
End-to-end encryption in depth
🔐 Cryptographic Primitives
Desktop encryption uses the Node.js built-in crypto module. The webapp uses the Web Crypto API (SubtleCrypto) with non-extractable private keys that JavaScript cannot access.
Your existing tool approvals, on your phone
BeachViber reads the permissions you've already configured in Claude Code. Tools you've allowed stay allowed — everything else gets sent to your phone for approval. We never bypass Claude Code's permission model with --dangerously-skip-permissions. See the message protocol for how approval requests flow between components.
Least Privilege
The approval hook reads your existing Claude Code permission settings. Tools you've already allowed in Claude Code are auto-approved — no redundant phone prompts.
Requires Phone Approval
Any tool not already permitted by your Claude Code settings is sent to your phone for explicit approval. You see the tool name and arguments before deciding:
🛠 Approval Flow Implementation
- Hook reads your existing Claude Code permission settings first
- Tools matching your existing allow-list are auto-approved — no phone round-trip needed
- Local-only IPC with no network exposure
- IPC channel created with restrictive permissions (owner-only access)
- Short approval timeout — unanswered requests are denied
- IPC unreachable = tool denied (never silently approved)
- Hook installed on agent start, removed on agent shutdown
- Claude Code runs with your existing desktop permissions — --dangerously-skip-permissions is never used
Relay and infrastructure hardening
CORS Policy
CORS restricted to a single configured origin. No wildcard origins. Prevents cross-origin attacks from malicious sites.
Content Security Policy
Strict CSP headers limit script sources, connection endpoints, and frame embedding. X-Frame-Options: DENY prevents clickjacking.
Automatic Expiry
Pairing codes, verification codes, and temporary records auto-expire. No stale sensitive data persists in the database.
Input Validation
All API inputs validated with zod schemas at the boundary. Strict type checking prevents injection and malformed data from reaching handlers.
TLS Enforcement
TLS certificate verification enabled on all outbound connections. No certificate pinning bypass. HTTPS enforced for all API and WebSocket traffic.
No Debug Logging
All debug logging removed from production. No secrets, tokens, keys, or sensitive data written to logs. Console output sanitized.
Local file system protection
Runtime protections
Active defenses that protect sessions beyond encryption and authentication.
🔄 Replay Protection
- Every encrypted message includes a unique nonce
- Nonce deduplication with a short-lived tracking window
- Strict timestamp validation rejects stale messages
- Minimal clock skew tolerance for network latency
⚡ Rate Limiting
- Server-side rate limiting prevents message flooding
- Per-connection enforcement with configurable thresholds
- Atomic counters prevent race conditions
- Connections exceeding the limit are throttled
🔒 Webapp Key Isolation
- Private keys created as non-extractable CryptoKey objects
- Web Crypto API enforces: JavaScript cannot read key material
- Even full XSS cannot extract the private key
- Private keys are never persisted — only derived AES keys are stored
💻 Multi-Desktop Isolation
- Each paired desktop gets its own X25519 key exchange
- Separate AES-256-GCM key derived per device
- Compromising one device's key cannot decrypt another's traffic
- Re-pairing a device automatically revokes old tokens
Why we made these choices
Why platform-native crypto?
The desktop uses Node.js built-in crypto (OpenSSL-backed, zero dependencies). The webapp uses the Web Crypto API with non-extractable CryptoKey objects — private keys never touch JavaScript, so even full XSS cannot extract key material. No third-party crypto libraries to audit or keep updated.
Why local IPC for tool approval?
Local IPC provides OS-enforced access control, has no network attack surface, and is cleaned up automatically. It's the most secure mechanism available for same-machine communication between the agent and Claude Code hook.
Why per-pairing keypairs?
Compromising one pairing's keypair doesn't compromise others. Each pairing gets its own X25519 keypair with secret keys stored in the OS keychain. This limits the blast radius of any single key compromise.
Why no --dangerously-skip-permissions?
Claude Code's CLI has a flag that bypasses all tool permission checks. BeachViber never uses it. Instead, we layer on top of Claude Code's existing permission system — the same one you already trust on your desktop. Your machine, your permissions, no shortcuts.