Topic: Cloudflare
Cloudflare OS: Sandboxes Are Not the Security Model
Cloudflare OS offers a useful pattern for agent-built apps: isolate generated code, remove ambient authority, grant narrow capabilities, and review side effects separately.
Animated meme (expand/collapse)
“Run AI-generated code in a sandbox” sounds like the responsible answer to agent security. It is necessary, but it answers only one question: can the code escape its execution environment?
It does not answer what the code may legitimately do through the APIs, credentials, storage, and tools placed inside that environment.
Cloudflare recently open-sourced Cloudflare OS, an internal AI workspace where agents build small applications called Gadgets. A recent Reddit post focused on its isolated runtime, real-time state, and agent-generated apps. Those pieces are interesting, but the more reusable idea is quieter:
Generated code should begin with no ambient authority. Give it narrow, unforgeable capabilities for one task, while secrets and final authorization remain outside the sandbox.
That is a better security model than placing a powerful API key inside a container and calling the container “isolated.”
Cloudflare OS is a reference architecture, not a new desktop OS
The repository describes Cloudflare OS as an AI productivity environment, not a traditional operating system. It combines an agent chat, sandboxed personal apps, and a security layer named Gatekeepers.
Each Gadget has a server component running in a Dynamic Worker and client code running in a sandboxed iframe. Durable Objects provide per-Gadget state and collaboration. Cap’n Web RPC connects the pieces and exposes an API that both the client and an agent can call.
This is current, working code, but the repository also labels the August 2026 v2 release as early access, with rough edges and unfinished deployment details. Treat it as a design worth studying, not a production platform that has already made every hard decision for you.
The useful design separates four jobs:
| Boundary | Job | Failure it limits |
|---|---|---|
| Sandbox | Isolate generated code and resource use | Runtime escape and host damage |
| Capability | Expose only named resources and operations | Excessive permissions and data access |
| Gatekeeper | Authorize, audit, and stage side effects | Excessive autonomy |
| Durable state | Preserve application state and pending work | Lost or duplicated work after interruption |
Collapsing these into one “agent has tools” switch creates ambient authority: every tool and credential is silently available whether the current task needs it or not.
A sandbox contains code; it does not define authority
Dynamic Workers can load runtime-supplied code in separate V8 isolates. The loader controls bindings, network access, observability, and resource limits. For short TypeScript automations, this is lighter than booting a Linux container.
The safe default is explicit in Cloudflare’s egress-control documentation: set globalOutbound to null, then add only the capabilities the workload needs.
A simplified loader looks like this:
const worker = env.LOADER.load({
mainModule: "agent.js",
modules: { "agent.js": generatedCode },
globalOutbound: null,
env: {
REPOSITORY: readOnlyRepository,
},
limits: {
cpuMs: 20,
subRequests: 10,
},
});
The generated code cannot make arbitrary Internet requests. It receives one repository capability, not a GitHub token, not a generic shell, and not every integration configured for the parent application.
The sandbox still matters. It prevents generated code from reaching process memory, the host file system, or unrelated resources through normal runtime APIs. But if REPOSITORY exposes deleteRepository() to every task, isolation cannot save the repository. That is an authorization bug, not a sandbox escape.
Bind methods, not secrets
Cloudflare’s Dynamic Workers bindings use a capability model. The parent Worker passes an RPC stub into the sandbox; without the stub, the Dynamic Worker cannot discover or forge access to that object.
The distinction changes API design. Instead of giving generated code this:
GITHUB_TOKEN=token_with_repo_scope
give it an interface shaped for the task:
interface RepositoryReader {
listFiles(path: string): Promise<string[]>;
readFile(path: string): Promise<string>;
}
The implementation stays outside the sandbox. It can attach credentials, restrict the repository and path, validate the current user, rate-limit calls, and record an audit event. The model sees the methods, not the secret.
This is more than hiding an environment variable. A leaked broad token can be replayed anywhere until revoked. A narrow RPC stub has no global identifier, cannot be forged, and routes every call through policy code you control.
Cloudflare’s egress gateway offers the same pattern for libraries that must use HTTP: intercept outbound requests, allow only selected destinations, and inject credentials after the request leaves the sandbox. Generated code asks for a resource; it never handles the credential that authorizes the request.
Resource introductions beat globally configured tools
Cloudflare OS does not automatically make every configured external account available to every Gadget. A user introduces a specific resource—such as one repository—to one agent or application.
That is a useful correction to common MCP setups. Configuring ten servers globally may be convenient, but it silently gives every conversation a large capability surface. Tool search can hide schemas from the model’s context; it does not remove underlying authority.
A stronger grant answers five questions:
- Who is the agent acting for?
- Which resource may it access?
- Which operations are allowed?
- How long does the grant last?
- Which calls require separate approval?
“GitHub access” is not a useful answer. “Read files under /docs in repository X until this task ends” is.
This aligns with OWASP’s Excessive Agency guidance: minimize tool functionality, permissions, and autonomy; execute in the user’s context; require human approval for high-impact actions. Model quality does not remove this requirement. A perfect model can still receive malicious instructions from an email, web page, or tool result.
Approval should be a proposed transaction
Cloudflare OS Gatekeepers wrap external services, handle authorization, narrow resources, log calls, and require approval for side effects. Their experimental twist is asynchronous approval: simulate a write, let the agent continue using the simulated result, then ask the user to approve the queued actions later.
That is more useful than returning from coffee to find an agent blocked on step one. It is also more complex than adding an “Approve all” button.
Animated meme (expand/collapse)
Treat a simulated side effect as a proposed transaction, not a completed fact. A reliable queue needs:
- The exact operation, arguments, actor, resource, and policy version.
- A preview that cannot be controlled by untrusted content.
- Dependencies between proposals, so rejecting step one invalidates steps built on it.
- Expiration and revalidation before execution.
- Idempotency keys or another duplicate-execution defense.
- Clear separation between simulated state and committed external state.
Do not let the agent render its own approval summary. OWASP documents approval-dialog forging as a real attack surface: malicious content can make a dangerous operation appear harmless. The policy layer should generate the human-readable diff from validated structured data.
Bulk approval is appropriate for a coherent, reversible batch. Sending email, publishing content, moving money, changing IAM, or deleting data deserves narrower review because the real world cannot always roll back with the local simulation.
Isolation also needs budgets and evidence
Agent loops can be harmless to data and still expensive or noisy. Cloudflare lets a loader apply per-invocation CPU and subrequest limits. Those controls belong beside capability grants:
authority budget = methods + resources + time
compute budget = CPU + subrequests + retries
evidence trail = inputs + capability calls + approvals + results
Dynamic Worker logs do not automatically become a durable audit trail. Official observability guidance uses Tail Workers to collect logs, exceptions, and request metadata after execution. Store the security events you need, redact secrets and private content, and attach a stable task or proposal ID.
Logs alone are not authorization. They explain what happened after policy decided whether it was allowed.
A practical adoption path
You do not need to deploy Cloudflare OS to borrow its strongest pattern.
- Inventory every tool, credential, network destination, and storage binding available to the agent today.
- Remove ambient access; begin each task with no external capability.
- Wrap resources in narrow interfaces tied to the current user and object.
- Keep credentials outside generated code and inject them only at an audited gateway.
- Separate reads, reversible writes, and irreversible actions into different policy classes.
- Add explicit budgets for CPU, subrequests, retries, and task lifetime.
- Log structured capability calls and approval decisions without logging secrets.
- Test prompt injection from user input, retrieved documents, web pages, and tool results.
If a full Linux toolchain or native binary is required, use a hardened container or microVM. If the workload is a short script against a narrow typed API, a Dynamic Worker isolate may be cheaper and faster. The capability boundary should remain the same either way.
Conclusion: remove authority before adding intelligence
The most interesting part of Cloudflare OS is not that an agent can generate another small app. We already have plenty of demos for that.
The useful part is treating generated software like untrusted tenant code: isolate it, deny network access by default, give it object-specific capabilities, keep secrets outside, budget its work, and stage dangerous side effects for independent review.
A sandbox answers “where can this code run?” Capability design answers “what may it do?” Agent systems need both, and the second question usually decides the real blast radius.
External references
- Cloudflare OS repository and architecture overview
- Cloudflare Dynamic Workers
- Dynamic Workers: Egress control
- Dynamic Workers: Capability-based bindings
- Dynamic Workers: Custom limits
- Dynamic Workers: Observability
- Cloudflare Blog: Code Mode
- daily.dev: Code Mode—the better way to use MCP
- OWASP LLM06:2025 Excessive Agency
- OWASP: HITL Dialog Forging
- Reddit: Cloudflare OS open-source discussion