[HN Gopher] Sandboxing Untrusted Python
___________________________________________________________________
Sandboxing Untrusted Python
Author : mavdol04
Score : 28 points
Date : 2026-01-05 16:11 UTC (6 hours ago)
(HTM) web link (gist.github.com)
(TXT) w3m dump (gist.github.com)
| petters wrote:
| > Older alternatives like sandbox-2 exist, but they provide
| isolation near the OS level, not the language level. At that
| point we might as well use Docker or VMs.
|
| No,no, Docker is not a sandbox for untrusted code.
| mavdol04 wrote:
| You're right, Docker isn't a sandbox for untrusted code. I
| mentioned it because I've seen teams default to using it for
| isolating their agents on larger servers. So I made sure to
| clarify in the article that it's not secure for that purpose.
| s_ting765 wrote:
| Docker provides some host isolation which can be used
| effectively as a sandbox. It's not designed for security (and
| it does have some reasonable defaults) but it does give you
| options to layer on security modules like apparmor and seccomp
| very easily.
| ashishb wrote:
| Show me how you will escape a docker sandbox.
| staticassertion wrote:
| Exploit the Linux kernel underneath it (not the only way,
| just the obvious one). Docker is a security boundary but it
| is not suitable for "I'm running arbitrary code".
|
| That is to say, Docker is typically a security win because
| you get things like seccomp and user/DAC isolation "for
| free". That's great. That's a win. Typically exploitation
| requires a way to get execution in the environment plus a
| privilege escalation. The combination of those two things may
| be considered sufficient.
|
| It is not sufficient for "I'm explicitly giving an attacker
| execution rights in this environment" because you remove the
| cost of "get execution in the environment" and the full
| burden is on the kernel, which is not very expensive to
| exploit.
| neoCrimeLabs wrote:
| This is a well understood and well documented subject. Do
| your own research.
|
| Start here to help give you ideas for what to research:
|
| https://linuxsecurity.com/features/what-is-a-container-
| escap...
| neoCrimeLabs wrote:
| It depends on your threat model, but generally speaking would
| not trust default container runtimes for a true sandbox.
|
| The kata-containers [1] runtime takes a container and runs it
| as a virtual host. It works with Docker, podman, k8s, etc.
|
| It's a way to get the convenience of a container, but benefits
| of a virtual host.
|
| This is not do-all-end-all, (there are more options), but this
| is a convenient one that is better than typical containers.
|
| [1] - https://katacontainers.io/
| ptspts wrote:
| Neither the article nor the README explains how it works.
|
| How does it work? Which WASM euntime does it use? Does it use a
| Python jnterpreter compiled to WASM?
| chaboud wrote:
| There's a link to the author's work here:
|
| https://github.com/mavdol/capsule
|
| (From the article)
|
| Appears to be CPython running inside of wasmtime
| mavdol04 wrote:
| yep, and to be specific, it leverages the WASM Component
| Model and uses componentize-py to bundle the user's script
| bArray wrote:
| See the linked project at the end:
| https://github.com/mavdol/capsule
| maxloh wrote:
| Edit: never mind, I read it wrong.
|
| ---
|
| That is not save at all. You could always hijack builtin
| functions within untrusted code. def
| untrusted_function(): original_map = map
| def noisy_map(func, *iterables): print(f"--- Log:
| map() called on {func.__name__} ---") return
| original_map(func, *iterables) globals()['map']
| = noisy_map
| mavdol04 wrote:
| Actually, since it runs inside a WASM sandbox, even if the
| untrusted code overwrites built-ins like map or modifies
| globals(), it only affects its own isolated memory space. It
| cannot escape the WASM container or affect the host system
| incognito124 wrote:
| Sharing my friend's startup for sandboxed code execution:
|
| https://judge0.com/
| bArray wrote:
| I have been thinking about this myself, but am still not
| convinced about how to run untrusted Python code. I'm not
| convinced that the right solution is to run the code as WebASM
| [1].
|
| I have been looking towards some kind of quick-start qemu option
| as a possibility, but the project will take a while.
|
| [1] https://github.com/mavdol/capsule
| mavdol04 wrote:
| I see what you mean, but i think there is room for both
| approaches.
|
| If we want to isolate untrusted code at a very fine-grained
| level (like just a specific function), VMs can feel a bit heavy
| due to the overhead, complexity etc
| amluto wrote:
| The example is: @task(name="analyze_data",
| compute="MEDIUM", ram="512MB", timeout="30s", max_retries=1)
| def analyze_data(dataset: list) -> dict: # Your code
| runs safely in a Wasm sandbox return {"processed":
| len(dataset), "status": "complete"}
|
| This is fundamentally awkward in a language with as absurdly
| flexible a type system as Python. What if that list parameter
| contains objects that implement __getattr__? What if the output
| dict has an overridden __getattr__?
|
| Even defining semantics seems awkward, especially if one wants
| those semantics to simultaneously make sense and have any sort of
| clear security properties.
|
| edit: a quick look at the source suggests that the output is
| deserialized JSON regardless of what the type signature says.
| That's certainly one solution.
| mavdol04 wrote:
| Yep, exactly.
|
| We stick to JSON to make sure we pass data, not behavior. It
| avoids all that complexity.
| loeg wrote:
| > Python doesn't have a built-in way to run untrusted code
| safely. Multiple attempts have been made, but none really
| succeeded.
|
| Long, long ago, there was "repy"[1][2]. (This is definitely
| included in the "none succeeded" bucket, FWIW.)
|
| [1]: https://github.com/SeattleTestbed/repy_v2
|
| [2]: https://dl.acm.org/doi/10.1145/1866307.1866332
| staticassertion wrote:
| Seems fine to me. I think you're going to take a huge performance
| hit by putting CPython into wasm. gVisor is mentioned as having a
| performance penalty but I'm extremely doubtful of that penalty
| (which is really on IO, which I expect to not be a huge deal for
| these workloads) being anywhere near the penalty of wasm.
___________________________________________________________________
(page generated 2026-01-05 23:01 UTC)