[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)