On this page

Lockdown workflow

~10 min Python TypeScript

Goal: 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

PatternDecision
api.openai.com, api.github.com - high frequency, expectedKeep
pypi.org, files.pythonhosted.org, pythonhosted.org - if sandbox installs packagesKeep
registry.npmjs.org - if sandbox installs npm packagesKeep
fonts.gstatic.com, cdn.jsdelivr.net - only if the sandbox serves a browser appKeep if needed
169.254.169.254 - AWS metadata endpointDeny explicitly
ifconfig.me, ipinfo.io - IP-lookup servicesUsually deny
Unknown third-party domainsInvestigate 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.

Next

Was this helpful?