Proxyline is a Node-process runtime, not an operating-system sandbox. Understanding what it does — and what it cannot do — is essential before relying on it as a policy.
Proxyline's runtime assurances assume it is installed before application and plugin networking code is loaded. Install it as the first import in the process when proxy routing is part of the security posture.
These assurances apply to the surfaces Proxyline patches or helpers it creates. They do not apply to code that captured networking functions before installation, raw sockets, native transports, or separate bundled transport stacks.
In managed mode, Proxyline forces traffic through the configured proxy on the surfaces it covers:
http.request/http.get/http.globalAgenthttps.request/https.get/https.globalAgent- The undici global dispatcher (i.e.
fetch) - WebSocket clients that accept a Node
agent, viaproxy.createWebSocketAgent()or by reusing the patchedhttp.requestduring the upgrade - Explicit HTTP CONNECT when callers opt in to
openProxyConnectTunnel
Caller-supplied http.Agent / https.Agent instances are replaced per request, and createConnection overrides are stripped. TLS-relevant agent options are lifted onto the request so destination TLS still validates correctly.
Managed mode can also accept a bypassPolicy callback for explicitly trusted direct-routing exceptions, such as local control-plane endpoints. Treat it as part of your security policy: keep it narrow and log matching URLs with explain().
In ambient mode the same surfaces are covered when at least one supported http:// or https:// proxy endpoint is set through HTTP_PROXY, HTTPS_PROXY, or ALL_PROXY; unsupported proxy schemes are ignored, and NO_PROXY is honored.
Anything that does not flow through the patched APIs:
- Direct
net.connectortls.connectcalls. Code that opens raw sockets is not seen by Proxyline. - Native modules with private transport stacks (e.g. some database drivers, gRPC C bindings).
- Libraries that import and call
undici.fetchdirectly with their own explicitDispatcher. Proxyline's managedglobalThis.fetchstrips explicit dispatchers, but it cannot rewrite every imported undici function reference. - DNS resolution itself. Proxyline tells the proxy a hostname; DNS-based exfiltration via the local resolver is out of scope.
- Sockets opened before
installProxylineran. Existing keepalive connections continue to use whatever transport they were created with. - Module references captured before
installProxylineran. Anything that storedhttp.requestin a local variable at import time keeps the un-patched reference. - Non-standard internals on native
Requestobjects created beforeinstallProxylineran. Proxyline can normalize standard Request fields, but runtimes do not expose every internal field consistently.
For a process-wide proxy enforcement policy, combine Proxyline with operating-system level controls (egress firewall rules, network namespaces, seccomp, or a sidecar proxy).
Install Proxyline as the first import in your application entry point. Anything that imports node:http, node:https, undici, or a wrapper library before Proxyline is initialized may have already captured the original method references. The patches still apply to future calls into http.request etc., but a stale captured reference will bypass them.
// entry.ts
import { installGlobalProxy } from "@openclaw/proxyline";
installGlobalProxy({ mode: "managed", proxyUrl: process.env.PROXY_URL! });
// only after install:
await import("./app.js");Only one Proxyline runtime can be installed at a time. A second installProxyline call throws ProxylineError with code RUNTIME_ALREADY_ACTIVE by default. Use ifActive: "reuse-compatible" to share the current matching runtime, ifActive: "replace" to stop and reinstall intentionally, or call proxy.stop() yourself before installing a different runtime.
This is deliberate: two competing proxy patches would race on http.request and globalAgent, and the loser would silently bypass the winner.
- Userinfo in proxy URLs becomes a
Proxy-Authorization: Basicheader on every CONNECT / absolute-form request. - Userinfo, search, and fragment are stripped from any URL Proxyline reports back to the caller (
handle.proxyUrl,decision.proxyUrl,runtime.installed). redactProxyUrlis exported so callers can apply the same rule to URLs they log themselves.
| Threat | Mitigated | Notes |
|---|---|---|
Library passes a direct http.Agent per request |
yes (managed) | Replaced before the request runs |
Library passes a direct Dispatcher to managed globalThis.fetch |
yes | Explicit dispatchers are stripped |
| Trusted local endpoint needs direct routing | yes, with bypassPolicy |
Keep the callback narrow and auditable |
Library calls imported undici.fetch with a direct Dispatcher |
no | Imported function references are outside the global fetch patch |
Library uses net.connect directly |
no | Out of scope |
Library captured http.request at import time |
no (if before install) | Install Proxyline first |
| Environment variable set after install | no | Snapshot at install time |
| Proxy credentials leaked into logs | yes (in Proxyline output) | Use redactProxyUrl for caller logs |
| Process-wide CA trust drift | yes | proxyTls is scoped to the proxy endpoint |
Security issues: open a private advisory at https://github.com/openclaw/proxyline/security/advisories. Do not open public issues for unpatched problems.