Skip to content

Decision: nothing stops an agent deleting a file — containment is network-only #302

Description

@AminChirazi

needs-human under CHARTER §8 — this is a public-API decision and a scope question, not a defect to fix. Filed for a decision, not for a loop to take.

The gap

The promise the product is marketed on — most plainly on automators.ai/flowproof, and in the README as of #298 — is that a bot "only ever does the job it was given, and never deletes, sends or approves the thing it must not."

Containment today is network only. The BPF filter traps connect, sendto, sendmsg, sendmmsg, listen, plus EPERM on io_uring_setup and socket(AF_PACKET). Everything else returns SECCOMP_RET_ALLOW (crates/flowproof-adapters/src/egress_linux.rs:190-215). open, write, unlink, rename, execve are untouched. There is no Landlock, no chroot, no mount namespace — verified by absence across crates/.

So an agent under full containment on Linux can delete any file its uid can reach. It can also execve freely; children inherit the network filter under NO_NEW_PRIVS but nothing constrains what they do to disk.

The mcp: stand-in covers declared tools only, and is convention-dependent rather than mechanism-enforced (see the separate concern below).

Why this needs a human

Three reasons it is not a loop task:

  1. Net-new public API. Any answer adds surface — an allow_fs:, an assert_no_fs_write, or a new lane in the trace. CHARTER DECIDE 5 caps net new public API precisely so this kind of thing is deliberate.
  2. It is a positioning decision, not only a technical one. There is a legitimate answer that says no — flowproof is "a testing sandbox, not a jail" (egress_linux.rs:10-11, docs/agent-testing.md:883-884), and the honest move is to make the marketing narrower rather than the mechanism wider. That is a founder call.
  3. It interacts with the containment/behaviour split, which is the page's load-bearing copy rule.

The options, as I see them

A. Narrow the claim. Keep containment network-only; make the docs and the page say "network" wherever they currently say "can't". Cheapest, entirely honest, and gives up the line that most resonates with the buyer.

B. Detection without prevention. No filesystem lock, but a red-path proof that a destructive filesystem action is observed and fails the run. Fits the existing "record it, then assert over it" model, needs no new containment machinery, and is a behaviour claim — so it belongs in the outlined panel, not the filled one.

C. Real filesystem containment. Landlock (kernel ≥ 5.13) is the natural fit and composes with the existing NO_NEW_PRIVS + seccomp install path. Strongest, most work, and inherits every platform limit that already applies to egress.

My read: B is the best value and the smallest lie-surface. It matches what flowproof actually is, it is testable in the falsifiability suite alongside the other red-path proofs, and it does not promise a jail. C is a real product if filesystem risk is what pilots actually ask about — which is worth knowing before building it.

Related, same decision family

The mcp: stand-in currently sits in the page's containment ("it can't") block, but it is bypassable by misconfiguration: flowproof injects FLOWPROOF_MCP_SERVER_<NAME> (crates/flowproof-cli/src/agent_flow.rs:276-280) and the agent's own config has to point at it. If it points at the real server instead, flowproof is out of the path. The guards at agent_flow.rs:410-425 detect the empty lane after the fact — that is a guard, not a barrier.

Under the page's own hard copy rule (a behaviour claim written as a containment claim is the one mistake a security-minded reader will not forgive), that placement is hard to defend as-is. It either needs qualifying in place or moving. Same decision, so noted here rather than filed separately.

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs-humanA loop escalated this: it needs a decision or a protected-path change

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions