Encryption
- All traffic is TLS.
- Secrets at rest use AES-256-GCM with a per-workspace data key in an envelope scheme, wrapped by a deployment master key.
- Each ciphertext is bound by GCM additional authenticated data to its workspace id and purpose (for example
slack_bot_token,connector_oauth,byo_model_key). A blob copied from one column class to another fails authentication instead of decrypting. - Master-key and per-workspace key rotation are supported operator procedures.
Tenant isolation
Row-level security in Postgres is the backstop, not the only line.- Every tenant-facing query runs as a scoped database role carrying a short-lived token with the workspace id. Policies read that claim. No claim means zero rows.
- The scoped role cannot log in directly and holds grants only on covered tables.
- Application-layer workspace filters remain everywhere in addition.
Integration credentials
Third-party OAuth tokens for integrations are held by the connection provider (Pipedream), not by Henry. Henry stores connection metadata only. Where Henry does hold a credential, such as a Slack bot token or a custom MCP header, it is encrypted as above.Prompt injection
Henry treats everything it reads as data, never as instructions:- Tool results, emails, web pages, and file contents are explicitly untrusted. If external content tries to change Henry’s behavior, Henry ignores it and tells the user what it saw.
- Memory writes carry a provenance tag: a member’s statement, a tool result, or external content. Durable rules can originate only from member statements; external content is summarized, never pasted.
- A turn that started from an untrusted source keeps that taint through any background continuation.
- Writes to third-party tools stage a confirmation by default. Spending always requires a manual confirmation.
- Findings from parallel research helpers are drafts over untrusted data that Henry verifies before answering.
Code execution sandbox
When Henry runs code to process data, it runs in a microVM dedicated to one workspace. No two workspaces ever share a sandbox.- Egress is enforced outside the guest and allows exactly one HTTPS host: Henry’s gateway.
- No provider credential ever enters the sandbox. Scripts hold one run-scoped opaque token, delivered as a read-once file, revoked at run end, and scrubbed from output.
- The sandbox reaches only the tools this run was granted, and writes are drafted for approval rather than executed directly.
Agent Browser
- The browser turn’s toolset is limited to reading pages, acting, navigating, requesting a login, requesting a confirmation, and finishing. It has no access to email, texts, files, or memory, so there is no one-time code to steal.
- Page text arrives only as tool output, never as a system or user message.
- Navigation is confined to the task’s site. Redirects are re-judged; the first off-site landing ends the turn.
- A page cannot approve anything. An approval is consumed by the first action it authorizes and cannot be replayed. A terminal outcome cannot be overwritten.
- Henry never types a password or a code. The user signs in on a live view.
- Unattended and guest turns get no browser.
- Banking, brokerage, payment, and similar sites are denylisted, including parent-domain evasion. Sites covered by an integration are routed to the integration instead.
- Deciding whether an action is irreversible is heuristic (prompting plus an action guard), not a structural guarantee. Sessions are recorded for review.