Security
Fuselee holds the keys that can spend your money and, when you ask it to, cut them off. This page explains exactly how those keys are protected, who can do what, and how you can keep them out of Fuselee entirely.
Encryption: credentials are sealed, and only the worker can open them
Provider credentials (OpenAI and Anthropic admin keys, AWS access keys, Vercel tokens) are encrypted in the browser request that connects the provider, using a libsodium sealed box addressed to the worker’s public key. The ciphertext is what the database stores. Neither the web app nor the database can read it back: the private half (FUSELEE_MASTER_KEY) exists only in the worker process.
Notification channel configuration (webhook URLs, push subscriptions, outgoing-webhook secrets) is sealed the same way. Replacement API keys issued on Resume are sealed for the worker and revealed to you exactly once, then wiped.
- Sealed boxes: X25519 + XSalsa20-Poly1305 (libsodium crypto_box_seal).
- The master key never leaves the worker; rotate it and every stored secret becomes unreadable by design.
- Column-level grants hide sealed columns from every application role; the browser role cannot even select them.
Role separation
The web app runs with the public Supabase anon key and the signed-in user’s own session. Row-level security is enabled and forced on every table, scoped by organisation, so a query can only ever see one tenant. The worker is the only component holding the service-role key and the master key, and it is the only writer of spend, enforcement, billing and plan state.
Inside an organisation: owners manage billing; owners and admins connect providers, manage budgets, disarm dry-run and add org-wide channels; members read and manage their own personal channels. Role changes are guarded by a database trigger: nobody can change their own role, and the owner role is immutable through the app.
- Web → worker calls carry the user’s own JWT; there is no shared secret between them.
- Plan and billing columns are writable by the worker only, never through the app.
- Team API tokens and agent tokens are stored as SHA-256 hashes and shown once.
Audit: every decision is an event
Every threshold crossing, dry-run decision, sever, pause, resume, skipped never-touch key, forecast, anomaly, notification, plan change and agent command is appended to an immutable events table with the actor and a machine-readable payload. The dashboard shows the feed; Pro plans can export it as CSV; Team plans can read it over the API.
- Dry-run is on by default. Disarming it is a three-step confirmation that the server re-validates and records.
- Enforcement targets exactly the connections you registered; the never-touch list is honoured and logged.
- Outgoing webhooks are HMAC-signed (X-Fuselee-Signature) so receivers can verify origin and freshness.
Self-host option: keep credentials in your own environment
If you would rather not hand Fuselee any credential at all, run fuselee-agent (MIT) next to your workloads. The agent reads spend and executes cutoffs locally with the same adapters, and reports only numbers, key identifiers and redacted results to the Fuselee API over outbound HTTPS. It has no inbound ports, runs read-only as a non-root user, and can be revoked from the dashboard at any time.
- Least-privilege policies are published for every provider; the AWS act role can only touch resources tagged fuselee:managed=true.
- Reissued secrets never leave the agent: only a fingerprint is reported.
Reporting a vulnerability
Email security reports to the address on the GitHub repository. We acknowledge within two business days and do not pursue researchers acting in good faith.
See also guarantee levels, dry-run and self-hosting.