Overview
Activepieces makes outbound HTTP from two surfaces, and each is hardened separately:- User code in flows — Code steps, piece actions, anything a flow author can write. Hardened by
AP_NETWORK_MODE; see User-code egress. - Server-side HTTP from the API — OAuth token claim/refresh, Vault, Conjur, event-destination webhooks, on-call pager, MCP tool validation. Always filtered, tuned via
AP_SSRF_ALLOW_LIST; see Server-side egress.
AP_SSRF_ALLOW_LIST allow-list.
User-code egress
Every flow eventually runs user-supplied code — Code steps, piece actions, HTTP requests. Without an explicit boundary, that code can reach anything the host can reach:127.0.0.1, Redis, Postgres, the Kubernetes API, cloud-metadata endpoints (169.254.169.254), the VPC. AP_NETWORK_MODE is the switch that controls this boundary.
| Value | Effect |
|---|---|
UNRESTRICTED | No outbound guards. User code can reach any host the worker can reach. Default while the hardening stack is being validated. |
STRICT | All three layers below are installed. Outbound connections to private, loopback, link-local, and cloud-metadata IPs are blocked from user code. |
AP_SSRF_ALLOW_LIST— comma-separated IPs that bypass the block (e.g. an internal DB or sidecar).HTTP_PROXY/HTTPS_PROXY— if set, the engine routes all outbound HTTP(S) through the proxy. Loopback proxy ports are auto-exempted.
How Isolation Works
InSTRICT mode, three layers stack. Each one is a tripwire — if a request slips past one, the next one stops it.
Engine SSRF guard (in-process)
The engine monkey-patches Node’s
dns.lookup, Socket.prototype.connect, and undici’s global dispatcher. The moment user code resolves a hostname or opens a socket, the guard checks the resulting IP against a blocklist (every non-unicast range — RFC1918, loopback, link-local, multicast, cloud metadata). Covers axios, fetch, undici, and raw http/net in one pass.Egress proxy (per worker)
The worker spins up a loopback-bound HTTP(S) CONNECT proxy (
proxy-chain). User code is routed through it by the engine dispatcher. The proxy re-resolves every hostname and checks every A/AAAA record — closing the multi-record bypass where one IP is public and another is private.How It Applies to Each Sandbox Mode
Network Security layers on top of the sandbox execution mode — they are independent choices. The table below shows what is active inSTRICT mode for each sandbox:
| Sandbox Mode | Engine SSRF guard | Egress proxy | Kernel lockdown |
|---|---|---|---|
No Sandboxing (UNSANDBOXED) | ✅ | ✅ | ❌ — no per-UID separation available |
V8 Sandboxing (SANDBOX_CODE_ONLY) | ✅ | ✅ | ❌ — engine process shares the host UID |
Kernel Namespaces (SANDBOX_PROCESS with isolate) | ✅ | ✅ | ✅ — iptables rules scoped to sandbox UIDs |
Verifying Your Setup
From a Code step in a test flow, try:AP_NETWORK_MODE=STRICT you should see an SSRFBlockedError (from the engine guard) or a 403 from the egress proxy (for hostname-resolved requests). With UNRESTRICTED the request will succeed if the host allows it — confirming the guard is off.
Rolling Out
- Start in
UNRESTRICTED(default) and identify any internal services that legitimate flows need to reach (internal APIs, databases used by Code steps, etc.). - Add those IPs to
AP_SSRF_ALLOW_LIST. - Switch to
AP_NETWORK_MODE=STRICT. Watch worker logs forSSRFBlockedErrororEgress proxy refused request— each one is either an attack, a misconfigured flow, or a missing allow-list entry.
Server-side egress
Separate from flow code, the API server itself makes outbound HTTP on behalf of admins and users — OAuth token claim/refresh, Hashicorp Vault, CyberArk Conjur, event-destination webhooks, on-call pager, MCP tool validation. The URLs come from admin config (Vault server URL) or user input (webhook destination, MCP server URL), so the same SSRF risks apply. Unlike user-code egress, this layer is always on — it does not requireAP_NETWORK_MODE=STRICT. It is implemented as a request-filtering-agent wrapper attached to the shared axios instances in @activepieces/server-utils; every outbound request flows through it. The blocked ranges are identical to the engine guard (RFC1918, loopback, link-local / cloud metadata, non-unicast).
When a request is blocked, the axios error surfaced in the admin UI includes the AP_SSRF_ALLOW_LIST hint, so operators see the remediation directly in connection-test dialogs.
Self-hosted providers on private IPs
If Vault, Conjur, an on-prem OAuth2 token endpoint, or an internal webhook resolves to a private IP, the server-side filter will reject it until you add the target toAP_SSRF_ALLOW_LIST:
Relaxed TLS is still filtered
Connectors that accept self-signed certs (e.g. CyberArk Conjur in a private cluster) userejectUnauthorized: false. The SSRF filter is preserved under this setting — TLS verification is relaxed, SSRF protection is not.