Threat model
What we protect. What we don’t.
FlyWorkers runs AI agents on your infrastructure, with your API keys. The central promise is a single sentence: the agent can use the model, but it cannot have the key. Everything below is a consequence of holding that promise — or an honest statement of where it stops.
This page is a condensed, translated version of the living threat-model document that ships with the product. The rule carries over: no marketing. Every claim here is verified by an executable test, or it isn’t here.
TRUST ZONE (yours) │ UNTRUSTED (the agent's)
─────────────────────────────────┼──────────────────────────────
control-plane · harness │ agent sandbox
your API key, in RAM │ workspace + agent's git repo
vault · databases │ NO key · NO harness
│ │ egress → allowlist proxy
└── docker exec ───┼─▶ tools execute HEREThe structural decision: the harness — the process that talks to the model provider — runs outside the sandbox. In the first design it ran inside, which made the promise false by construction; an adversarial review flagged it and the design changed before code was written.
Verified, not promised
- The key never enters the sandbox
- A sentinel shaped like an API key is planted in the harness; 33 assertions confirm it appears nowhere inside — env, /proc/*/environ, argv, docker inspect, or any file of the 24 MB exported rootfs — with a positive control that proves the search works.
- The agent runs in its own unprivileged container
- cap-drop=ALL, no-new-privileges, seccomp, non-root uid, memory and CPU limits, one internal network per agent. An end-to-end test crosses the hostname seen inside against docker ps outside.
- Egress is default-deny and fail-closed
- Per-agent allowlist; no valid policy means nothing passes, not everything. 304 tests over real sockets; 10 targeted mutations produce 10 failures. An adversarial reviewer could not exfiltrate.
- Self-written tools cannot ship themselves
- The build runs with the network off, from a context that cannot include an agent-written Dockerfile, and boots on a throwaway container. Promotion requires an authenticated human of the owning tenant; the agent holds a git token, not a session.
- Memory survives the sandbox; nothing else does
- Preferences live in a git repo committed by the agent. The same test that proves memory comes back after a rebuild proves that uncommitted state is gone.
- One tenant cannot see another
- Every reachable query carries the tenant. Deleting that filter turns 19 of 26 integration tests red; returning 403 instead of the indistinguishable 404 turns 8 red.
What FlyWorkers does not protect
This list is the point of the page. It exists so you can decide with real information, not a feature list.
- 01
Kernel escape from the container
The isolation boundary is a container runtime (runc), not a microVM. A kernel local-privilege-escalation compromises the host. gVisor is supported as a fail-loud opt-in where the host allows it; if a kernel escape is in your threat model, use a microVM driver.
- 02
An attacker on the host
The host reaches any sandbox on its internal network even without published ports (verified). On a compromised host, everything else is irrelevant.
- 03
Exfiltration inside the allowlist
If github.com is allowed, data can leave through a gist. The allowlist narrows destinations; it does not eliminate exfiltration. Monitor egress volume.
- 04
Misuse of granted credentials
Credential injection protects the material, not the use. A compromised agent can ask the proxy to use any channel it legitimately has.
- 05
Persistence through self-written tools, without the human gate
The agent is self-modifying by design. The human approval gate on builds is what keeps one bad instruction from becoming permanent — it can be disabled, and disabling it is logged.
- 06
Execution isolation between organizations on one machine
Data access control exists and is tested; what two tenants on the same host still share is the kernel. The deployment topology (one VM per customer) covers this, not the code.
- 07
Abuse of a legitimate role
A compromised admin sees and operates everything in their own organization. That is what the role means.
- 08
Slack as an identity provider
The per-agent user map decides which principal runs a turn; who the human is, Slack asserts. A compromised workspace passes through the map intact. Unmapped users are denied without creating a run.
- 09
Vault rollback by DELETE+INSERT
Anti-rollback covers the UPDATE path. An attacker who can already rewrite the secrets table can reinsert old bytes; anchoring state outside the database is not in v1.
- 10
A compromise of the harness process
The harness holds the Docker socket — root-equivalent on its machine, inherent to controlling sandboxes from outside (which is what keeps your key out of the container). It runs no agent code and publishes no ports; one VM per customer bounds the blast radius to that customer.
Questions this page didn’t answer?
The full document — adversary model, vault construction, Slack access mapping, open findings with their status — ships with every deployment. Ask us for it; we’ll send it as is, open findings included.