Network Policy

--network-policy restricts where the requests, scriptling.wait_for, and scriptling.net.websocket 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.

scriptling --network-policy=policy.toml --no-subprocess script.py

A missing or invalid policy file aborts startup rather than running scripts unrestricted. Combine with --no-subprocess so scripts can’t bypass the policy by shelling out to curl.

With a policy active, these address categories are blocked by default:

  • Loopback (127.0.0.0/8, ::1)
  • Link-local (169.254.0.0/16 including 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; granted addresses still face the address rules above.
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"]

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
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.