Security overview

beebox is a personal assistant that a Claude Code agent operates on your behalf: it reads your email, listens to your voice memos, edits your files, and runs shell commands. A system like that deserves a blunt security document, so this one leads with blast radius, not reassurance.

This is the readable overview. The reporting policy is SECURITY.md at the repo root; the full accounting is security-report.md.

This document is maintained by an agent, reviewed by a human. The process that generates it — an ordered inventory and evaluation rubric — is committed at .claude/skills/security-report/SKILL.md (repo root), and the full accounting it produces is security-report.md: every endpoint and its auth, every credential and its blast radius, every place data leaves the machine. You can't verify a security doc wasn't shaped by error or malice, but you can read the rubric that produced it, the diff of every regeneration, and the review header above. That's the claim this document makes: it is auditable as a process, honest about where it isn't verifiable as an artifact.

Reporting a vulnerability

See SECURITY.md — the reporting policy lives there so it is where GitHub and a first-time reader look for it.

Threat model, briefly

beebox assumes a single trusted operator (plus, optionally, a few invited members they personally trust). It defends the box from the network — authentication is structurally always-on; there is no flag, env var, or config field that disables the login wall — and it limits what the box's own moving parts inherit: per-box processes and agent subprocesses get an allowlisted environment that omits the session-signing secret and other cross-box credentials. Be precise about what that is: env-level isolation, not OS-level. Everything runs as one OS user, and the secret is also a 0600 file that same-user code could read — the stripping stops accidents and lazy exfiltration, not a determined same-user process. It does not defend you from your own agent: the agent is the product, and it runs with real power (next section). It also does not currently treat invited members as adversaries — membership grants broad capability short of admin operations (details).

What the agent can do

Plainly: the box agent runs Claude Code with bypassPermissions and no tool allowlist. It can execute arbitrary shell commands as the user the box runs as, and read or write any file in the box. Its working scope is the box directory, and no current call site widens it beyond that — but the scope parameter itself is unguarded caller input, and either way it is a convention the agent operates within, not a sandbox that contains it. Treat "what can the agent do" and "what can beebox do" as the same question. On fresh boxes, scheduled agent runs are off by default — nothing runs until you turn it on.

Prompt injection — the risk we most want you to understand

beebox is, by design, an agent that reads your private data, ingests untrusted external content, and acts with no tool allowlist. Those three together are the well-known "lethal trifecta": text written by someone else — an email body, a web clipping, a calendar invite, a Telegram message, even words inside a photographed image — can reach the agent's context and try to steer it. If that succeeds, the attacker isn't limited to reading one card; they have whatever the agent has, which is arbitrary shell as your box's user.

We're telling you this plainly because the honest mitigations today are thin. There is no injection filter and no containment sandbox. What actually reduces the risk is the shape of how you run it: it's your own single-operator box (the blast radius is your data, not a stranger's), scheduled processing is off until you enable it, and the few dangerous actions — publishing, changing credentials — refuse to happen without a human present. That's a real posture, but it's mitigation-by-how-you- deploy, not a guarantee the agent can't be turned against you. Tighter containment is tracked and not yet built. Until it is, be deliberate about which untrusted sources you connect, and don't leave the agent processing them unattended in a box that can reach anything you'd mind losing.

What leaves your machine

The complete inventory is §3 of the structured report. The summary:

One caveat worth naming: the iOS app's dictation prefers Apple's on-device recognizer, but on older systems it falls back to Apple's cloud speech service without an app-level opt-out (issue).

The authentication surface

Every box route — HTTP and the WebSocket upgrade alike — sits behind one auth wall. A request gets in with a logged-in session (local password, scrypt-hashed, throttled; or Google OAuth), a scoped machine credential (mobile device token, per-box agent token, scan token), or not at all. Box access fails closed: a box with no explicit member list is owner-only. A corrupt credential store answers 503, never "logged out."

The deliberately unauthenticated surface is small enough to list: the CSP violation report sink (spec-required, tightly capped), a build-info probe (a hash and a flag), the login/static assets needed to reach the login page, and — for its 15-minute first-run window — the setup route, gated by a token printed only to the server console. Everything else that skips the session wall carries its own dedicated credential (Telegram webhook secret, diagnostic bearer key, Cloudflare Access JWT). The full route-by-route table is §1 of the structured report.

Publishing

Publishing a document is the one flow that deliberately makes box content public, so it gets its own controls: a leak scan runs before anything enters git history, and flipping a publication live requires a human typing a confirmation at an interactive terminal — an agent can't do it through the blessed path. Be clear about two things the design says out loud: the leak scan is a backstop, not a gate (it can't read prose or the inside of images — the file-by-file preview you confirm is the real control), and a published bundle is fully public content regardless of tier. Tiers gate who can reach a page — secret means an unguessable capability URL with no login, accounts means Cloudflare Access with an email allowlist — not what a viewer does with it after loading it.

Known limitations and accepted risks

The full register with rationale is §8 of the structured report. The ones you should actually weigh:

Known gaps (tracked, not yet accepted or fixed) live in the issue queue — at this writing they include plain-HTTP between Cloudflare's edge and the origin on the public deploy path, deploy-time infra config drift, and how much capability an invited member should hold. (The connector secret-file permission gap this list used to carry is closed: connector credentials now live in the machine secret store, not box files.) The structured report lists each with a pointer.

A few gaps are tracked privately rather than in the public queue: where a defect is specific and unpatched enough that publishing its exact location would be a roadmap to a live hole, we hold it until it's fixed and name it only by class here. That's a deliberate rule, not concealment of the kind of problem — the structured report says which category is affected, just not the file:line. It is the mirror of the prompt-injection section above: architectural risks we disclose loudly; location-precise unpatched defects we disclose once they're closed.