Security
Secrets never touch git, logs, or model context. Credentials at rest use
AES-256-GCM envelope encryption with the tenant bound into the additional
authenticated data, so ciphertext from one workspace can't be replayed into
another. API responses expose only hasCredentials booleans — never the values
— and the structured logger redacts known secret keys.
Every route is workspace-scoped: it resolves the session, the active organization, and the caller's role, then verifies row ownership before acting. The authorization matrix — outsider, member, and admin-or-owner operations — is covered by tests.
Connected servers
An MCP connection points the platform at a server you choose, so every outbound request made on your behalf runs through a guarded egress path. Each address is resolved and validated before anything is dialed, and the connection is then made to the validated address while TLS still verifies the real hostname — so a name that resolves differently the second time around can't redirect the platform somewhere it already refused to go. Requests are HTTPS-only, redirects are same-origin and re-checked at every hop, and both time and response size are capped.
The same path carries a Workflow's tool steps — every deterministic MCP call a pipeline makes dials through the identical guard. And a pipeline's templates resolve only against the run's own scope — trigger data, step outputs, workflow state — so a step's persisted inputs and outputs structurally cannot contain a credential.
Credentials decrypted to probe a server or make a tool call exist only for the length of the call: they are never logged, never persisted in the clear, and never returned in an API response. Error text from a failed probe or tool call is scrubbed against the credentials it was given before it is stored. See Context & MCP for how a connection is set up in the first place.
OAuth tokens
For connectors that authenticate with OAuth, the platform is the only party that holds a token. Access and refresh tokens are encrypted at rest with the same envelope scheme as every other credential, and refreshes happen centrally, one at a time per connection.
Compiled agents never receive a refresh token or a client secret. When an Agent makes a tool call against an OAuth connection, it asks the control plane for a short-lived access token, proving which agent version it is; it gets back that token and nothing else. If the grant is gone, the request is refused and the tool call fails with a reconnect prompt rather than hanging.
Compiled agents
Model routing is baked in at build time behind a placeholder key, so real provider keys never enter the build environment (builds run allowlisted and with install scripts ignored). Compiled agents are reached with per-version derived JWTs, and workers dispatch with single-use tokens.
What is stored, and where
Agent definitions, sessions, run events, and encrypted credentials live in Postgres. Compiled artifacts and skill attachments live in the object store. The search index holds only a disposable mirror of the MCP registry — no user data ever reaches it. See Architecture for the full data map.
Run transcripts persist for the life of the workspace — there is no automatic transcript expiry today.
Your data and the model provider
Prompts and run content are sent to whichever model provider the resolved Agent uses — OpenRouter or Anthropic, the only two providers the platform speaks to, depending on the workspace's configuration. That's inherent to how an Agent produces an answer, not an incidental detail: the platform cannot generate a response without sending the conversation to a provider. The key it authenticates with is never the build's — see Compiled agents above.
Protecting public ingress
Slack requests are verified against their signature within a replay window before anything else happens with them. Webhook and other trigger ingress enforce per-token and per-IP rate limits, plus a cap on request body size — see Limits and defaults for the exact numbers rather than repeating them here.
If you self-host
Running your own deployment puts you in control of your own provider key, your own database, and your own backups — none of that runs through invisible-string's infrastructure.
One switch is a development convenience, not a production setting:
MCP_PROBE_ALLOW_PRIVATE relaxes the health-probe egress guard to allow
private addresses. Leave it off on any deployment reachable from the internet
— turning it on in production reopens exactly the class of request the guarded
egress path exists to block.