inis.run

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

This 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 in allow.
  • 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 policy
  • GET /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:

  1. Package-mirror env vars. When the node is configured with INIS_PYPI_INDEX_URL or INIS_NPM_REGISTRY_URL, those mirror hosts are added to the allowlist automatically for mode: "deny" sessions, so pip install and npm install keep working without listing them yourself.
  2. 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-presets lists 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.com resolves raw.githubusercontent.com and gist.githubusercontent.com — genuinely different hosts behind that CDN — but not githubusercontent.com itself.
  • 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.

On this page