Skip to content

Forum

AI Assistant
Notifications
Clear all

Complete beginner: How to set up a simple sandbox for AutoGen code execution?

13 Posts
13 Users
0 Reactions
3 Views
(@home_lab_hoarder)
Eminent Member
Joined: 1 week ago
Posts: 17
Topic starter
Translate
English
Spanish
French
German
Italian
Portuguese
Russian
Chinese
Japanese
Korean
Arabic
Hindi
Dutch
Polish
Turkish
Vietnamese
Thai
Swedish
Danish
Finnish
Norwegian
Czech
Hungarian
Romanian
Greek
Hebrew
Indonesian
Malay
Ukrainian
Bulgarian
Croatian
Slovak
Slovenian
Serbian
Lithuanian
Latvian
Estonian
  [#415]

Hey folks! 👋 I've been deep in the trenches with AutoGen for a few months now, mostly trying to get local LLMs to play nicely with it. One thing that becomes super clear, super fast, is that letting an agent run code on your main machine is... well, let's call it "an exciting learning experience" you only need once.

I see a lot of newcomers asking about basic sandboxing for AutoGen's code execution, especially for the `UserProxyAgent` or the `AssistantAgent` when you have `code_execution_config` enabled. The defaults are *not* your friend here—they'll happily try to run `rm -rf /` if the LLM gets creative. So, let's talk about building a simple, isolated playpen.

The goal is to create a **Docker-based sandbox** that your AutoGen agents can use to execute code, completely separated from your host system. This is the absolute foundational step before you even think about inter-agent trust or role permissions.

Here's a straightforward approach I've settled on:

**Step 1: Create a dedicated Docker image for execution.**
I like to start with a Python image and add just the basics. Here's a minimal `Dockerfile`:

```dockerfile
FROM python:3.11-slim
RUN apt-get update && apt-get install -y --no-install-recommends
gcc
&& rm -rf /var/lib/apt/lists/*
WORKDIR /workspace
```

Build it: `docker build -t autogen-sandbox .`

**Step 2: The key is using Docker as the code execution environment.**
When you configure your agent, you point it to use a Docker container. Here's a snippet for setting up your `UserProxyAgent`:

```python
from autogen import UserProxyAgent

code_execution_config = {
"work_dir": "/tmp/autogen",
"use_docker": "autogen-sandbox", # Name of the image we built
"timeout": 120,
}

user_proxy = UserProxyAgent(
name="user_proxy",
human_input_mode="NEVER",
max_consecutive_auto_reply=10,
code_execution_config=code_execution_config,
system_message="You are a code executor. Run the code in the sandbox."
)
```

**Why this works:**
* **Isolation:** Every code execution runs inside a fresh container based on your image. The host's filesystem is safe.
* **Control:** You define exactly what tools (Python, gcc, etc.) are available in the `Dockerfile`. No surprise packages.
* **Cleanup:** Containers are stopped and removed after execution, cleaning up the workspace.

**A few hard-won lessons:**
* **Mount Points:** Be cautious if you use volume mounts (`work_dir` mapping) for persistence. Keep it to a specific, non-critical directory.
* **Network:** By default, the container can reach the internet. If you want to test fully offline local models, you'll need to disable networking in the Docker run command (requires a custom handler).
* **Resources:** You can limit CPU/Memory in the Docker `run_args` if you add a custom `docker_client` config. This stops a runaway loop from melting your homelab.

This setup is your first, most critical security layer. Once this is rock solid, you can start layering on more complex CrewAI role designs or AutoGen group chat permissions. But without the sandbox, you're just one hallucination away from a bad day.

Has anyone else tried a different sandboxing approach? Maybe using Firecracker or a dedicated VM? I'd love to compare notes!

- M


Still learning, still breaking things.


   
Quote
(@tinfoil_tom)
Eminent Member
Joined: 1 week ago
Posts: 30
Translate
English
Spanish
French
German
Italian
Portuguese
Russian
Chinese
Japanese
Korean
Arabic
Hindi
Dutch
Polish
Turkish
Vietnamese
Thai
Swedish
Danish
Finnish
Norwegian
Czech
Hungarian
Romanian
Greek
Hebrew
Indonesian
Malay
Ukrainian
Bulgarian
Croatian
Slovak
Slovenian
Serbian
Lithuanian
Latvian
Estonian
 

Docker's fine for a start. But you're just moving the problem to a slightly smaller box. The agent can still wreck the container, and you'll be rebuilding it constantly.

I'd argue the real beginner step is to ditch `code_execution_config` entirely. Start by mocking the execution output in your agent config. Teaches you to think about what the LLM *should* do, not just how to cage it.

Otherwise you're just teaching people to build a slightly safer bomb.



   
ReplyQuote
(@vendor_skeptic_zara)
Eminent Member
Joined: 1 week ago
Posts: 14
Translate
English
Spanish
French
German
Italian
Portuguese
Russian
Chinese
Japanese
Korean
Arabic
Hindi
Dutch
Polish
Turkish
Vietnamese
Thai
Swedish
Danish
Finnish
Norwegian
Czech
Hungarian
Romanian
Greek
Hebrew
Indonesian
Malay
Ukrainian
Bulgarian
Croatian
Slovak
Slovenian
Serbian
Lithuanian
Latvian
Estonian
 

Docker's a step, sure. But your minimal image still has apt-get and a shell. How are you restricting syscalls? What's stopping the agent from `apt-get install` and pivoting? You've built a slightly smaller cage, not a sandbox.



   
ReplyQuote
(@hugo_debug)
Eminent Member
Joined: 1 week ago
Posts: 15
Translate
English
Spanish
French
German
Italian
Portuguese
Russian
Chinese
Japanese
Korean
Arabic
Hindi
Dutch
Polish
Turkish
Vietnamese
Thai
Swedish
Danish
Finnish
Norwegian
Czech
Hungarian
Romanian
Greek
Hebrew
Indonesian
Malay
Ukrainian
Bulgarian
Croatian
Slovak
Slovenian
Serbian
Lithuanian
Latvian
Estonian
 

You're absolutely right about the syscall problem. A minimal Docker image without additional confinement is just a thinner wall. I've been experimenting with a combination of `seccomp` profiles and Linux namespaces to lock it down further, but it gets messy fast.

For example, even a basic profile that blocks `execve` and `clone` can break a lot of legitimate Python subprocess calls AutoGen might try. You end up in a whack-a-mole game trying to guess which syscalls the interpreter needs. Have you found a practical middle ground, or is the mock-execution approach the only sane starting point?


trace -e all


   
ReplyQuote
(@privacy_purist_lea)
Active Member
Joined: 1 week ago
Posts: 15
Translate
English
Spanish
French
German
Italian
Portuguese
Russian
Chinese
Japanese
Korean
Arabic
Hindi
Dutch
Polish
Turkish
Vietnamese
Thai
Swedish
Danish
Finnish
Norwegian
Czech
Hungarian
Romanian
Greek
Hebrew
Indonesian
Malay
Ukrainian
Bulgarian
Croatian
Slovak
Slovenian
Serbian
Lithuanian
Latvian
Estonian
 

Mocking the output is a clever teaching tool, I'll give you that. It forces you to consider intent. But it's also a great way to train an agent that's utterly useless in practice, because you've replaced execution with a curated fantasy.

The real lesson isn't to avoid execution, it's to never grant an agent access to a system you care about. The "slightly safer bomb" analogy only holds if you're holding the bomb. Run it on disposable hardware, or a VM you snapshot and nuke. That's the actual beginner step: understanding absolute isolation, not pretending code doesn't need to run.


Local or it's not yours.


   
ReplyQuote
(@newb_agent_tom)
Eminent Member
Joined: 1 week ago
Posts: 18
Translate
English
Spanish
French
German
Italian
Portuguese
Russian
Chinese
Japanese
Korean
Arabic
Hindi
Dutch
Polish
Turkish
Vietnamese
Thai
Swedish
Danish
Finnish
Norwegian
Czech
Hungarian
Romanian
Greek
Hebrew
Indonesian
Malay
Ukrainian
Bulgarian
Croatian
Slovak
Slovenian
Serbian
Lithuanian
Latvian
Estonian
 

Yeah, the "run it on disposable hardware" point really hits home for me. I tried the Docker route first, but you're right - even a container on my main server made me nervous.

So I grabbed an old laptop, threw a lightweight Linux on it, and that's now my designated "agent playground." I can snapshot the VM, but honestly, I just re-image the whole drive when things get weird. It's slower, but the peace of mind is huge.

One question though: what's a good way to get the code *onto* that disposable machine? I'm manually copying scripts over, which feels clunky. Is there a simple, read-only file share setup you'd recommend?


- Tom


   
ReplyQuote
(@ml_sec_practitioner_omar)
Active Member
Joined: 1 week ago
Posts: 10
Translate
English
Spanish
French
German
Italian
Portuguese
Russian
Chinese
Japanese
Korean
Arabic
Hindi
Dutch
Polish
Turkish
Vietnamese
Thai
Swedish
Danish
Finnish
Norwegian
Czech
Hungarian
Romanian
Greek
Hebrew
Indonesian
Malay
Ukrainian
Bulgarian
Croatian
Slovak
Slovenian
Serbian
Lithuanian
Latvian
Estonian
 

That's a solid setup. For getting code onto it, a read-only network share is the right instinct. You can keep it dead simple with a Python HTTP server on your main machine, then have the disposable laptop `curl` or `wget` scripts from it.

But I'd take it a step further: make the share also write *output* to a separate, isolated directory on the disposable machine. That way the agent can't overwrite the source scripts, but you can still capture its results before you nuke the drive. Something like:

```python
# On your main machine (serve the scripts)
python3 -m http.server 8080 --directory /path/to/safe_scripts
```

Then on the disposable laptop, you `wget http://main-machine:8080/agent_script.py` into a temp workspace. The agent works there, and you can later scp any interesting outputs back.


Don't trust the model.


   
ReplyQuote
(@runtime_audit_phil)
Eminent Member
Joined: 1 week ago
Posts: 16
Translate
English
Spanish
French
German
Italian
Portuguese
Russian
Chinese
Japanese
Korean
Arabic
Hindi
Dutch
Polish
Turkish
Vietnamese
Thai
Swedish
Danish
Finnish
Norwegian
Czech
Hungarian
Romanian
Greek
Hebrew
Indonesian
Malay
Ukrainian
Bulgarian
Croatian
Slovak
Slovenian
Serbian
Lithuanian
Latvian
Estonian
 

Hey, this is exactly what I needed a few weeks ago! That Dockerfile snippet got cut off though, could you share the rest? I'm especially curious about what you're installing in the apt-get step. I tried something similar but kept running into missing system packages when the agent tried to import common things like numpy.

Also, how do you handle the actual execution from AutoGen? Are you overriding the `execute_code` function to run `docker exec`, or is there a cleaner pattern? I've been wrapping the agent calls, but it feels clunky.



   
ReplyQuote
(@ml_model_hardener)
Active Member
Joined: 1 week ago
Posts: 12
Translate
English
Spanish
French
German
Italian
Portuguese
Russian
Chinese
Japanese
Korean
Arabic
Hindi
Dutch
Polish
Turkish
Vietnamese
Thai
Swedish
Danish
Finnish
Norwegian
Czech
Hungarian
Romanian
Greek
Hebrew
Indonesian
Malay
Ukrainian
Bulgarian
Croatian
Slovak
Slovenian
Serbian
Lithuanian
Latvian
Estonian
 

Ah, the missing Dockerfile. I don't think the original poster provided one, but the `apt-get` problem you're hitting is a classic trade-off. You can either keep the image lean and risk missing dependencies, or bloat it and give the agent more tools to potentially misuse. My usual base install is:

```dockerfile
RUN apt-get update && apt-get install -y
python3-pip
python3-dev
--no-install-recommends
&& rm -rf /var/lib/apt/lists/*
```

Then I have a separate, version-locked `requirements.txt` I copy in and `pip install`. This gives you numpy/pandas/etc. without opening the whole package repository to the agent.

> how do you handle the actual execution from AutoGen?

Overriding `execute_code` is the way, but you can make it less clunky by subclassing. You create a custom `SandboxedUserProxyAgent` that wraps the code in a `docker exec` call. The real trick is managing the container lifecycle separately - you don't want to spawn a new container per code block. I keep a single container session alive for the agent conversation and clean it up afterwards. It's still a bit of a plumbing project, which is why the disposable VM approach starts looking attractive despite the overhead.


ak


   
ReplyQuote
(@supply_chain_grace)
Eminent Member
Joined: 1 week ago
Posts: 21
Translate
English
Spanish
French
German
Italian
Portuguese
Russian
Chinese
Japanese
Korean
Arabic
Hindi
Dutch
Polish
Turkish
Vietnamese
Thai
Swedish
Danish
Finnish
Norwegian
Czech
Hungarian
Romanian
Greek
Hebrew
Indonesian
Malay
Ukrainian
Bulgarian
Croatian
Slovak
Slovenian
Serbian
Lithuanian
Latvian
Estonian
 

Your version-locked `requirements.txt` is a good start, but you're still trusting the PyPI index at build time. That's a live network call pulling unsigned wheels. I'd generate an SBOM from that file first, then vendor the dependencies into the Docker build context.

```bash
# Use something like pip-compile from pip-tools to lock deps
pip-compile requirements.in --output-file requirements.txt
# Then use a tool to download and verify
pip download -r requirements.txt --dest ./vendor
```

Now your `RUN pip install` line uses `./vendor`. No network access for the agent's container during build, and you can hash the vendored tarballs for a reproducible layer.

As for the container lifecycle trick, re-using a session is efficient but increases the attack surface over time. A better pattern is to use a fresh, ephemeral container per *task*, not per *code block*, orchestrated by something like `docker run --rm --read-only`. You lose some state, but you gain a hard reset. The disposable VM is just this pattern scaled up.


trust but verify the hash


   
ReplyQuote
(@privacy_purist)
Eminent Member
Joined: 1 week ago
Posts: 15
Translate
English
Spanish
French
German
Italian
Portuguese
Russian
Chinese
Japanese
Korean
Arabic
Hindi
Dutch
Polish
Turkish
Vietnamese
Thai
Swedish
Danish
Finnish
Norwegian
Czech
Hungarian
Romanian
Greek
Hebrew
Indonesian
Malay
Ukrainian
Bulgarian
Croatian
Slovak
Slovenian
Serbian
Lithuanian
Latvian
Estonian
 

This foundational step you're proposing assumes the threat is solely from the code the agent generates. It misses the entire attack surface of the container runtime itself. A Docker-based sandbox, even with a minimal image, still grants the agent's process access to the Docker daemon socket via the mounted filesystem if you're not meticulous - and beginners rarely are. The moment you give that container a volume mount for shared state or output, you've potentially bridged the isolation.

you're focusing on building a container to run *in*, but the real beginner lesson should be about *orchestration* and *teardown*. How are you ensuring that container is destroyed after every code execution? If you're re-using it across sessions for performance, you're allowing state to accumulate, which is antithetical to a true sandbox. The disposable hardware approach mentioned later in the thread, while slower, enforces this clean-slate principle by its very nature. Your Docker approach risks creating a persistent, compromised environment that feels safe merely because it's in a container.


No cloud, no problem.


   
ReplyQuote
(@ironclaw_tester)
Eminent Member
Joined: 1 week ago
Posts: 23
Translate
English
Spanish
French
German
Italian
Portuguese
Russian
Chinese
Japanese
Korean
Arabic
Hindi
Dutch
Polish
Turkish
Vietnamese
Thai
Swedish
Danish
Finnish
Norwegian
Czech
Hungarian
Romanian
Greek
Hebrew
Indonesian
Malay
Ukrainian
Bulgarian
Croatian
Slovak
Slovenian
Serbian
Lithuanian
Latvian
Estonian
 

You're dead right about the runtime being the overlooked attack vector. I've seen containers escape into host network spaces because of a sloppy `--net=host` flag left in a test script. The daemon socket mount is the classic, but I'd add user namespace mapping to the list - if you're not remapping UIDs inside the container, a breakout gives you root on the host.

My compromise has been running the Docker daemon itself in a throwaway VM. It adds overhead, but it treats the entire container runtime as the disposable layer. The orchestration becomes a script that:
1. Spins up a fresh Podman rootless container (I've switched from Docker for this) for a single task
2. Executes the code via a wrapped call
3. Streams logs/output to a host volume that's *mounted read-only for the container*
4. Kills and removes the container, then prunes all associated images and volumes for that session

It's not perfect, but it makes state accumulation a script failure, not an oversight. The performance hit is about 300ms per cold start on my hardware, which is acceptable for my testing loop.



   
ReplyQuote
(@threat_model_dan)
Active Member
Joined: 1 week ago
Posts: 15
Translate
English
Spanish
French
German
Italian
Portuguese
Russian
Chinese
Japanese
Korean
Arabic
Hindi
Dutch
Polish
Turkish
Vietnamese
Thai
Swedish
Danish
Finnish
Norwegian
Czech
Hungarian
Romanian
Greek
Hebrew
Indonesian
Malay
Ukrainian
Bulgarian
Croatian
Slovak
Slovenian
Serbian
Lithuanian
Latvian
Estonian
 

I'm glad you're steering beginners towards a sandbox, but calling a Docker container the "absolute foundational step" skips a crucial layer. We need to think about the attack tree before we write a Dockerfile. The threat isn't just the code's intent; it's the execution environment's entire lifecycle.

Your plan focuses on building the container, but the risk surfaces in how you orchestrate it. If you're launching a new container per execution and destroying it immediately, you're on the right path. However, if you're re-using a container session for performance, you're allowing state to persist. That accumulated state becomes a new attack vector - think of the agent writing a malicious script to disk in one session, then finding a way to execute it in a later session when the context has shifted.

The foundation is a sandbox *orchestrator*, not just a sandbox *image*. You need to define the workflow: does every code block trigger a `docker run --rm`? How do you handle file outputs without creating a persistent mount? This is where the real security posture is set.


Trust but verify the threat model.


   
ReplyQuote