byre is open source on GitHub -- pjlsergeant/byre

Security model

This is the straight version of byre’s security story – the facts that are true and important but too sharp for a pitch. What’s boxed, what isn’t is the summary; this is the detail. byre is young; read the warning on the install page first.

Threat model

The threat is the agent, never the user. byre exists so an autonomous coding agent can run at full permissions without wearing your identity or reaching your machine. It is NOT designed to protect you from yourself: every protection is one config edit from off, and that is deliberate (“not your nanny” – the box is locked against the agent, not against you). byre’s standing promise is legibility, not gates: byre status always tells you what the box can reach.

byre is meant to contain over-eager, reckless, or misbehaving agents – including one acting on hostile instructions it read somewhere – up to the strength of a container. It is not built to resist a dedicated attacker with kernel exploits.

The contract

  • Boxed: your host filesystem, environment, and credentials. The agent sees the project folder, plus exactly what you mount, pass, or enable – nothing else. byre reads no host credentials and copies none. Agent logins happen inside the box; the one exception is the optional shared-auth token for Claude (ADR 0017), which you mint yourself with claude setup-token – wherever suits you – and hand over at an explicit prompt. Explicit hand-over, never ambient inheritance.
  • Not boxed, by design: the network (open by default; the default-deny firewall skill closes it to a derived allowlist) and the project itself (mounted read-write – editing it is the agent’s job).
  • A container is not a microVM. The box shares your kernel. If your requirement is “the agent must never share a kernel with my machine”, use a microVM product or a separate physical box.

Specific facts worth knowing

Docker daemon access is root-equivalent. Anyone who can talk to the Docker daemon (the docker group) can mount any named volume – byre’s included, identity volumes included – or the host filesystem itself. This is Docker’s design, not a byre gap, and byre cannot change it. On shared machines, treat daemon access as root. byre’s uid-qualified naming (byre-<id>-u<uid>-... images, byre-machine-u<uid>-... volumes) prevents users accidentally sharing state; it cannot stop a daemon user doing it deliberately. Project state volumes (byre-<id>-...) are not uid-qualified, so two Unix users sharing one checkout on the same daemon share – and one’s reset/forget can clobber – that agent state; byre is a single-operator tool and does not re-key them. byre shell does hide a box started by another Unix user (--skip-uid-check enters it anyway, as that box’s dev identity). The optional docker-host skill is exactly this grant, made legible: see docs/DOCKER-HOST.md before enabling it.

A skill is trusted code – enabling one hands it the box. Skills ship raw Dockerfile lines, shell hooks sourced at launch, and (for a network-posture skill) a root helper in the box’s network namespace. The allowlists on a skill’s typed fields (apt, env keys, egress) exist for legibility – so a typed field always reads as data – not as containment; there is no sandbox between an enabled skill and the box it builds. The agent command is deliberately a shell fragment for the same reason (flags ride in it; quoting it would contain nothing). Treat enabling a skill like installing an editor extension: a trust decision about its author, made once, with the consequences legible in byre status.

Config env values are baked into the image. They are emitted as Dockerfile ENV layers, so docker history shows them to anyone with daemon access, and they live in the image – surviving byre reset, which clears volumes, not images – until it is rebuilt or deleted. To be clear about what this does NOT change: byre images never leave your machine (there is no push path), and daemon access is root-equivalent anyway – nobody can read the layer who couldn’t already read the running container’s env, the volumes, and the host. So this is a hygiene fact, not a new exposure. The reasons to know it: a value persists in image layers after you delete it from config, and changing one re-runs the project block’s installs. Real credentials belong to the agents’ own login flows or the shared-auth skills, which keep them in volumes.

An open network is an exfiltration channel. With the default open posture, an agent can send anywhere – including the project it is working on, or any credential you passed in. The firewall skill (deny-by-default, per-skill derived allowlist, applied from outside the box, fail-closed launch gate) is the mitigation; enable it if this is in your threat model. The firewall-open skill is NOT: its open-denylist posture blocks a snapshot of named hosts’ IPs – hygiene against well-behaved telemetry clients, trivially routed around by an agent that wants to. The network under it is still open, and this document treats it as such.

The firewall’s allowlist is an IP snapshot. A hostname grant is resolved once, at session launch, and the rules pin those IPs; the name is never re-resolved while the box runs. If the host’s DNS answer moves after that – CDNs rotating a pool, and some resolvers rotating the answer on every query (Azure’s forwarding DNS does) – connections to that host start failing even though it is granted. On a per-query resolver this can bite seconds after launch, not just mid-session. The failure direction is always closed: rotation can cost you reachability, never containment. A session restart re-resolves; for an endpoint with a stable address, granting the IP directly sidesteps the race.

--self-edit is transitive trust of the agent with your host. A self-edit agent authors the next develop’s config – mounts, run args, build context – through the front door. There is no meaningful containment beyond that point, and byre does not pretend otherwise: the launch banner says exactly this, and the session ends with a diff of what changed in the store.

Shared (machine-scoped) volumes cross project boundaries. The shared-auth skills (ADR 0017) put one agent credential where every one of your projects’ boxes can use it – that is their purpose. A misbehaving agent in ANY box can read (and so exfiltrate) that credential, exactly as it can its own per-project login today; the tokens involved are inference-scoped where the vendor allows it (Claude’s setup-token). byre status names shared volumes; reset / forget never delete them silently.

Agents hold usable credentials by construction. Whatever auth story you choose, the agent can read its own credential – it needs it to work. byre’s job is that the credential’s scope is what you chose, its location is legible, and nothing you did not choose rides along.

Reporting

Report security issues via GitHub security advisories on pjlsergeant/byre – the policy lives in docs/SECURITY.md.