Network Policy
--network-policy restricts where the requests, scriptling.wait_for, scriptling.net.websocket, scriptling.ai, and scriptling.mcp libraries may connect — the tool for letting scripts reach the internet without letting them reach your private network or cloud metadata endpoints. Enforcement happens at connect time: hostnames are resolved through the configured DNS servers, every resolved address is checked, and the connection is made to the validated address — so DNS rebinding, redirects, and IP-notation tricks don’t get through.
For scriptling.ai, the policy also covers remote_servers — the MCP servers an AI client can attach for tool use — so a script cannot reach an internal MCP endpoint by routing through ai.Client(..., remote_servers=[...]) instead of mcp.Client(...) directly.
scriptling --network-policy=policy.toml --disable-lib subprocess script.pyA missing or invalid policy file aborts startup rather than running scripts unrestricted. Combine the policy with --disable-lib subprocess in any mode so code cannot bypass it by shelling out to curl. A network policy constrains only the libraries wired to it; it is not a process-level network sandbox.
With a policy active, these address categories are blocked by default:
- Loopback (
127.0.0.0/8,::1) - Link-local (
169.254.0.0/16including cloud metadata endpoints,fe80::/10) - Private (
10/8,172.16/12,192.168/16,fc00::/7) - Unspecified (
0.0.0.0,::) and multicast addresses - URLs that name an IP directly (e.g.
http://10.0.0.1/)
Policy File Reference
A TOML file; every key is optional.
# Require https:// and wss:// URLs only
https_only = false
# Permit URLs that name an IP directly (http://1.2.3.4/). Blocked by
# default unless the address is already granted by allow_cidrs; every
# literal still faces the address-category and deny_cidrs rules.
allow_ip_literals = false
# Permit loopback addresses (e.g. for local testing)
allow_loopback = false
# Permit private network addresses (10/8, 172.16/12, 192.168/16, fc00::/7)
allow_private_ips = false
# Host allowlist: when set, ONLY these hosts may be contacted. Listed
# hosts are trusted — they may resolve to internal addresses. An exact
# name matches itself; a leading dot matches the domain and all subdomains.
allow_hosts = ["api.example.com", ".internal.corp"]
# Host denylist: always wins, even over the allowlist. Same syntax.
deny_hosts = ["tracker.example"]
# Address range exceptions. allow_cidrs overrides the built-in address
# blocks (how you grant one slice of your LAN); deny_cidrs wins over
# everything.
allow_cidrs = ["10.1.0.0/16"]
deny_cidrs = ["10.66.0.0/16"]
# Resolve hostnames through these servers instead of the host's resolver
# (plain DNS, port 53). One resolver then serves every script network path,
# including scriptling.net.resolve, so lookups and connections always agree.
dns_servers = ["1.1.1.1", "8.8.8.8:53"]
# Cap each HTTP request end to end - dial, TLS, redirects, reading the
# body - e.g. "30s" or "2m". Off by default: requests run as long as
# their own per-request timeout allows, which long-running calls such as
# LLM APIs need.
client_timeout = "30s"Common recipes:
# Internet-only: no internal access at all (the default policy — an empty file)# API allowlist: scripts may call one API and nothing else
allow_hosts = ["api.example.com"]# One slice of the LAN granted, https only. IP-literal URLs inside this
# range are accepted without setting allow_ip_literals.
https_only = true
allow_cidrs = ["10.1.0.0/16"]Note that in the CLI, custom DNS always comes with the policy’s address checks — a policy file cannot turn them off. Embedding hosts that want nameservers without any blocking can construct a resolver-only configuration in Go (see AllowAll in the library registration guide).
Go hosts configure the same policy in code — see the library registration guide for the netsecurity.Config reference, and the security guide for the broader sandboxing model.