Both the code execution function and tool require the ability to run gVisor for secure sandboxing. Your Open WebUI instance needs to be set up to handle this.
This utility should work wherever gVisor works, i.e. x86_64/AMD64 and ARM64 processors.
gVisor only runs on Linux. However, if you are running on Windows or OS X, you can use Docker Desktop or similar container runtime which will automatically run a Linux virtual machine in which the container will actually run.
If you run Open WebUI inside a container, you will need to adjust its settings to grant gVisor the necessary privileges to work.
You can do this the easy way (good for single-user setups) by running Open WebUI in privileged mode, or the hard way to change the minimal set of things that still allows sandboxing to be possible.
- On Docker: Add
--privileged=truetodocker run. - On Kubernetes: Set
spec.securityContext.privilegedtotrue.
This will remove all security measures from the Open WebUI container. From a security perspective, this is roughly equivalent to running the Open WebUI server as root outside of a container on the host machine. However, code running as part of this code execution function/tool will still run in a secure gVisor sandbox and cannot impact the host or the Open WebUI container.
This is adequate for single-user setups not exposed to the outside Internet, while still providing strong security against LLMs generating malicious code. However, if you are running a multi-user setup, or if you do not fully trust Open WebUI's code, or the Open WebUI server's HTTP port is exposed to the outside Internet, you may want to harden it further. If so, don't set the privileged setting, and read on to the hard way instead.
The below is the minimal subset of changes that --privileged=true does that is still necessary for sandboxing to work.
- Remove the container's default system call filter (
seccomp):- On Docker: Add
--security-opt=seccomp=unconfinedtodocker run. - On Kubernetes: Set
spec.securityContext.seccompProfile.typetoUnconfined. - If you would like to use a specific seccomp profile rather than running without system call filtering, you can use Dangerzone's seccomp profile which is tuned to allow gVisor system calls through.
- Why: By default, some system calls are blocked by the container runtime's default system call filter. The use of these system calls enhances security when running subcontainers, but they are blocked by default because most containerized applications don't ever need to create subcontainers. gVisor, however, does. Specifically, gVisor needs to:
- ... create isolated namespaces using the
unshare(2)system call - ... create isolated chroots via the
mount(2)system call - ...
pivot_rootinto these roots via thepivot_root(2)system call - ... trace sandboxed processes to block their system calls from reaching the host Linux kernel using the
ptrace(2)system call
- ... create isolated namespaces using the
- On Docker: Add
- Mount
cgroupfsas writable:- On Docker: Add
--mount=type=bind,source=/sys/fs/cgroup,target=/sys/fs/cgroup,readonly=falsetodocker run. - On Kubernetes: Add a
hostPathvolume withpathset to/sys/fs/cgroup, then mount it in your container'svolumeMountswith optionsmountPathset to/sys/fs/cgroupandreadOnlyset tofalse. - Why: This is needed so that gVisor can create child cgroups, necessary to enforce per-sandbox resource usage limits.
- On Docker: Add
- Set the
container_engine_tSELinux label:- On Docker: Add
--security-opt=label=type:container_engine_ttodocker run. - On Kubernetes: Set
spec.securityContext.seLinuxOptions.typetocontainer_engine_t. - Why: The default SELinux label for containers (
container_t) does not allow the creation of namespaces, which gVisor requires for additional isolation . Thecontainer_engine_tlabel allows this. - If you don't have SELinux enabled, this setting does nothing and may be omitted.
- On Docker: Add
To verify that your setup works, you can run the tool in self-test mode using run_code.py's --use-sample-code flag.
For example, here is a Docker invocation running the run_code.py script inside the Open WebUI container image with the above flags:
$ git clone https://github.com/EtiennePerot/open-webui-code-execution && \
docker run --rm \
--security-opt=seccomp=unconfined \
--security-opt=label=type:container_engine_t \
--mount=type=bind,source="$(pwd)/open-webui-code-execution",target=/selftest \
ghcr.io/open-webui/open-webui:main \
python3 /selftest/open-webui/tools/run_code.py --self_testIf all goes well, you should see:
⏳ Running self-test: simple_python
✔ Self-test simple_python passed.
⏳ Running self-test: simple_bash
✔ Self-test simple_bash passed.
⏳ Running self-test: bad_syntax_python
✔ Self-test bad_syntax_python passed.
⏳ Running self-test: bad_syntax_bash
✔ Self-test bad_syntax_bash passed.
⏳ Running self-test: long_running_code
✔ Self-test long_running_code passed.
⏳ Running self-test: ram_hog
✔ Self-test ram_hog passed.
✅ All self-tests passed, good go to!
If you get an error, try to add the --debug flag at the very end of this command (i.e. as a run_code.py flag) for extra information, then file a bug.
The code execution tool and function have the following valves available:
- Networking allowed: Whether or not to let sandboxed code have access to the network.
- Note: If you are running Open WebUI on a LAN, this will expose your LAN.
- Max runtime: The maximum number of time (in seconds) that sandboxed code will be allowed to run.
- Useful for multi-user setups to avoid denial-of-service, and to avoid running LLM-generated code that contains infinite loops forever.
- Max RAM: The maximum amount of memory the sandboxed code will be allowed to use, in megabytes.
- Useful for multi-user setups to avoid denial-of-service.
- Auto Install: Whether to automatically download and install gVisor if not present in the container.
- If not installed, gVisor will be automatically installed in
/tmp. - Useful for convenience, but should be disabled for production setups.
- If not installed, gVisor will be automatically installed in
- Debug: Whether to produce debug logs.
- This should never be enabled in production setups as it produces a lot of information that isn't necessary for regular use.
- When filing a bug report, please enable this valve, then reproduce the issue in a new chat session, then download the chat log (triple-dot menu →
Download→Export chat (.json)) and attach it to the bug report.
To avoid the tool having to download and install gVisor on first run, you can pre-install gVisor in your Open WebUI container image or environment. Follow the gVisor installation guide. At the end, the command runsc --version (run within the Open WebUI container if you are running it in a container) should work and return the gVisor version you installed.
TODO: Add environment variables that take precedence over valves to allow multi-user setups.