Managed Runtime HTTP keeps URL, credential, redirect and TLS policy while following the user's ordinary proxy for public destinations. When a request goes through that proxy, the proxy resolves the target hostname; the client validates the target first, then pins and checks the proxy socket peer.
A direct, peer-pinned connection cannot reach services that are only reachable through the user's proxy. Fake-IP proxies such as Clash also answer local DNS queries from the benchmarking range 198.18.0.0/15, so a policy that trusts only the local resolver sees every public hostname as a non-global address and refuses it (NON_GLOBAL_ADDRESS), even though the real resolution happens inside the proxy.
tool.web_fetch, tool.image_result.download, channel attachment and asset downloads) and fixed audited HTTPS services (search APIs including DuckDuckGo, image APIs, updater, skills catalog, office assets, channel APIs, TTS).provider.*, webui.model_listing.*) follow ordinary proxies only when the exact request origin is in the provider API or OAuth audit inventory.The route is chosen before the target policy runs, for every request and every redirect hop, so the policy and the transport always agree on whether a proxy carries the request. A host matched by NO_PROXY, or a process without any route, connects directly with the full local address check.
When a public request is routed through the proxy, the policy evaluates it as proxy-resolved:
localhost and the .localhost, .local, .lan, .home.arpa, .internal, .intranet, .corp and .home suffixes. Metadata hostnames report METADATA_ADDRESS.198.18.0.0/15 and failed lookups are left to the proxy; malformed answers fail closed.requires_proxy. Building a direct pool or opening a direct socket for such a decision raises PROXY_ROUTE_REQUIRED.Fixed audited HTTPS services also accept fake-IP answers on direct connections, because the caller cannot choose their hostname and TLS verifies it. Untrusted public URLs never accept a fake-IP answer on a direct connection.
HTTP, HTTPS and SOCKS5 proxies use httpcore proxy pools with a decision-aware backend. HTTPS targets are tunnelled by hostname with CONNECT; plain HTTP targets are forwarded in absolute form. The proxy authority is an owner-selected route; metadata and link-local addresses remain forbidden. Proxy authentication is passed only to the proxy handshake. TLS verifies the original service hostname, the Host header is generated from the validated origin, and redirects cannot forward credentials across origins. Failures never fall back to a direct connection.
The routing map is immutable within a client and part of shared-client cache identity. A new call after routing changes retires stale clients. Explicitly supplied transport-security objects stay deterministic and do not inherit ambient routing.
Reuse HTTPX's environment parsing and URLPattern precedence instead of implementing a second NO_PROXY matcher. Keep ordinary routing separate from PolicyProxyConfig: a normal Clash proxy does not assert arbitrary URL policy enforcement, so local checks still run in front of it. Do not introduce a new profile, disable URL protection, modify OAuth credentials or extend ordinary routing to configured custom services. CA bundles remain explicitly controlled by outbound security configuration.
Accepted residual risk: behind a proxy the final resolution is the proxy's, so a public hostname whose real answer is private is caught only when the local resolver returns that real answer. Behind a fake-IP resolver, or with DNS rebinding between the local check and the proxy's lookup, the proxy's own rules decide. Read-only methods, the 80/443 port limit for untrusted URLs and credential stripping still apply. Owners who need a strict guarantee configure an enforcing policy proxy or list hosts in NO_PROXY.
Public sync and async entries use HTTP, HTTPS and SOCKS5 routes; web_fetch behind a fake-IP resolver reaches the target through the proxy by hostname; IP literals, local names and real private answers stay refused when proxied; NO_PROXY hosts keep the direct check; a proxy-resolved decision never opens a direct socket; NO_PROXY and override precedence hold; shared clients are replaced when routes change; unauthorized target and proxy addresses are rejected before network activity; service and proxy credentials stay isolated; explicit policy-proxy behavior and cleanup are retained.
Implemented in openprogram/security/url_policy.py (proxy_resolves, requires_proxy), openprogram/security/safe_http.py (uses_ambient_proxy, route-before-policy) and load_outbound_security_config. The sandbox command proxy (openprogram/sandbox/network_policy.py) keeps its own direct public-address rule and does not yet recognise fake-IP answers. A live model reply also requires valid provider credentials and available service quota.
Source: references/openclaw/src/infra/net/proxy-env.ts, proxy-fetch.ts,
src/infra/net/proxy/, and https://docs.openclaw.ai/cli/proxy/.
proxy-env.ts) that deliberately mirrors
undici EnvHttpProxyAgent semantics: lowercase vars take precedence over
uppercase; HTTPS requests prefer https_proxy then fall back to
http_proxy; ALL_PROXY is a fallback fed in explicitly. A full
NO_PROXY matcher (comma/whitespace split, case-insensitive, *,
leading-dot, *., subdomain suffix, optional :port, bracketed IPv6,
plus their own IPv4-CIDR extension) gates every proxy decision — it is
a reimplementation kept in sync with undici because undici doesn't
export its matcher.--proxy-url flag / proxy.proxyUrl config /
OPENCLAW_PROXY_URL env, with optional --proxy-ca-file, implemented as
a makeProxyFetch(proxyUrl) wrapper over undici ProxyAgent, plus a
managed-proxy lifecycle (validation, TLS options, active-state tracking).fetch-guard.ts) composes with the same matchesNoProxy.OpenProgram borrows the useful diagnostic property that standard environment variables have one documented interpretation, while its managed provider path adds a separate policy-proxy boundary. OpenClaw goes further with proxy lifecycle validation and SSRF gating, which this design does not need.