Run untrusted code with Restricted Functions
This guide page documents Restricted Functions, which can be used to safely execute untrusted code in Modal Functions.
Create a Restricted Function
To create a Restricted Function, set restrict_modal_access=True in the Function definition:
When restrict_modal_access is enabled, the Function cannot
- access Modal resources (Queues, Dicts, etc.)
- call other Functions
- access Modal’s internal APIs
Sandboxes offer an alternative interface for untrusted code
Modal provides two primitives for running untrusted code: Restricted Functions and Sandboxes. While both can be used for running untrusted code, they provide different interfaces: Sandboxes provide a process interface, while Restricted Functions provide a function-calling interface. Process interfaces are especially useful for stateful, multi-stage communication, while function-calling interfaces are especially useful for stateless, input/output communication.
These differences are summarized in the table below.
| Feature | Restricted Function | Sandbox |
|---|---|---|
| State | Stateless | Stateful |
| Interface | Function-like | Container-like |
| Setup | Simple decorator | Requires explicit creation/termination |
| Use case | Quick, isolated code execution | Interactive development, long-running sessions |
Best Practices
When running untrusted code, consider these additional security measures:
- Use
single_use_containers=Trueto ensure each container only handles one request. Containers that get reused could cause information leakage between users.
Note: Prior to v1.3.0, single-use containers were configured by setting max_inputs=1.
- Set appropriate timeouts to prevent long-running operations:
- Consider using
block_network=Trueto prevent the container from making outbound network requests:
- Minimize the App source that’s included in the container
A restricted Modal Function will have read access to its source files in the container, so you’ll want to avoid including anything that would be harmful if exfiltrated by the untrusted process.
If deploying an App from within a larger package, the entire package source may be automatically included by default. A best practice would be to make the untrusted Function part of a standalone App that includes the minimum necessary files to run:
Example: Running LLM-generated Code
Below is a complete example of running code generated by a language model:
This example locks down the container to ensure that the code is safe to execute by:
- Restricting Modal access
- Using a fresh container for each execution
- Setting a timeout
- Blocking network access
- Catching and handling potential errors
Error Handling
When a Restricted Function attempts to access Modal resources, it will raise an AuthError:
The error message will indicate that the operation is not permitted due to restricted Modal access.