> ## Documentation Index
> Fetch the complete documentation index at: https://docs.murmur.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Agent VM Controls

> The three legs of agent VM security — secret access, trusted input, and egress control — and the controls you have over each in Murmur.

A coding agent on a VM is risky for a specific, well-understood reason. To do its
job it needs three things at once: access to your secrets and source, the ability
to read untrusted content (issues, PRs, web pages, dependency docs), and the
ability to reach the network. Any one of those is fine. **All three together is
the problem** — a prompt-injected agent can read a secret, be told to leak it, and
have a channel to send it out.

This is Simon Willison's [**lethal trifecta**](https://simonwillison.net/2025/Jun/16/the-lethal-trifecta/):
an agent that simultaneously has (a) access to private data, (b) exposure to
untrusted content, and (c) the ability to communicate externally is exposed to
data theft, and prompt-injection detection is too unreliable to depend on. Remove
any one leg and the data-theft class collapses. Meta's
[**Agents Rule of Two**](https://ai.meta.com/blog/practical-ai-agent-security/)
makes it a rule: an agent session should satisfy **at most two** of these three —
processes untrusted input, accesses sensitive data, or can communicate externally;
if it genuinely needs all three, keep a human in the loop. Google DeepMind's
[**CaMeL**](https://simonwillison.net/2025/Apr/11/camel/) (paper: *Defeating
Prompt Injections by Design*) pushes the same principle into a capability-enforcing
interpreter.

This page maps each leg to the controls **you** have in Murmur — what you decide,
what you configure, and what the platform enforces underneath so you don't have to.

## Root on the VM is not a boundary

The agent runs as the `murmur` user with **passwordless sudo** — root on its own VM.
That's deliberate. The VM is ephemeral, single-tenant, and holds nothing the agent
can't already read: its own unsealed developer profile and its own identity token.
An in-VM privilege wall would fence nothing, so Murmur doesn't pretend it's one.
All real isolation is enforced server-side — the API authenticates every call with
the agent's identity token, the Temporal proxy admits only the VM's own task queue,
and per-tenant KMS keys never touch the VM. What root buys you is self-provisioning:
an agent that needs a system package installs it at runtime (`sudo apt-get install`,
or `npx playwright install --with-deps chromium` on an image with Node.js) instead
of stranding on a missing dependency.

The honest cost is defense-in-depth on the `murmur-vm` supervisor: a root agent
could tamper with it and misreport its own lifecycle events. Those events carry
only the VM's own identity — they can't cross a tenant or touch another agent — and
durable state is re-derived from GitHub, not from what the VM says about itself. If
your policy requires a non-root agent anyway, remove `/etc/sudoers.d/murmur` in
your own [recipe](/concepts/recipe) bake.

## Leg 1 — Secret access

You decide which credentials an agent can reach, and Murmur guarantees those
credentials never leave the VM in usable form.

**What you control:**

* **Scope secrets to where they're needed.** Tenant [secrets](/concepts/secrets)
  are only injected into the [workspaces](/concepts/workspaces) whose `secret_refs`
  list them — keep a secret out of a workspace and no agent there ever sees it.
  Pass one-off credentials as spawn-time secrets (`murmur spawn -e`) that live only
  for that single agent.
* **Run agents under a narrowed identity.** A [service profile](/security/service-profile)
  gives an automated agent its own bot credentials and its own access grants, so a
  Flight or bot gets exactly the access it needs instead of inheriting a developer's
  full scope.
* **Secret values are write-only.** The API never returns a stored secret value —
  [`murmur secret ls`](/cli/secret-ls) shows names only, and a value can't be read
  back once set. RBAC governs who can *manage* secrets (`secret.create`,
  `secret.edit`, `secret.delete`) through [roles and bindings](/security/authorization);
  which agents actually *receive* a secret is set by the workspace's `secret_refs`,
  above.

**What the platform enforces for you:**

* **End-to-end encryption to the specific VM.** Credentials are encrypted at rest
  under your tenant's KMS key, re-sealed with NaCl box to the target VM's
  *ephemeral* key, decrypted only in memory, and destroyed with the VM. See
  [Encryption](/security/encryption).
* **Per-tenant isolation.** Each tenant has its own KMS key, and AAD binding makes
  a secret encrypted for one tenant (or developer) impossible to decrypt for
  another.
* **Secret scrubbing on the way out.** As a backstop, `murmur-vm` redacts any
  session-event field or task response that **exactly equals** an unsealed profile
  secret, replacing it with `[REDACTED]` before it leaves the VM — so an agent that
  is tricked into echoing a credential can't ship it back through the control plane.

  <Warning>
    Scrubbing is **exact-match only** — it catches a string equal to a secret in its
    entirety, not a secret embedded in a larger string or transformed (e.g.
    base64-encoded). It is a conservative backstop, not a guarantee, and it does not
    inspect traffic the agent sends directly to the network — that's the egress leg.
  </Warning>

## Leg 2 — Trusted input

A coding agent has to read untrusted content — that's the job — so you can't stop
injected *content* from reaching it. What you **can** control is **who is allowed
to steer the agent**: whose instructions it will act on. Murmur gives you two
layers of this.

### Who in your org can drive an agent (RBAC)

Steering a running agent — queueing follow-ups, updating its task list, killing it
— requires the `agent.edit` permission; acting *as* an agent requires
`agent.assume`. You grant these through [roles, groups, and
tenant-bindings](/security/authorization), and you can scope them with name
patterns so a developer drives only their own agents. An org member without
`agent.edit` on an agent simply cannot send it instructions.

### Which external identities can steer an agent (steering policies)

The riskier input path is **events from outside your org** — a PR comment, a
review, or an issue/PR that opens and triggers a [Flight](/concepts/flights).
Murmur gates these with **steering policies**, so a stranger commenting on a public
PR can't drive your agent.

A steering policy sets a minimum **tier** of trust for the event's author, plus
optional **allowlists** of specific usernames:

| Tier             | Who may steer                                                   |
| ---------------- | --------------------------------------------------------------- |
| `OPEN`           | Any author                                                      |
| `COLLABORATORS`  | Owners, members, and repo collaborators (write/triage)          |
| `MEMBERS`        | Org owners and members                                          |
| `ALLOWLIST_ONLY` | Only the named allowlists (plus a user-owned agent's own owner) |

You attach a policy in two places, and **the narrower of the two always wins**:

* **Per repo** — set a steering policy on a repo's [config](/catalog/repo-config) to
  govern events coming from that repo. If you set nothing, Murmur auto-selects by
  repo visibility: **public repos default to `COLLABORATORS`**, **private repos to
  `OPEN`** (every commenter is already org-vetted).
* **Per service profile** — set a policy on a [service profile](/security/service-profile)
  to gate every agent that runs under it, regardless of which repo the event came
  from. A locked-down profile can't be loosened by a permissive repo.

Allowlists (named sets of usernames, scoped by identity provider) let you admit
specific trusted outsiders or approved bots — e.g. `dependabot[bot]` — without
opening the tier for everyone.

<Note>
  Enforcement is fail-closed and auditable: an event whose author fails the
  effective policy is recorded on the agent's timeline as **BLOCKED** and is never
  delivered — no follow-up, no checklist task, no wake, no Flight spawn. The agent's
  own owner can always steer their own agent.
</Note>

## Leg 3 — Egress control

Egress control — restricting where an agent VM can send traffic — is the
highest-leverage leg, because it's the one you can cut on a coding agent without
taking away its job. In Murmur, **egress control is a feature of
[customer placements](/guides/customer-placements).**

When you run agents in a customer placement, each VM boots in **your own GCP
project or AWS account, on your subnet** — so the network the VM lives in is yours,
and you apply **whatever native egress controls your cloud provides**. There's
nothing Murmur-specific to learn:

* VPC firewall rules / security groups that default-deny outbound and allow only
  the destinations you choose
* A forced egress proxy, NAT gateway, or VPN
* DNS-resolution allowlists and SNI/Host filtering at a managed firewall
* Cloud-native network policy, flow logs, and your own incident response

Because the VM is in your account, **you own the network path end to end** — your
rules, your routes, your egress, your logs. If a VM misbehaves it's in your
project: you can capture logs, snapshot the disk, or shut it down directly. See
[Customer placements](/guides/customer-placements) for setup and
[Placements](/concepts/placement) for the concept.

<Warning>
  On the default **platform placements**, agent VM egress is **not restricted** — VMs
  can reach the public internet. If your threat model requires cutting the egress
  leg, run your agents in a customer placement and apply your own network controls
  there.
</Warning>

***

| Type      | Page                                                                                         |
| --------- | -------------------------------------------------------------------------------------------- |
| Concept   | [Security model](/security/overview)                                                         |
| Guide     | [Encryption](/security/encryption)                                                           |
| Guide     | [Authorization (RBAC)](/security/authorization)                                              |
| Concept   | [Secrets](/concepts/secrets)                                                                 |
| Guide     | [Service profiles](/security/service-profile)                                                |
| Reference | [Repo config](/catalog/repo-config)                                                          |
| Guide     | [Customer placements](/guides/customer-placements)                                           |
| Concept   | [Placements](/concepts/placement)                                                            |
| External  | [The lethal trifecta (Willison)](https://simonwillison.net/2025/Jun/16/the-lethal-trifecta/) |
| External  | [Agents Rule of Two (Meta)](https://ai.meta.com/blog/practical-ai-agent-security/)           |
| External  | [CaMeL (DeepMind / Willison)](https://simonwillison.net/2025/Apr/11/camel/)                  |
