all posts

The best sandbox APIs for .NET agents in 2026

Ajay Kumar··10 min read

If you are building an agent in C#, you have almost certainly hit this in the following order: you wire up Semantic Kernel, you give the model a tool that executes code, you reach for Roslyn scripting because it is right there in NuGet, and then somebody asks what stops the generated code from reading appsettings.json. There is no good answer inside the process. This post is about what to do instead.

I'm Ajay, I build PandaStack, which is one of the options below — treat this as a vendor's roundup. The .NET-specific parts are not marketing, though: they are the same three dead ends every C# team walks into, and they are worth stating precisely before any comparison.

Code Access Security is gone and is not coming back

On .NET Framework you could, in principle, run partially trusted code with Code Access Security and a restricted permission set. That mechanism does not exist in modern .NET. Microsoft's own guidance is unambiguous: CAS was never a reliable security boundary even when it shipped, and .NET Core and everything after it deliberately dropped it. Anyone reaching for the old advice is reading documentation for a runtime they are not using.

The same applies to AppDomains. On .NET Framework, an AppDomain was the usual answer to 'isolate this plugin'. Modern .NET has exactly one AppDomain per process, and the isolation story it used to provide simply is not there.

AssemblyLoadContext is a loader, not a boundary

This is the most common substitution, and it is a category error. AssemblyLoadContext solves assembly versioning and unloadability — two copies of a library, plugins you can unload. It does not restrict what loaded code can do. Code in a collectible AssemblyLoadContext can still open files, make network calls, read environment variables and P/Invoke into native code, because it is running in your process with your process's privileges.

Roslyn scripting is the same story one level up. Microsoft.CodeAnalysis.CSharp.Scripting compiles and runs C# with full trust by default. You can restrict which assemblies the script references, and it is worth doing, but that is a usability guardrail, not a security control — reflection and P/Invoke are one line away from routing around it.

// This is NOT a sandbox. The reference list is a convenience, not a boundary.
var options = ScriptOptions.Default
    .WithReferences(typeof(object).Assembly)
    .WithImports("System");

// Generated code can still reach the filesystem via reflection or P/Invoke.
await CSharpScript.EvaluateAsync(modelOutput, options);

Process.Start is separation, not isolation

Shelling out to `dotnet run` in a child process is a genuine improvement over in-process evaluation — a crash or an infinite loop no longer takes your agent with it. But the child runs as the same user, on the same filesystem, with the same network access and the same credentials in the environment. It is a blast-radius reduction, not a trust boundary.

Containers share your kernel

The usual next step is a container per execution, and for most workloads that is a reasonable trade the entire industry makes. It is worth being precise about what it buys: namespaces and cgroups on a kernel every tenant shares. A kernel vulnerability is a cross-tenant vulnerability, and container escape CVEs are a recurring category rather than a historical curiosity.

For code you wrote, that is fine. For code a language model just produced in response to an untrusted prompt, the honest position is that you want a boundary the kernel is on the inside of.

The .NET tax nobody mentions

Every sandbox vendor in this category ships a Python SDK first and a TypeScript SDK second. As of 2026, none of them ships a first-party, supported C# SDK. That is the single most important practical fact for a .NET team, and it changes what you should evaluate:

  • You will talk to the sandbox over its REST API with HttpClient, or wrap a thin client yourself. Budget for that; it is usually a day, not a week.
  • Documentation quality for the raw HTTP API matters more to you than SDK ergonomics do. A vendor with a beautiful Python SDK and a thin API reference is a worse buy for you than the reverse.
  • Streaming matters. Agent UX depends on streaming stdout back as it happens, so check whether the HTTP API exposes server-sent events or only a blocking call that returns at the end.
  • The code you execute inside the sandbox does not have to be C#. Plenty of .NET agents generate Python for data work because the libraries are better, and only the orchestration is C#.

The criteria I would actually use

  1. Isolation boundary: hardware virtualisation or shared kernel. This is the one that cannot be fixed later.
  2. Quality of the raw HTTP API, since that is your integration surface.
  3. Cold start, because an agent that runs a dozen tool calls per turn pays it a dozen times.
  4. Whether the .NET SDK can be installed inside the sandbox, if you want to execute C# rather than orchestrate it.
  5. What an idle sandbox costs while the model is thinking.

1. PandaStack

Mine, so discount accordingly. Each sandbox is a Firecracker microVM with its own kernel, created by restoring a baked snapshot — p50 create is 179ms, which is the number that matters when a turn triggers several tool calls. The HTTP API is documented as an OpenAPI 3.1 spec, which for a .NET team is the useful part: you can generate a typed client rather than hand-writing one.

using var http = new HttpClient { BaseAddress = new Uri("https://api.pandastack.ai") };
http.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("PANDASTACK_API_KEY"));

var created = await http.PostAsJsonAsync("/v1/sandboxes",
    new { template = "code-interpreter", ttl_seconds = 300 });
var sandbox = await created.Content.ReadFromJsonAsync<JsonElement>();
var id = sandbox.GetProperty("id").GetString();

var run = await http.PostAsJsonAsync($"/v1/sandboxes/{id}/exec",
    new { command = "python3 -c 'print(2 + 2)'" });
var result = await run.Content.ReadFromJsonAsync<JsonElement>();
Console.WriteLine(result.GetProperty("stdout").GetString());

There is no first-party C# SDK, same as everyone else in this list — I would rather say that plainly than imply otherwise. Sandboxes also fork from a snapshot, which is genuinely useful for agents: you can branch a prepared environment several ways and explore in parallel instead of rebuilding setup per attempt.

2. E2B

The best-known name in the category and the one with the largest community, so the most existing example code to learn from — nearly all of it Python or TypeScript. Firecracker-based, so the isolation boundary is the strong one. For a .NET team the integration story is the same REST-and-HttpClient work as everywhere else.

Excellent at the thing it is designed for — Python functions on serious hardware, GPUs included — and the sandbox primitive came later. If your agent's heavy lifting is model inference and the code execution is adjacent to it, Modal is a strong single-vendor answer. If you want a general sandbox and are not writing Python, its Python-centric design works against you more than most.

4. Daytona

Comes at this from the development-environment direction rather than the ephemeral-execution direction, which shows in the primitives: longer-lived workspaces, editor integration, a repo-shaped mental model. Good if your agent works on a checked-out codebase over many turns; heavier than you need for stateless tool calls.

5. Vercel Sandbox

The natural choice if the agent already lives in a Vercel application — one vendor, one bill, one auth model. It is deliberately scoped to that world, and as a .NET team you are by definition not in it, so most of the integration advantage evaporates.

6. Cloudflare Sandbox SDK / Workers

Very fast starts and a global edge footprint, on a runtime that is not a general Linux machine. Excellent for short, well-bounded execution; a poor fit if the generated code expects to install packages or use a normal filesystem, which C#-adjacent workloads usually do.

7. Runloop

Aimed squarely at coding agents — devboxes, repo state, benchmark harnesses. Similar tradeoff to Daytona: strong when the unit of work is a repository over time, more machinery than you want for a single tool call.

What I would do on a Tuesday

Delete the Roslyn scripting path first — it is the one that will be in the incident report. Then decide whether you are orchestrating from C# and executing anything (in which case pick on isolation, cold start and HTTP API quality) or genuinely need to execute C# inside the sandbox (in which case verify the .NET SDK installs cleanly in the sandbox image before you compare anything else). Write the thin HttpClient wrapper once, behind an interface, and keep the vendor swappable — that day of work is what makes the rest of this comparison low-stakes.

Frequently asked questions

Can I sandbox C# code inside my own process?

No, not in modern .NET. Code Access Security and multi-AppDomain isolation were both removed after .NET Framework, and AssemblyLoadContext is an assembly loader rather than a security boundary — code inside one keeps your process's full privileges. The supported answer is out-of-process isolation, and for untrusted or model-generated code, a boundary stronger than a shared-kernel container.

Is Roslyn scripting safe for running model-generated code?

No. Microsoft.CodeAnalysis.CSharp.Scripting executes with full trust by default. Restricting the reference list is worth doing as a guardrail, but it is not a security control — reflection and P/Invoke route around it. Treat Roslyn scripting as a convenient compiler, and put the security boundary somewhere else entirely.

Do any sandbox vendors ship a C# SDK?

As of 2026, none of the major ones ship a first-party, supported C# SDK — Python and TypeScript are the two everyone builds first. In practice you call the REST API with HttpClient, or generate a client from the vendor's OpenAPI spec if they publish one. It is usually about a day of work, and it makes the quality of the raw HTTP API documentation a more important selection criterion for a .NET team than SDK ergonomics.

Should my .NET agent execute C# or Python in the sandbox?

Often Python, even in a C# codebase. Orchestration stays in .NET where your application lives, while the generated code targets whichever ecosystem has the better libraries for the task — which for data analysis and plotting is usually Python. Execute C# when the task genuinely concerns your own C# code, such as running a test suite or reproducing a bug.

Keep reading

Run code in a microVM in one API call.

49ms p50 cold start. Fork, snapshot, and scale to zero.

Start free
Written by Ajay Kumar, Founder, PandaStack.