Security
BEAM is in internal beta, by invitation. Nothing is for sale yet.
This page states the posture. Every line names the file that implements it, so you can check the claim rather than take it — and the last section is the list of things that are not built, which is the part of a page like this that is usually missing.
To report a vulnerability: security@usebeam.sh. You get an acknowledgement within two business days. The full policy is SECURITY.md and there is a machine-readable pointer at /.well-known/security.txt.
What is built
Permission ceremonies — agents propose, people approve. Every tool an agent can reach carries a tier, and the tier decides what the approval has to cost you: auto runs unattended, confirm needs a y, and manual needs a typed code rather than a keystroke. The mapping is one function with no third path, and lowering a tier cannot admit a tool the loop does not already hold. The set of tools allowed to run unattended is written down rather than remembered, and the document is generated from the code so it cannot drift. src/engine/agent/permissionGate.ts, src/engine/agent/permissionTiers.ts, docs/security/AUTO_TIER_ALLOWLIST.md, scripts/gen-auto-allowlist.mjs
An approval is bound to the arguments it was shown for. A y or a typed code used to bind to a tool name and nothing else, so whatever sat in the pending arguments at the moment of execution was what ran — an approval was a token for the verb, and the object of the verb was free. Now a SHA-256 digest over a canonical encoding of the tool name, its arguments, the policy version and the schema version is minted when the receipt is rendered and recomputed from what is about to execute at every gate call site; a mismatch refuses. The two version fields are in the digest deliberately, so an armed receipt stops being valid when the rules underneath it move. Every substitution row in the test is paired with a positive control, so a refusal cannot be mistaken for a no-op. src/engine/agent/approvalDigest.ts (tests: src/engine/agent/__tests__/approvalDigest.test.ts, src/engine/agent/__tests__/approvalBinding.callSites.test.ts)
An external tool that changes its meaning is refused. A third-party MCP server writes its own tool names, descriptions and schemas, and those are what tell you and the model what a call does. BEAM records a hash of the name, the description and the canonical schema at approval, then recomputes it before execution and on every later call to that tool in the same session. If the description or the schema moved, the call is refused and the re-armed receipt says which part changed — without reprinting it, because in this attack that text is the payload and repeating it would deliver it inside the warning about it. src/engine/agent/toolIdentity.ts, server/mcp/clientManager.ts (test: server/mcp/__tests__/toolIdentityPoisoning.test.ts)
A per-tier monthly AI allowance. Each seat tier carries a monthly model-work allowance, enforced at admission — before the provider call — on the chat, council and research routes. It fails open on a billing-read failure: a billing-database outage must never read to a user as a product outage, which means a long outage is a period with no ceiling at all. Which routes are gated is derived from the code by a test rather than written in prose — the list is SPEND_GATED_ROUTE_FILES, pinned by server/routes/__tests__/spendGateParity.test.ts, which iterates that list asserting each route still calls the gate and asserts in both directions that the deliberately-ungated surfaces do not. server/billing/spendGate.ts (refuseIfOverSpendCeiling)
A structured audit log with correlation ids. One auditLog(event) seam with a closed event union — tool calls, gate decisions, proposals, MCP connects and calls, spend-ceiling verdicts, auth outcomes, admin actions, egress. A correlation-id middleware mounts first, accepts an inbound x-request-id only when it is well-formed, mints one otherwise, and echoes it back. No content, no secrets and no raw user id reach the record: it is redacted and then shape-checked, so prose is refused rather than trusted. server/utils/auditLog.ts, server/middleware/correlationId.ts, docs/security/AUDIT_LOG.md
A rotatable key over stored third-party credentials. The key that encrypts the credentials BEAM holds on your behalf — MCP OAuth refresh tokens, personal-MCP header credentials, calendar secrets — can be rotated without downtime, because the stored blob carries a key id. This is not your own encryption key. That one is derived from your password on your device, and your password and recovery phrase never leave it — but a copy of the key itself, sealed under your recovery phrase, is stored on the server so a second device can be unlocked, and we cannot open it without the phrase. Rotating the credential key described here touches neither that copy nor a single workspace document. docs/security/KEY_ROTATION.md, src/crypto/keyManager.ts, src/crypto/adoptCloudKey.ts
An outbound URL guard, including IPv6. Any URL a client hands the server to fetch is checked against private, loopback, link-local and cloud-metadata ranges, in both IPv4 and IPv6 — including IPv4-mapped IPv6 forms and compressed-zero notation — with a bound on the guard's own DNS lookup, a connection-time IP re-check to close DNS rebinding, and redirect: 'manual' so the guard runs again on every redirect hop. server/utils/urlGuard.ts
Response byte caps. A remote peer cannot make the server hold an unbounded response in memory: there is a content-length pre-check plus a reader that stops at a byte cap, on the web-fetch path and on the MCP transport. server/utils/bodyCap.ts
Content-Security-Policy on both surfaces. The web app's policy is served by Vercel; the desktop renderer has its own, in a pure module so a test can diff the two and catch drift. vercel.json, electron/cspPolicy.ts
A pinned, script-free supply chain. CI pins every GitHub Action by commit hash, installs with npm ci --ignore-scripts so no dependency lifecycle script runs on a build machine, and publishes an SBOM from its own workflow. .github/workflows/ci.yml, .github/workflows/sbom.yml
An adopted incident-response plan. Severities, detection sources, the notification decision and the roles — including the fact that one person currently holds all of them. docs/security/INCIDENT_RESPONSE_PLAN.md
Structural commitments enforced by a linter. No plaintext in logs, no server-side key access, no single-vendor AI sidecars, no encrypted-store bypass, no user content in telemetry — checked by custom ESLint rules at PR time, not by a code-review habit. tools/eslint-plugin-charter/, CHARTER_RULES.md
Not yet
- No external security review has happened. It is a first use of funding. Until then, nothing on this page rests on anyone outside BEAM having looked.
- The group-messaging library is unaudited. Team messaging uses the MLS protocol (RFC 9420) through
ts-mls. The mechanics work and are tested; an external crypto review is required before anything stronger is said about them, and nothing stronger is said.src/crypto/mls.ts - Encryption is opt-in, and switching it on does not rewrite history. A workspace that ran without it wrote content the server could read, and those rows stay as they were stored until you run
sync force. This is an open finding, tracked, not closed quietly. - Structure and ordering sync in the clear. With encryption on, content fields are sealed on your device; task titles, status, dates, ordering and interface state are not. When AI tools run, titles cross the server in plaintext so the tools can act on them. See Encryption → The honest gaps.
- No around-the-clock monitoring, no second responder, no compliance attestation. One operator, stated in the incident-response plan rather than implied away.
- No data-residency commitment. BEAM runs on Supabase (database, auth, file storage), Vercel (web) and Railway (API), with Stripe for billing in test mode, Resend for email, and Anthropic, OpenAI, Google and Perplexity for model calls. We operate in the United States today. If your organisation needs a residency commitment, tell us what it is before you rely on BEAM.
See also: Encryption · Local tier · MCP & proposals