Networking & egress
Control which domains code in a session can reach with a per-session egress allowlist.
Default: full egress
By default a session has full public outbound network access. Lateral movement is always blocked — code in a session cannot reach the host, the local network, the cloud metadata endpoint, or other sessions. Only public internet egress is open by default.
Egress source addresses
All sandbox outbound traffic currently leaves through a fixed address:
51.15.136.120This holds across nodes and pause/resume today — the address a session's guest is assigned internally can change, but the address your services see it come from does not. If you allowlist inbound traffic on your own infrastructure, this is the address to add. It may change as the fleet evolves; we'll announce it in advance.
Per-session egress allowlist
For untrusted code you can lock a session down to an explicit allowlist. Set the egress policy at create time, or change it on a live session.
{
"egress": {
"mode": "deny",
"allow": ["api.openai.com", "*.githubusercontent.com", "pypi.org"]
}
}mode: "allow"(or omitted) — full public egress. Current behaviour.mode: "deny"— block all outbound traffic except the domains inallow.allow— domains only (no IP ranges in this version). Each entry is either an exact hostname (api.openai.com) or a single leading wildcard (*.githubusercontent.com, which matches any subdomain but not the apex). Up to 256 entries.
On create
inis sessions create --egress-deny \
--allow api.openai.com \
--allow '*.pypi.org'from inis import Client
client = Client()
session = client.sessions.create(
egress_default="deny",
egress_allow=["api.openai.com", "*.githubusercontent.com"],
)const session = await client.sessions.create({
egress: { mode: "deny", allow: ["api.openai.com", "*.githubusercontent.com"] },
});On a live session
Read or replace the policy at any time:
inis sessions egress <session-id> # print active policy
inis sessions egress <session-id> --egress-deny \
--allow api.openai.com # replace policyGET /v1/sessions/{id}/egress— read the active policy.POST /v1/sessions/{id}/egress— set or replace the policy.
The active policy is also reflected on GET /v1/sessions/{id} under egress.
Forks
A forked child inherits its parent's egress policy. Each child gets its own isolated network, so the policy is applied independently to every child.
Pause / resume
The policy is stored with the session and survives pause/resume. It is re-applied automatically when the session resumes.
Project & org defaults
A session created without its own egress field inherits its project's
default, if one is set. This is how a team standardizes on deny-by-default
for a given project (or an entire org) without every caller specifying a
policy on every sessions.create call:
GET/PUT /v1/org/projects/{project_id}/egress-default— a project's default. Any member may read it; owner/admin may set it.GET/PUT /v1/org/egress-default— an org-level default. New projects created after this is set inherit it automatically; existing projects keep whatever they already had. It is a one-time template, not a live fallback — changing the org default later never retroactively changes an existing project.
An explicit per-request egress field always wins over both. The fleet-wide
default remains full public egress — deny-by-default is opt-in, per project
(or per org, via the setting above), not a platform-wide default.
Package installs in deny mode
A locked-down session still needs to reach its package mirrors. Two mechanisms cover this, and they stack:
- Package-mirror env vars. When the node is configured with
INIS_PYPI_INDEX_URLorINIS_NPM_REGISTRY_URL, those mirror hosts are added to the allowlist automatically formode: "deny"sessions, sopip installandnpm installkeep working without listing them yourself. - Baseline allowlist presets. A project's (or org's) egress default can
enable a named preset — for example
standard-dev, which covers PyPI, npm, GitHub, and Debian/Ubuntu apt mirrors — instead of hand-curating a list. Presets are configured server-side (an operator-updatable list, not compiled into the binary) and resolved live, so an update to a preset's domains takes effect immediately for sessions created afterwards.GET /v1/org/egress-presetslists what's available.
If you rely on the public indexes instead, allow the hosts you need explicitly, for example:
- pip:
pypi.org,files.pythonhosted.org - npm:
registry.npmjs.org
How it works
In deny mode, enforcement happens at the host, on the name itself, not just on whatever IP that name happens to resolve to:
- DNS is policy-aware. A deny-mode session's guest talks to a resolver
that only answers queries for names on the allowlist — an exact match, or a
real subdomain of a wildcard entry. A query for anything else comes back as
if the name doesn't exist (
NXDOMAIN), and that includes the bare domain of a wildcard-only entry:*.githubusercontent.comresolvesraw.githubusercontent.comandgist.githubusercontent.com— genuinely different hosts behind that CDN — but notgithubusercontent.comitself. - HTTPS is matched on the TLS handshake, not on DNS. Outbound TLS
connections are checked against the allowlist by the SNI in the
ClientHello, independently of how the destination IP was obtained. A workload that hardcodes an IP to dodge the resolver is still stopped at the TLS layer: connecting straight to a wildcard-only domain's own IP with that domain as the SNI is rejected the same as an unresolvable name would be.
Both checks run on the host, outside the guest, so code inside the session can't see or disable them. Anything that doesn't match is dropped, and the standard lateral-movement blocks stay in place regardless of egress mode.
While a session is under an allowlist, every allowed and denied attempt is recorded — see Execution log for the event types, payload shape, and how to read them back via the API. A session on the default full-egress policy has nothing to enforce and produces no network events.
Production best practices
Session lifecycle knobs, why you don't need your own warm pool, bulk file transfer, idempotent creates, reconnecting after resume, pagination, and retries.
Connections
Session-scoped credential brokering — code in the session calls the provider's real hostname, and the platform injects the credential on the way out.