Skip to main content

Security

Styrby is built on a zero-knowledge architecture. Your code and conversations are end-to-end encrypted. We cannot read them.

End-to-End Encryption

All session messages are encrypted with TweetNaCl box (Curve25519 key exchange, XSalsa20 encryption, Poly1305 authentication) before leaving your machine.

# Encryption flow:
1. CLI generates a 32-byte NaCl keypair during "styrby onboard"
2. Public key uploaded to Styrby and stored in the machine_keys table
3. Private key stored locally in ~/.styrby/config.json
4. Each message encrypted: nacl.box(msg, nonce, recipientPub, senderPriv)
   - nonce: 24 random bytes, unique per message
5. Server stores only the ciphertext
6. Dashboard and mobile decrypt locally using the device's private key

Zero-Knowledge Architecture

What Styrby can see

  • Token counts (input, output, cache) for cost tracking
  • Agent type and model name
  • Session timestamps and duration
  • Machine connection status

What Styrby cannot see

  • Message content (prompts and responses)
  • File contents or diffs
  • Tool call arguments
  • Your source code

Even if Styrby servers were compromised, attackers would only get encrypted blobs. The decryption keys exist only on your devices.

Key Management

Generation

Keys are generated using nacl.box.keyPair() during the onboarding process. This produces a 32-byte public key and a 32-byte secret key. The entropy source is the OS cryptographic random number generator.

Storage

The CLI stores the private key in ~/.styrby/config.json with 0600 file permissions (owner read/write only). On mobile, the key is stored in the device keychain (iOS Keychain / Android Keystore).

Re-pairing

If you lose your private key (cleared browser storage, corrupted config, or new machine), run styrby onboard --force to generate a new keypair and re-register. Sessions encrypted with the old key will no longer be decryptable on the new device.

API Key Hashing

API keys are prefixed with styrby_ and hashed with bcrypt (cost factor 12) before storage. When you make an API request, Styrby hashes the provided key and compares it against the stored hash. The raw key is never persisted. The plaintext key is returned only once at creation time.

Rate Limiting

All API endpoints are rate-limited using Upstash Redis with a sliding window algorithm. Limits are applied per user (authenticated routes) and per IP (public routes like login).

  • Authentication endpoints: 10 requests per minute per IP
  • API v1 endpoints: 100 requests per minute per API key
  • Webhook management: 30 requests per minute per user

Webhook Security

Webhook URLs must use HTTPS and must not target internal or private network addresses. The following are blocked:

  • localhost and 127.0.0.1
  • RFC 1918 private IPs (10.x.x.x, 172.16-31.x.x, 192.168.x.x)
  • Link-local (169.254.x.x) and cloud metadata services

This prevents SSRF attacks where a webhook could be used to make requests against internal infrastructure.

Audit Logging

Security-relevant events are recorded in the audit_log table with BRIN indexing for efficient time-range queries. Logged events include:

  • Login attempts (success and failure)
  • Machine pairing and unpairing
  • API key creation and revocation
  • Webhook endpoint changes
  • Permission approvals and denials
  • Team member additions and removals
  • Budget alert triggers

Data Residency and Compliance

Styrby infrastructure runs on Supabase (AWS) and Vercel. Database and auth are in the Supabase project region. Encrypted session data at rest uses AES-256 (Supabase default). In transit, all connections use TLS 1.3.

For compliance details, data processing agreements, and security certifications, see the Data Processing Agreement and Security page.