Skip to main content
All sandbox network traffic passes through a host-controlled networking stack where policies are enforced at the packet level. There’s no underlying host network to bypass. See Networking concepts for more on how this works.

Preset policies

public_only is the default. It blocks private address ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 127.0.0.0/8, 169.254.0.0/16) while allowing public internet access.
use microsandbox::{Sandbox, NetworkPolicy};

// No network access
let sb1 = Sandbox::builder("isolated")
    .image("python:3.12")
    .disable_network()
    .create()
    .await?;

// Public internet only (default)
let sb2 = Sandbox::builder("web-agent")
    .image("python:3.12")
    .network(|n| n.policy(NetworkPolicy::public_only()))
    .create()
    .await?;

// Unrestricted access
let sb3 = Sandbox::builder("dev")
    .image("python:3.12")
    .network(|n| n.policy(NetworkPolicy::allow_all()))
    .create()
    .await?;

Custom policies

Build a policy with explicit egress and ingress rules. Rules are evaluated first-match-wins.
use microsandbox::Sandbox;
use microsandbox_network::policy::*;

let policy = NetworkPolicy {
    default_action: Action::Deny,
    rules: vec![
        Rule {
            direction: Direction::Outbound,
            destination: Destination::Any,
            protocol: Some(Protocol::Tcp),
            ports: Some(PortRange::single(443)),
            action: Action::Allow,
        },
        Rule {
            direction: Direction::Outbound,
            destination: Destination::Any,
            protocol: Some(Protocol::Udp),
            ports: Some(PortRange::single(53)),
            action: Action::Allow,
        },
        Rule::deny_outbound(Destination::Group(DestinationGroup::Metadata)),
        Rule::deny_outbound(Destination::Group(DestinationGroup::Private)),
    ],
};

let sb = Sandbox::builder("secure-agent")
    .image("alpine:latest")
    .network(|n| n.policy(policy))
    .create()
    .await?;

Port mapping

Expose ports from the sandbox to the host so services running inside the VM are accessible from your machine. For Rust, SandboxBuilder::port() and port_udp() are top-level shorthands that compose with .network(...) when you also need policy, DNS, or TLS settings.
use microsandbox::{Sandbox, NetworkPolicy};

let sb = Sandbox::builder("api")
    .image("python:3.12")
    .port(8080, 80)
    .port_udp(5353, 5353)
    .network(|n| n.policy(NetworkPolicy::public_only()))
    .create()
    .await?;

DNS interception

All DNS queries are intercepted and resolved on the host side. This enables domain blocking, suffix blocking, and rebinding protection.
use microsandbox::{Sandbox, NetworkPolicy};

let sb = Sandbox::builder("safe-agent")
    .image("python:3.12")
    .network(|n| n
        .policy(NetworkPolicy::public_only())
        .block_domain("malware.example.com")
        .block_domain_suffix(".tracking.com")
    )
    .create()
    .await?;

Secrets

Secrets use a placeholder substitution model. The guest VM never sees the real credential. When you bind a secret to an environment variable and one or more allowed hosts, microsandbox generates a random placeholder (e.g., OPENAI_API_KEY=msb_ph_a8f3c2...) and injects that into the guest instead. The real value never enters the VM. The only way it reaches the outside world is when a request goes to an allowed host, at which point microsandbox swaps the placeholder for the real value. Everywhere else, the placeholder is just a meaningless string. So even with full code execution inside the sandbox, there’s nothing to steal. The credential was never there.
use microsandbox::Sandbox;

let sb = Sandbox::builder("agent")
    .image("python:3.12")
    .secret(|s| s
        .env("GITHUB_TOKEN")
        .value(std::env::var("GITHUB_TOKEN")?)
        .allow_host("api.github.com")
        .allow_host_pattern("*.githubusercontent.com")
    )
    .secret_env("OPENAI_API_KEY", api_key, "api.openai.com")
    .create()
    .await?;

TLS interception

Enable HTTPS traffic inspection with an auto-generated CA certificate. microsandbox generates a per-sandbox CA during creation, installs it in the guest’s trust store, and generates per-domain certificates on first connection. Domains that use certificate pinning (or that you don’t want to intercept) can be bypassed.
use microsandbox::Sandbox;

let sb = Sandbox::builder("agent")
    .image("python:3.12")
    .network(|n| n
        .tls(|t| t
            .bypass("pinned-api.example.com")
            .bypass("*.gov")
        )
    )
    .create()
    .await?;

Protocol support

For most sandboxed workloads, networking behaves the way you’d expect:
  • Normal outbound TCP and UDP traffic works, including common tools and libraries like curl, wget, package managers, HTTP clients, database drivers, and DNS lookups.
  • DNS is intercepted on the host side, which is what enables domain blocking, rebinding protection, and secret-aware policy checks.
  • ICMP echo is supported: Pinging external hosts works on systems that support unprivileged ICMP echo sockets.
Raw sockets and full ICMP forwarding are not supported because they require elevated privileges on the host. Tools that depend on richer ICMP behavior, such as traceroute, are outside the current scope.
In practice, web requests, APIs, package installs, service-to-service calls, and published ports are the primary use case, and those work independently of these ICMP caveats.