Networking
Networking
A run executes your agent's code in a sandbox with no direct route to the internet. Outbound traffic is governed by two layers:
- The per-run policy (
environment.networking) — enforced by the agent runtime inside the run. It applies to the standard proxy path every normal HTTP client uses (see below) and can only narrow what the run may reach. - The platform ceiling — a fixed, platform-managed egress boundary every
connection ultimately traverses. It allows the hosts aex itself manages
(model providers, built-in tool endpoints, package registries, and related
well-known development hosts such as
github.com) and enforces a fixed SSRF deny-list: loopback, link-local, cloud-metadata, and other private ranges are blocked on the standard proxy path every normal HTTP client uses, including hostnames that resolve to those ranges. Note: on the current managed (Fargate) plane a subprocess that deliberately bypasses the proxy with a raw socket can still reach the on-link task-metadata IP (169.254.170.2), which exposes non-secret task identity (AWS account id via the task ARN, cluster/image ref) — but never IAM credentials (the run's task role is unset, so the metadata credential endpoint serves nothing) and never another tenant's data.
Honest boundary statement: the per-run allowedHosts policy is enforced by the
run's own runtime on the standard proxy path — it is not yet enforced at
the platform proxy layer. A subprocess that deliberately bypasses the standard
proxy environment (a raw socket / raw CONNECT) is bounded by the platform
ceiling rather than by the per-run list. Per-run enforcement at the platform
proxy layer is planned; until it ships, treat allowedHosts as a strong
default-path control and an auditable statement of intent, not a hard isolation
boundary against adversarial code inside the run.
Default posture. A run that does not set environment.networking runs in
open mode: its own code may reach anything within the platform ceiling with
no allowlist required. Use environment.networking to narrow that surface
when you want a tighter, auditable egress posture. Code cannot widen the
ceiling from inside the container.
Paths that always work
These reach the network over managed platform paths and are not subject to
environment.networking, so you never list their hosts:
- The model / provider call for the run (and its subagents).
- The built-in
web_searchandweb_fetchtools. They run over a managed, SSRF-guarded server-side path, which is why they can reach arbitrary public URLs even though your own code is bounded by the ceiling. - Remote MCP servers you declare in
mcpServers— MCP traffic rides a managed path; see MCP. - The package registries for any
environment.packagesyou declare (pip → PyPI, apt → the distribution mirrors). Declaring a package implicitly allows the registry it installs from.
environment.networking governs the other case: outbound that your own
code makes — a curl in the bash tool, a requests/urllib call in Python,
a fetch in code_execution, or a third-party SDK.
Restrict a run to an allowlist
Set mode: "limited" and list exactly the hosts your code is allowed to reach.
The run's runtime enforces the list on the standard proxy path: a connection to
a host that is neither on the list nor one of the always-allowed paths above is
refused before it leaves the run. Package-registry hosts implied by
environment.packages are appended automatically so installs keep working.
Note that allowedHosts narrows within the platform ceiling — listing a host
does not by itself make it reachable if the platform ceiling does not carry it.
If your run needs a host the ceiling blocks, contact support.
TypeScript
import { Aex, Models, Providers } from "@aexhq/sdk";
const aex = new Aex({ apiKey: process.env.AEX_API_KEY! });
await aex.run({
provider: Providers.ANTHROPIC,
model: Models.CLAUDE_HAIKU_4_5,
message: "Fetch the public status page and summarize it.",
environment: {
networking: {
mode: "limited",
allowedHosts: ["api.example.com", "status.example.com"]
}
},
apiKeys: { anthropic: process.env.ANTHROPIC_API_KEY! }
});allowedHosts entries are host names (lowercased), e.g. api.example.com. Add a
non-default port when you need one (api.example.com:8443); a bare host name
covers HTTPS on 443. Matching is exact per host — it is not a wildcard or suffix
match, so list each host you need.
Keep the allowlist in your session options so the submitted network policy is visible at the same call site as the code that needs it.
Open mode
open is the default: a run that omits environment.networking already runs in
open mode. Set mode: "open" explicitly when you want to be unambiguous. Open
mode applies no per-run allowlist — the run's own code may reach anything the
platform ceiling allows, still subject to the SSRF deny-list. Prefer limited
whenever you can name the hosts — it gives the run a stable, auditable,
least-privilege egress surface (it is the tighter posture, not the default).
await aex.run({
model: Models.CLAUDE_HAIKU_4_5,
message: "Research the topic across the open web.",
environment: { networking: { mode: "open" } },
apiKeys: { anthropic: process.env.ANTHROPIC_API_KEY! }
});(Web research like the example above flows through the managed web_search /
web_fetch path, which is not ceiling-bounded.)
Transparent for normal HTTP clients
You write ordinary code — there is no per-request proxy configuration and no
client changes. The runtime sets the standard proxy environment
(HTTP_PROXY / HTTPS_PROXY, with NO_PROXY for internal hosts), so any client
that honors it — curl, Python requests / urllib, pip, npm, Node
fetch, and most language SDKs — reaches allowed hosts transparently:
# In the agent's shell, against a limited run that allows api.example.com:
curl -sS https://api.example.com/v1/status # works
curl -sS https://other-host.example # refused (not in allowlist)You also do not need to install any certificate. The platform manages the trust store for the managed egress path automatically, so TLS verification in your client succeeds without extra setup.
Limitations and gotchas
- The per-run policy is enforced by the run's runtime, not at the platform
proxy. Clients that honor the standard proxy environment (almost all HTTP
tooling) are held to the
allowedHostslist. A subprocess that deliberately ignores the proxy environment and opens a raw connection is not held to the per-run list — it is bounded by the platform ceiling (the aex-managed provider/tool/registry host set) and the SSRF deny-list instead. Per-run enforcement at the platform proxy layer is planned. - A client that hard-bypasses the standard environment may fail to connect. A client that ignores the proxy environment, pins or replaces its certificate trust store, or speaks a non-HTTP protocol over a raw socket can hit a wall even for a host you allowed. The fix is to let the client use the standard proxy and certificate environment the runtime provides (most libraries do by default), rather than overriding it.
allowedHostsonly applies inlimitedmode. It is ignored inopenmode, where the platform ceiling and the SSRF deny-list are the gates.allowedHostscannot exceed the platform ceiling. It narrows; it never widens. A listed host outside the ceiling still fails.
For credentialed HTTP calls, pass the credential as an environment.secrets
entry and let your code use its normal HTTP client. For remote tool servers, see
MCP. For the full set of run-config fields, see
Run configuration.