Lockdown workflow
~10 min Python TypeScriptGoal: Move a sandbox from audit-only (observe everything, block nothing) to enforce mode (block everything not on the allowlist) safely. This playbook walks every step, from “let it run for a few days” through “lock down” through “handle something unexpected.”
What you’ll use: Network Allowlist, Audit Log
The four phases
Phase 1 - Observe sandbox runs, everything logged, nothing blocked
Phase 2 - Review inspect traffic suggestions from the MIOSA Network tab
Phase 3 - Lock down apply the allowlist, switch to enforce mode
Phase 4 - Operate handle pending requests, roll back if needed Phase 1 - Observe
Every new sandbox starts in audit-only mode. You don’t need to do anything - just use the sandbox normally.
Let the sandbox run for at least a few days. The longer you observe, the more complete your allowlist will be. Seven days is a good baseline for a regularly-running sandbox.
Phase 2 - Review suggestions
After the observation window, pull the list of hosts MIOSA suggests based on actual traffic.
What to keep, what to question
| Pattern | Decision |
|---|---|
api.openai.com, api.github.com - high frequency, expected | Keep |
pypi.org, files.pythonhosted.org, pythonhosted.org - if sandbox installs packages | Keep |
registry.npmjs.org - if sandbox installs npm packages | Keep |
fonts.gstatic.com, cdn.jsdelivr.net - only if the sandbox serves a browser app | Keep if needed |
169.254.169.254 - AWS metadata endpoint | Deny explicitly |
ifconfig.me, ipinfo.io - IP-lookup services | Usually deny |
| Unknown third-party domains | Investigate before allowing |
Phase 3 - Lock down
Apply the allowlist and switch to enforce mode.
Verify enforce mode is active
policy = sandbox.network.get_policy()
print(policy.mode) # → "enforce"
print(policy.allow_rules) # list of allowed hosts
print(policy.deny_rules) # list of explicit denies Test the boundary
# This should succeed
r = sandbox.exec("curl -s -o /dev/null -w '%{http_code}' https://api.openai.com/")
print("OpenAI reachable:", r.stdout) # → 401 (auth error is fine - proves egress works)
# This should be blocked
r = sandbox.exec("curl -s -o /dev/null -w '%{http_code}' https://pypi.org/simple/numpy/ --max-time 5")
print("pypi.org:", r.stdout) # wait - pypi.org IS on our list, this should succeed
# If you're testing a host NOT on the list:
r = sandbox.exec("curl -s -o /dev/null -w '%{http_code}' https://example.com/ --max-time 5")
print("example.com (should be blocked):", r.stdout) # → 000 (connection refused by proxy) Phase 4 - Operate
Handling pending requests
When enforce mode is on, any request to a host not on the allowlist is blocked and added to the Pending Requests queue. You don’t lose visibility - you see exactly what was blocked and why.
Warn-only rules for trial hosts
If you want to allow a host temporarily but flag it in the audit log:
sandbox.network.allow("api.experimental.example.com", warn_only=True) The request passes in enforce mode, but appears in the audit log with action=warn. Good for trialling a new integration before committing to it permanently.
Rolling back
If something breaks and you need to unblock immediately:
Exporting the policy for reuse
To apply the same policy to a new sandbox:
# Export policy from the locked sandbox
policy = sandbox.network.get_policy()
# Apply to a new sandbox
new_sandbox = client.sandboxes.create(template="python-ds")
for rule in policy.allow_rules:
new_sandbox.network.allow(rule.host, methods=rule.methods)
for rule in policy.deny_rules:
new_sandbox.network.deny(rule.host)
new_sandbox.network.lockdown()
print(f"Policy cloned to {new_sandbox.id}.") Full script
Troubleshooting
Sandbox can’t reach pypi.org after lockdown. You need three rules for pip: pypi.org, files.pythonhosted.org, and pythonhosted.org. All three must be on the allowlist. Check the pending queue - the missing ones will appear there the first time pip tries to connect.
Agent stopped working and I can’t figure out what’s blocked. Use sandbox.network.pending() or filter the audit log by action=reject. Each blocked row has a rejected_by field naming the rule that triggered.
I locked down a template sandbox and now all new sandboxes forked from it are also locked. Policy is inherited from the template at creation time. If you want new sandboxes to start in audit-only, call new_sandbox.network.observe() immediately after creation.
I want the same policy on 50 sandboxes. Export the policy from a reference sandbox and apply it in a loop (see “Exporting the policy for reuse” above), or set it at the tenant level so it applies to all resources by default.
What you learned
- Sandboxes always start in audit-only - no accidental lock-outs.
suggestions(since="7d")gives you a data-driven starting point for the allowlist.lockdown()is reversible:observe()reverts instantly without losing the allowlist.- Blocked requests appear in the Pending queue - nothing is silently lost.