Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/pydantic/monty/llms.txt

Use this file to discover all available pages before exploring further.

Sandbox Isolation

Monty is designed to safely execute untrusted code by providing complete isolation from the host environment. The interpreter implements a strict sandbox that prevents code from accessing or modifying the host system.

What’s Blocked

Monty blocks all direct access to:
  • Filesystem: No direct file I/O operations
  • Environment Variables: Cannot read or modify environment variables
  • Network Access: No sockets or HTTP requests
  • Subprocess Execution: Cannot spawn processes or run shell commands
  • Import System: Cannot import modules with side effects or use __import__
  • Third-party Libraries: No external Python packages
  • Most Standard Library: Only a minimal subset is available

What’s Allowed

Monty provides controlled access through:
  • External Functions: Only functions explicitly provided by the host
  • OS Operations: Filesystem and network operations handled via host callbacks
  • Limited Standard Library: sys, os, typing, asyncio, re modules
  • Safe Operations: Pure computation, data structures, control flow
import pydantic_monty

# This code is safely sandboxed
code = """
result = x * 2
if result > 10:
    result = fetch_data()  # Only runs if you provide fetch_data
result
"""

m = pydantic_monty.Monty(code, inputs=['x'])

# You control what external functions are available
result = m.run(
    inputs={'x': 7},
    external_functions={'fetch_data': lambda: 'safe data'}
)
print(result)  # 'safe data'

Security Guarantees

Complete Host Isolation

Monty never uses CPython’s exec() or any FFI to Python. It’s a completely independent interpreter written in Rust that provides:
  • No filesystem access without explicit host callbacks
  • No environment variable access
  • No network access without explicit host callbacks
  • No subprocess execution
  • No access to system resources

Memory Safety

Monty is written in Rust without unsafe code (except in carefully reviewed FFI boundaries for Python/JavaScript bindings). This provides:
  • No buffer overflows
  • No use-after-free errors
  • No null pointer dereferences
  • Safe memory management with reference counting

Resource Limits

Monty enforces configurable limits to prevent denial-of-service attacks:
  • Memory limits: Cap maximum heap usage
  • Execution time: Timeout after specified duration
  • Allocation count: Limit number of heap allocations
  • Recursion depth: Prevent stack overflow (default: 1000)
See the Resource Limits page for detailed configuration options.

Controlled External Access

External Functions

All host interaction happens through external functions that you explicitly provide:
import pydantic_monty

code = "fetch(url)"
m = pydantic_monty.Monty(code, inputs=['url'])

# You control EXACTLY what the code can access
def safe_fetch(url: str) -> str:
    # Validate URL, check whitelist, add authentication, etc.
    if not url.startswith('https://api.example.com/'):
        raise ValueError('URL not allowed')
    # Your actual fetch logic here
    return "safe data"

result = m.run(
    inputs={'url': 'https://api.example.com/data'},
    external_functions={'fetch': safe_fetch}
)

OS Operations

Filesystem and network operations are never performed directly. Instead, they trigger callbacks that you handle:
# When code calls os.path.exists(path), Monty pauses
# and returns control to you via start()/resume()

progress = m.start(inputs={'path': '/some/path'})

if isinstance(progress, pydantic_monty.OsSnapshot):
    # You decide how to handle the OS operation
    if progress.function == 'path_exists':
        path = progress.args[0]
        # Apply your security checks
        result = your_safe_path_check(path)
        progress = progress.resume(return_value=result)

Deserialization Safety

Only deserialize (load()) snapshot data from trusted sources. Loading untrusted snapshot data could:
  • Restore malicious execution state
  • Bypass resource limits
  • Execute arbitrary code when resumed
Always validate the source of serialized data before calling:
  • Monty.load(bytes)
  • FunctionSnapshot.load(bytes)
  • RunProgress.load(bytes)

Threat Model

Monty is designed to protect against:

Protected Against

  • Code Injection: Untrusted Python code execution
  • Resource Exhaustion: Memory bombs, infinite loops
  • Information Disclosure: No access to host environment
  • Path Traversal: No filesystem access without your control
  • Regex DoS: Controlled through execution limits
  • Import Abuse: Only safe minimal standard library available

Out of Scope

  • Timing Attacks: Execution timing is observable
  • Deserialization Attacks: Don’t load snapshots from untrusted sources
  • Host Function Vulnerabilities: Security of external functions is your responsibility

Why Monty?

Traditional sandboxing approaches have significant limitations:
SolutionStart LatencySecurityComplexity
Monty0.06msStrictEasy
Docker195msGoodIntermediate
Pyodide/WASM2800msPoorIntermediate
Subprocess30msNoneEasy
Direct exec()0.1msNoneEasy
Monty provides strict security with microsecond startup time and no external dependencies.

Best Practices

1

Validate All Inputs

Validate and sanitize all input values before passing them to Monty.
2

Whitelist External Functions

Only provide the minimum set of external functions needed. Apply strict validation within each function.
3

Set Resource Limits

Always configure appropriate resource limits for your use case to prevent DoS.
4

Handle OS Callbacks Safely

When using start()/resume(), apply security checks in your OS operation handlers.
5

Trust Snapshot Sources

Only deserialize snapshots from trusted sources that you control.

Build docs developers (and LLMs) love