<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Vagner Bessa</title>
    <description>The latest articles on DEV Community by Vagner Bessa (@bessavagner).</description>
    <link>https://dev.to/bessavagner</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1268867%2Fb2cf9ef0-6390-40b1-8f98-1e82e9a9f5d2.png</url>
      <title>DEV Community: Vagner Bessa</title>
      <link>https://dev.to/bessavagner</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bessavagner"/>
    <language>en</language>
    <item>
      <title>Running LLM-Generated Code Without Getting Burned</title>
      <dc:creator>Vagner Bessa</dc:creator>
      <pubDate>Thu, 25 Jun 2026 11:41:57 +0000</pubDate>
      <link>https://dev.to/bessavagner/running-llm-generated-code-without-getting-burned-1gd7</link>
      <guid>https://dev.to/bessavagner/running-llm-generated-code-without-getting-burned-1gd7</guid>
      <description>&lt;p&gt;Language models are good at writing code. Ask one to compute a correlation, reshape a dataset, or plot two columns against each other, and it will happily produce a few lines of Python that do exactly that. What it can't do on its own is &lt;em&gt;run&lt;/em&gt; that code, look at the result, and use it to answer your question. Closing that loop — letting a model write code, execute it, and read the output back — is what turns a chatbot into something that can actually do data analysis.&lt;/p&gt;

&lt;p&gt;It's also where things get dangerous. The moment you execute text a model generated, you're running untrusted code on your machine. This post is about how to do that without handing an attacker (or a confused model) the keys to your server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why running model-written code is dangerous
&lt;/h2&gt;

&lt;p&gt;The problem isn't that models are malicious. It's that "run this Python" is an enormous capability, and a model can be steered into misusing it — by a prompt injection hidden in a document it's analyzing, by a jailbreak, or simply by hallucinating something destructive. Once arbitrary code runs in your process, it can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Read secrets&lt;/strong&gt; — environment variables, API keys, the contents of nearby files, your database credentials.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reach the network&lt;/strong&gt; — exfiltrate data to a remote host, or pull down a second-stage payload.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exhaust resources&lt;/strong&gt; — an infinite loop or a runaway allocation that takes the host down.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Escape into the host&lt;/strong&gt; — delete files, spawn processes, modify the system.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the design goal is narrow and specific: &lt;strong&gt;allow general computation while denying general capability.&lt;/strong&gt; You want the model to be able to run &lt;code&gt;numpy&lt;/code&gt; and &lt;code&gt;matplotlib&lt;/code&gt;, but not to open a socket, read &lt;code&gt;/etc/passwd&lt;/code&gt;, or fork-bomb the box.&lt;/p&gt;

&lt;h2&gt;
  
  
  The isolation spectrum
&lt;/h2&gt;

&lt;p&gt;There's no single "sandbox" primitive. There's a spectrum, trading strength for cost and complexity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;In-process restriction&lt;/strong&gt; (e.g. &lt;a href="https://github.com/zopefoundation/RestrictedPython" rel="noopener noreferrer"&gt;RestrictedPython&lt;/a&gt;) rewrites or limits what Python code can do. It's lightweight but leaky — Python's introspection makes airtight in-process sandboxing notoriously hard. Treat it as a speed bump, not a wall.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OS-level isolation&lt;/strong&gt; — Linux namespaces, cgroups, and seccomp filters confine a process's view of the filesystem, network, and syscalls. This is what containers are built on, and what Anthropic's &lt;a href="https://github.com/anthropic-experimental/sandbox-runtime" rel="noopener noreferrer"&gt;sandbox-runtime&lt;/a&gt; applies without a full container.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Containers&lt;/strong&gt; (Docker, Podman) bundle that isolation into a disposable unit with its own filesystem and resource limits. The pragmatic default for most teams.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MicroVMs&lt;/strong&gt; (&lt;a href="https://firecracker-microvm.github.io/" rel="noopener noreferrer"&gt;Firecracker&lt;/a&gt;) and &lt;strong&gt;gVisor&lt;/strong&gt; (&lt;a href="https://gvisor.dev/" rel="noopener noreferrer"&gt;gvisor.dev&lt;/a&gt;) add a hardware-virtualization or kernel-emulation boundary that a plain container can't offer — the standard choice when you're running &lt;em&gt;other people's&lt;/em&gt; untrusted code at scale.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WebAssembly&lt;/strong&gt; (&lt;a href="https://pyodide.org/" rel="noopener noreferrer"&gt;Pyodide&lt;/a&gt;) runs Python compiled to WASM with no host filesystem or network by default — strong isolation, at the cost of a constrained runtime.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For most applications, a &lt;strong&gt;disposable container&lt;/strong&gt; hits the sweet spot: strong enough, cheap enough, and easy to reason about.&lt;/p&gt;

&lt;h2&gt;
  
  
  A minimal Docker sandbox
&lt;/h2&gt;

&lt;p&gt;You don't need a framework to get started. Here's the shape of a locked-down container using the Docker SDK for Python — every flag here is doing security work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;docker&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_env&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run_untrusted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;containers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;python:3.12-slim&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;python&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-c&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;   &lt;span class="c1"&gt;# the model's snippet
&lt;/span&gt;        &lt;span class="n"&gt;network_disabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;            &lt;span class="c1"&gt;# no network egress at all
&lt;/span&gt;        &lt;span class="n"&gt;mem_limit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;256m&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                 &lt;span class="c1"&gt;# cap memory
&lt;/span&gt;        &lt;span class="n"&gt;pids_limit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                   &lt;span class="c1"&gt;# cap process count (anti fork-bomb)
&lt;/span&gt;        &lt;span class="n"&gt;read_only&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                   &lt;span class="c1"&gt;# read-only root filesystem
&lt;/span&gt;        &lt;span class="n"&gt;cap_drop&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ALL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;                 &lt;span class="c1"&gt;# drop every Linux capability
&lt;/span&gt;        &lt;span class="n"&gt;remove&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                      &lt;span class="c1"&gt;# discard the container afterwards
&lt;/span&gt;        &lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The container is created for one snippet and thrown away. It has no network, a hard memory ceiling, a capped process count, a read-only root, and no Linux capabilities. If the model writes something hostile, the blast radius is a throwaway container with nowhere to go and nothing to steal.&lt;/p&gt;

&lt;p&gt;If you'd rather not hand-roll this, &lt;a href="https://github.com/vndee/llm-sandbox" rel="noopener noreferrer"&gt;&lt;code&gt;llm-sandbox&lt;/code&gt;&lt;/a&gt; wraps the same idea in a small API, with Docker, Podman, and Kubernetes backends:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;llm_sandbox&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SandboxSession&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;SandboxSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;python&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;keep_template&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;import numpy as np; print(np.mean([1, 2, 3]))&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;libraries&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;numpy&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# "2.0"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Capturing results, including plots
&lt;/h2&gt;

&lt;p&gt;Running code is only half of it — you need the output back in a form the model and the user can use. &lt;code&gt;stdout&lt;/code&gt; and &lt;code&gt;stderr&lt;/code&gt; are easy. Plots are the interesting part: a data agent that can't show a chart isn't much of a data agent.&lt;/p&gt;

&lt;p&gt;The trick is to run the snippet inside a session that captures matplotlib figures and hands them back as images. &lt;code&gt;llm-sandbox&lt;/code&gt; does this when plotting is enabled — the model writes ordinary plotting code and calls &lt;code&gt;plt.show()&lt;/code&gt;, and the infrastructure turns the figure into a base64-encoded PNG you can stream into the chat. Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# inside the sandbox session, with artifact capture turned on
&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;import matplotlib.pyplot as plt&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;plt.plot([1, 2, 3], [2, 4, 6]); plt.show()&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plots&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;        &lt;span class="c1"&gt;# captured figures
&lt;/span&gt;    &lt;span class="nf"&gt;save_png&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content_base64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The model never has to know about your capture mechanism. It writes normal code; the harness handles turning a figure into a displayable artifact.&lt;/p&gt;

&lt;h2&gt;
  
  
  Defense in depth
&lt;/h2&gt;

&lt;p&gt;The container is the hard boundary, but it shouldn't be the only one. A small amount of belt-and-suspenders pays off:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Constrain the model with the prompt.&lt;/strong&gt; Tell it which libraries are allowed and what's off-limits. This keeps it inside the lines &lt;em&gt;before&lt;/em&gt; the container would have to stop it:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  You may use only: pandas, numpy, matplotlib, seaborn, scipy.
  Never import os, subprocess, socket, or requests.
  Do not read or write files outside the working directory,
  and never make network calls.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Allowlist libraries&lt;/strong&gt;, don't blocklist them. Decide what can be installed; reject everything else.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cap code length and execution time.&lt;/strong&gt; A wall-clock timeout on each run prevents a clever or accidental hang. (Anthropic's hosted code-execution tool, for instance, enforces a per-cell time limit and returns a timeout result rather than blocking — see the &lt;a href="https://docs.anthropic.com/en/docs/agents-and-tools/tool-use/code-execution-tool" rel="noopener noreferrer"&gt;code execution tool docs&lt;/a&gt;.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Degrade gracefully.&lt;/strong&gt; If execution isn't available — the feature is off, or there's no Docker socket — return a friendly error instead of crashing the agent. The model should be able to keep answering questions even when it can't run code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these replace the sandbox. They reduce how often it has to do its job, and they shrink the surface the model can probe.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't want to run your own? Use a managed sandbox
&lt;/h2&gt;

&lt;p&gt;Running disposable containers in production — pooling, scaling, cleaning up — is real work. Several services exist specifically to take it off your hands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://e2b.dev/" rel="noopener noreferrer"&gt;E2B&lt;/a&gt;&lt;/strong&gt; runs AI-generated code in Firecracker microVMs with a code-interpreter SDK; sandboxes start in well under a second.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://modal.com/" rel="noopener noreferrer"&gt;Modal&lt;/a&gt;&lt;/strong&gt; offers serverless sandboxes you can spin up per request.&lt;/li&gt;
&lt;li&gt;Model providers ship their own server-side execution. &lt;strong&gt;Anthropic's &lt;a href="https://docs.anthropic.com/en/docs/agents-and-tools/tool-use/code-execution-tool" rel="noopener noreferrer"&gt;code execution tool&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;OpenAI's &lt;a href="https://platform.openai.com/docs/assistants/tools/code-interpreter" rel="noopener noreferrer"&gt;Code Interpreter&lt;/a&gt;&lt;/strong&gt; both run the model's code in a hosted sandbox and return results and files — no infrastructure on your side at all.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A nice property of building behind a small &lt;code&gt;execute(code)&lt;/code&gt; interface is that the backend becomes a swappable detail: run a local container in development, delegate to a provider's sandbox in production, and the agent code barely changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping it fast: a warm pool
&lt;/h2&gt;

&lt;p&gt;One practical wrinkle: cold-starting a container with &lt;code&gt;pandas&lt;/code&gt;, &lt;code&gt;numpy&lt;/code&gt;, &lt;code&gt;matplotlib&lt;/code&gt;, and friends adds seconds of latency to every request. The fix is a &lt;strong&gt;pre-warmed pool&lt;/strong&gt; — create a handful of ready containers at startup, hand one out per request, and reclaim idle ones when traffic drops. You trade a little idle memory for a much snappier interaction, which matters a lot when a user is waiting on a chart.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this is worth getting right
&lt;/h2&gt;

&lt;p&gt;This is a recurring shape in modern AI engineering: give a model real computational power without giving it dangerous reach. The durable answers are the same ones that show up across every implementation — disposable containers for isolation, a warm pool for latency, an allowlist plus prompt guardrails for defense in depth, and a backend abstraction so you can run locally or in the cloud without rewriting the agent.&lt;/p&gt;

&lt;p&gt;I used exactly this approach to add a code-execution data agent to an internal analytics application, letting it answer open-ended questions with custom charts while staying safely contained. The specifics differ from project to project, but the principles travel — and they're worth internalizing before you wire a language model up to a Python interpreter.&lt;/p&gt;

&lt;h2&gt;
  
  
  References and further reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/vndee/llm-sandbox" rel="noopener noreferrer"&gt;llm-sandbox&lt;/a&gt; — lightweight Python sandbox runtime (Docker / Podman / Kubernetes) · &lt;a href="https://vndee.github.io/llm-sandbox/" rel="noopener noreferrer"&gt;docs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://e2b.dev/" rel="noopener noreferrer"&gt;E2B&lt;/a&gt; — Firecracker-backed sandboxes for AI agents · &lt;a href="https://e2b.dev/docs" rel="noopener noreferrer"&gt;docs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://firecracker-microvm.github.io/" rel="noopener noreferrer"&gt;Firecracker&lt;/a&gt; — lightweight microVMs (the AWS Lambda / E2B substrate)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://gvisor.dev/" rel="noopener noreferrer"&gt;gVisor&lt;/a&gt; — a user-space kernel for stronger container isolation&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pyodide.org/" rel="noopener noreferrer"&gt;Pyodide&lt;/a&gt; — CPython compiled to WebAssembly&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/zopefoundation/RestrictedPython" rel="noopener noreferrer"&gt;RestrictedPython&lt;/a&gt; — in-process Python restriction (a speed bump, not a wall)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/anthropic-experimental/sandbox-runtime" rel="noopener noreferrer"&gt;Anthropic sandbox-runtime&lt;/a&gt; — OS-level filesystem/network restriction without a container&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.anthropic.com/en/docs/agents-and-tools/tool-use/code-execution-tool" rel="noopener noreferrer"&gt;Anthropic code execution tool&lt;/a&gt; and &lt;a href="https://platform.openai.com/docs/assistants/tools/code-interpreter" rel="noopener noreferrer"&gt;OpenAI Code Interpreter&lt;/a&gt; — hosted, provider-run sandboxes&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>python</category>
      <category>security</category>
    </item>
  </channel>
</rss>
