Secret keeps the credential on the host: sandbox code writes a placeholder such as <BOXLITE_SECRET:openai>, and the host proxy substitutes the real value on the way out. SecurityOptions hardens the OS-level sandbox around the VM — jailer, seccomp, resource limits.
Quick Example
Inject a credential (Secret)
The following calls an external API from inside the sandbox: the in-sandbox script only knows the placeholder<BOXLITE_SECRET:demo>, while the real credential <YOUR_API_KEY> stays on the host and is injected by the proxy on egress.
Note:api.example.comabove is a placeholder host with no/v1/pingendpoint, so running this as-is yields a non-zeroexit_code. To verify that injection works, replace bothhostsand the request target with a real, reachable HTTPS service that echoes request headers, and enable network egress. The following is a minimal verification (usinghttpbin.org/headersto echo theAuthorizationheader):
Note: the guest also gets an environment variableBOXLITE_SECRET_TESTKEY=<BOXLITE_SECRET:testkey>injected automatically (the placeholder, not the real value), which you can verify withprintenv BOXLITE_SECRET_TESTKEY. The real value is not found inenv, confirming that the real credential never enters the guest. The variable key is derived from the secret name asBOXLITE_SECRET_{NAME}(uppercased, with non-alphanumeric characters replaced by_).
Tighten isolation (SecurityOptions)
For untrusted workloads, use themaximum() preset to enable all isolation. Note: security must be passed through advanced=AdvancedBoxOptions(...); there is no top-level security= keyword, and AdvancedBoxOptions is exported only under the boxlite.boxlite submodule.
Combining the two (credentials plus isolation)
Node equivalent
In the Node SDK,secrets and security are both direct fields of SimpleBoxOptions (there is no advanced wrapper layer), and SecurityOptions is expressed as a plain object (there is no maximum() static preset).
Parameters and Returns
Secret(name, value, hosts=[], placeholder=None)
Constructor signature: see sdks/python/src/options.rs.
Injection entry point:
BoxOptions(secrets=[Secret(...)]), or passed through via SimpleBox(..., secrets=[...]). Node uses { name, value, hosts?, placeholder? }.
SecurityOptions (Python)
Preset static methods (sdks/python/src/advanced_options.rs):
Note: there is noResource limits set bySecurityOptions.minimum(); the weak-isolation preset is nameddevelopment().
maximum(): max_open_files=1024, max_file_size=1 GiB, max_processes=100 (max_memory/max_cpu_time are left to the VM configuration).
Custom constructor parameters (defaults per the source signature):
Attaching SecurityOptions to a box
AdvancedBoxOptions(security=None, health_check=None): exported only under the boxlite.boxlite submodule; import boxlite; boxlite.AdvancedBoxOptions at the top level is not available.
box.exec(...) return value (ExecResult)
Troubleshooting
AttributeError: module 'boxlite' has no attribute 'AdvancedBoxOptions'
AdvancedBoxOptions lives in the boxlite.boxlite submodule, not the top level.
AttributeError: type object 'SecurityOptions' has no attribute 'minimum'
There is no minimum() preset. Use SecurityOptions.development() for weak isolation, and standard() / maximum() otherwise.
Passing security= at the top level errors out
BoxOptions / SimpleBox do not have a security= keyword. Security options must be wrapped in advanced=AdvancedBoxOptions(security=...). Passing security= directly reports a TypeError due to the unknown keyword argument.
The secret was not injected (the request still contains the raw placeholder / authentication fails)
- The proxy substitutes placeholders in request headers (typically
Authorization), the URL query string, and the request body. It does not touch the URL path — a placeholder there is forwarded literally. hostsmust match the actual outbound target host. For example, requestingapi.openai.comwithhosts=["openai.com"]does not match: use the exact host or the*.openai.comwildcard.- Egress must be HTTPS and pass through the BoxLite proxy; if the sandbox network is fully disabled, injection cannot occur.
seccomp / jailer behave differently on macOS
seccomp_enabled, new_pid_ns, new_net_ns, and chroot are Linux-only. Setting them on macOS does not error — the runtime logs a warn and ignores them. seccomp_enabled takes effect only on Linux (standard()/maximum() already guard it internally with cfg!(target_os = "linux")). On macOS, even setting it to True does not enable seccomp; this is a platform difference. The jailer is available on both Linux and macOS.
Isolation is blocking your program and you cannot tell which layer
Downgrade temporarily to confirm it, then put it back — do not ship with isolation off:standard() or maximum() and narrow the specific
field instead. Which field touches which layer is on
Security and isolation.
The box fails to start (RuntimeError) — virtualization unavailable
BoxLite depends on hardware virtualization:
- Linux: requires KVM (
/dev/kvmaccessible); WSL2 requires KVM enabled and the user in thekvmgroup. - macOS: uses Apple’s Hypervisor.framework and does not need
/dev/kvm. - Without virtualization support, the box fails to start and raises a standard
RuntimeError(the process stays alive and can be caught with try/except).
RuntimeError, which can be caught and retried.
See also
- Box types — Box types and lifecycle
- compute-resources.md — CPU / memory / disk resource configuration

