Docker Sandbox Runner
Run arbitrary Python in a workflow without letting it poke your host
- r1
- r2
- r3
- r4
- r5
- r6
- log
The name is honest this time
Every custom node you install is arbitrary Python running with your full user-level OS access - that's literally how the LLMVISION malware shipped in 2024. So the natural reaction to "I want to run a Python snippet in my workflow" is a cold sweat. Docker Sandbox Runner is the middle path: it takes your code, ships it into a throwaway-ish Docker container, and hands you the result. No host filesystem access, no network, runs as the nobody user. It's the "I want arbitrary Python, but I also want my host to survive it" node.
The author - posting as LumbarJam - calls it "vibe coded," tested mainly on Arch Linux, with the distro install instructions in the README generated by Gemini rather than exhaustively verified. Read that as the honest warning it is: this is a rough-edged tool for people comfortable with Docker, not a polished ecosystem staple. It's also the one you'd reach for when a workflow needs a few lines of glue math, string processing, or data munging and you'd rather not write a whole custom node.
How it works
It uses the sidecar pattern. The first time you run it, the node pulls python:3.9-slim and starts a persistent container named comfyui-sandbox-worker with tail -f /dev/null as its only job - created with network_mode="none", a memory cap, and running as nobody. Every execution after that is a docker exec into the already-running container, which is why runs feel like milliseconds instead of Docker-boot seconds.
Your script is injected with the preloaded stdlib (math, random, json, re, time), executed via exec(), and guarded by a SIGALRM-based timeout. Whatever you assign to r1 through r6 gets JSON-serialized back to the graph; the container's stdout is captured into the log output for debugging. Clever detail: non-serializable values cross the boundary as opaque string handles, so you can pass a complex object out without it ever being flattened.
The inputs that matter
You'll set one of these, mostly. code is the multiline script - the whole point. timeout (int, default 10, max 60 seconds) is how long the script is allowed to run before SIGALRM kills it. memory_limit (string, default "512m", e.g. 1g) caps container RAM. Both are technically hidden-ish technical knobs; the defaults are fine until they aren't.
The dynamic inputs are where it gets fun. Right-click the node → "+ Add Input (Dynamic)" to add a STRING, INT, FLOAT, BOOLEAN, or wildcard * socket, and it arrives in your script as a variable of that name. This is how you feed the node numbers and strings from elsewhere in the graph. One gotcha grounded in the source: a plain int, float, string, list, or dict arrives as the real value, but a genuinely non-serializable object (say, an IMAGE tensor) arrives as a string handle you can't actually compute on inside the sandbox. Keep the dynamic inputs to JSON-able data.
Install
Real talk about prerequisites: this needs Docker installed and running - Docker Desktop on Windows/macOS (WSL2 required on Windows), or the engine plus your user in the docker group on Linux. Then:
pip install docker
cd path/to/ComfyUI/custom_nodes/
git clone https://github.com/fabioamigo/ComfyUI-DockerSandbox.git
Restart ComfyUI and you'll find Docker Sandbox Runner under Advanced/Scripting. ComfyUI Manager has it too if you'd rather click. The first run pulls python:3.9-slim, so your machine needs network for that one moment - after which the container runs with none. No model files, no torch, no heavy deps; requirements.txt is a single line.
Where people get burned
- "Docker client not initialized": the daemon isn't running, or your user isn't in the
dockergroup. Start Docker, orsudo usermod -aG docker $USERand re-login. - It only has the stdlib.
python:3.9-slimhas no numpy, no PIL, nothing. Don't try to do image math in there. - The container never dies.
comfyui-sandbox-workerkeeps running until you stop it -docker stop comfyui-sandbox-workerwhen you're done, or it idles forever in the background. - The 60-second timeout is a hard ceiling. Long-running logic doesn't fit; that's by design, and it's the main reason this stays a glue node.
One more honest note on security: this isolates your scripts from the host. Installing the node itself still runs host code, so "sandboxed" here means "untrusted snippet in a workflow," not "malicious custom node." It's a real improvement over bare exec(), not a bulletproof vault - but for glue logic it's exactly the right amount of caution.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| code | STRING | — | |
| timeout | INT | 101–60 | — |
| memory_limit | STRING | 512m | — |
Outputs (7)
| Name | Type | Description |
|---|---|---|
| r1 | * | — |
| r2 | * | — |
| r3 | * | — |
| r4 | * | — |
| r5 | * | — |
| r6 | * | — |
| log | STRING | — |