SECURITY DESIGN · RUNTIME NETWORK

Runtime outbound URL and SSRF protection

Evidence snapshot: 2026-08-12, Runtime implementation through the Task 10 consolidated fix (Task 1–8 anchor 80c377fa). This document is ordered as OpenProgram current state, other projects, then the OpenProgram future plan. Implemented behavior and future work are labeled separately.

Part I · Current
OpenProgram current state

Runtime-owned HTTP requests use a registry-keyed URL policy and managed transport. The implementation validates all DNS answers, dials only approved peers, handles redirects explicitly, confines credentials to their declared origin, bounds response resources, and fails static verification for unclassified consumers or active unmanaged SDK transports.

01Implemented boundary

ComponentImplemented responsibilityExplicit non-responsibility
openprogram/security/url_policy.pyURL and origin normalization; scheme, userinfo, host, and port validation; full A/AAAA classification; exact owner exceptions; stable sanitized reason codesDoes not send network requests or infer a caller's trust class
openprogram/security/safe_http.pyImmutable 42-consumer registry; sync/async peer-constrained transports; Host/SNI preservation; manual redirects; credential, header, MIME, decoded-body, encoding, timeout, proxy, and atomic-download enforcementDoes not accept caller-created policy objects or expose verify=False
Consumer adaptersSelect one immutable registry key and, for configured services or callbacks, supply the exact owner-configured originMay not implement a second private-address classifier or retry through a raw client
runtime_http_audit.py, doctor, and scripts/check_runtime_http.pyBounded sanitized denial state, exact owner exception/proxy reporting, AST inventory, SDK disposition verification, and stale exclusion detectionDo not display userinfo, query, fragment, credentials, peer response bodies, or token-bearing paths

02Runtime consumers and separate boundaries

BoundaryCurrent treatmentStatus in this feature
Arbitrary and derived Runtime URLsweb_fetch, attachments, generated assets, image result downloads, catalogs, marketplaces, and updater metadata use managed clients with public or exact-service policyIncluded
Fixed/configured APIsWeb search, image APIs, channel REST, TTS, provider listing/probes/OAuth, Web model listing, MCP HTTP/SSE, and local probes use fixed or owner-configured exact originsIncluded
Third-party SDKsProvider and MCP clients receive injected managed transports; exact-origin REST adapters remain managed; uninjectable Bedrock, Slack/Discord gateway, and edge-tts SDK paths fail closedIncluded and classified
Browser navigation, popup, Service Worker, and page subresourcesGoverned by the browser-control design and any owner egress isolationExcluded
Sandboxed arbitrary code, plugin code, external provider CLIs, and package managersGoverned by sandbox, plugin trust, child-process, and installation boundariesExcluded
Owner control-plane liveness probesNarrow loopback-only exclusions are inventoried with exact call kind, owner, reason, and countClassified, not claimed as Runtime URL fetch
Feature-matrix scope and status. The implemented controls cover only Runtime-owned HTTP fetches. The matrix records for this bounded feature after the integrated repository gate passed. Browsers, arbitrary code, plugins, external CLIs, and package-manager child processes remain separate boundaries.
Part II · References
How other projects design this boundary

The comparison preserves all twelve external feature-matrix columns plus OWASP. Permission prompts, hostname rules, application URL validation, policy proxies, and operating-system network sandboxes remain distinct controls; upstream wrappers and protocol libraries are not counted again as independent implementations.

03Reference mechanisms

Evidence boundary. The matrix uses fixed snapshots. Current official documentation is linked directly for design context, without retroactively changing the fixed-version matrix scores. Capabilities not confirmed in the audited snapshot are described as unconfirmed, not as universally absent.
ProjectApplication URL-fetch evidenceNetwork or permission boundaryAdopted, modified, or rejected
HermesShared url_safety covers web, browser, vision, and gateway media. DNS failure is closed; loopback, RFC1918, link-local, CGNAT, metadata, reserved, multicast, and unspecified results are rejected; redirects are checked hop by hop; URLs are sanitized and media is streamed with limits.A process-wide allow_private_urls switch relaxes multiple entries together. Application checks still do not replace OS network isolation.Adopted shared fail-closed validation, the full address set, redirect checks, sanitization, and limits. Modified the global switch into exact consumer-scoped service-origin exceptions.
OpenClawPrivate, internal, and special-use targets are denied by default, with exact or wildcard hostname exceptions and checks before navigation, interaction-generated loads, and final URLs. Its documentation identifies speculative navigation and browser subresource risk.Official documentation states that request interception is not a network firewall: redirects, popups, Service Workers, and background resources can still require egress isolation or a policy proxy.Adopted strict defaults and explicit exceptions. Modified browser interception into a separate acceptance boundary; it is not Runtime-fetch evidence.
Claude CodeWebFetch(domain:...) supports allow/deny. Before a request, the hostname is sent to the Anthropic safety blocklist; the result is cached for exactly five minutes, and the owner may disable the preflight.The Bash sandbox uses a Seatbelt or bubblewrap HTTP/SOCKS proxy that child processes inherit. The proxy trusts the client-provided hostname and does not inspect TLS content, so broad domains and domain fronting remain risks.Adopted layered tool authorization and child-process egress policy. Rejected hostname permission as DNS/IP/connect-time SSRF evidence.
CodexThe audited mainline does not substitute one WebFetch string check for a network boundary.codex-network-proxy supplies HTTP/SOCKS5 proxying, exact or restricted wildcard domains, private-resolution rejection, limited read-only methods, MITM header hooks, Unix-socket control, and structured audit; the OS sandbox constrains loopback bypass paths.Adopted structured deny reasons, audit, and managed-policy concepts. Retained consumer-aware Runtime safe clients rather than relying only on a child-process proxy.
CodeBuddy 2.109.3WebFetch applies Security Center domain policy and rejects IP literals, localhost, and selected private ranges. WeCom media uses an official CDN allowlist with redirects disabled.Sandbox allowedDomains intersects with WebFetch permission. The audited bundle's general WebFetch path checks literal hosts; the snapshot does not confirm full hostname A/AAAA validation, peer binding, or hop-by-hop redirect enforcement.Adopted fixed channel-service allowlists and the intersection of permission and network policy. Rejected literal-IP-only protection for general fetches.
Gemini CLIOfficial tool documentation warns that web_fetch can reach localhost and private networks; Plan Mode can require confirmation. The local 0.35.3 core contains IP classification and DNS utilities, but the warning shows they do not form a general WebFetch private-target boundary.User confirmation is a permission decision and does not constrain the connected peer.Adopted explicit risk documentation. Rejected confirmation as a substitute for deterministic target enforcement.
OpenCodewebfetch permissions use the complete requested URL and support allow, ask, or deny. Current official permissions documentation does not establish private-IP classification, full DNS results, hop-by-hop redirects, or peer binding.shell uses the host user's network privileges; official documentation calls string rules best effort, not network isolation.Adopted uniform resource-permission semantics. A permitted URL must still pass independent transport policy.
pi-monoThe fixed snapshot does not confirm a built-in arbitrary-URL fetch in the core product; network capability primarily comes from shell commands, installers, or user extensions.The core snapshot does not confirm an OS egress policy. Third-party pi-sandbox is not counted as built-in pi-mono behavior.Rejected it as a Runtime SSRF algorithm reference. Its extension boundary supports keeping third-party code outside safe-client completion.
pi-aiThis is protocol reference source, not a runnable product, and has no session or Runtime URL consumer.Not applicable.Excluded from product-level SSRF conclusions while retaining its matrix column to preserve the audited unit distinction.
weclawThe fixed snapshot is a messaging bridge to external ACP/CLI agents and does not confirm an independent general URL fetch.It primarily inherits the launched CLI's tools and network privileges; the delegated product's controls are not counted again for weclaw.Retained channel-media and external-process launch as its relevant boundaries; rejected it as a general safe-HTTP reference.
cc-internal / cx-internal / gm-internalcc-internal and cx-internal wrap upstream launchers; gm-internal substantially reuses Gemini CLI. The audited packages do not confirm independent strengthening of general URL-fetch policy.They inherit most Claude Code, Codex, or Gemini CLI permission and network behavior. Added authentication or endpoints do not themselves create an SSRF boundary.Audited only their additional endpoints, credential forwarding, and configuration differences; rejected double-counting them as three independent security designs.
OWASPSeparates known-service allowlisting from arbitrary-public-target validation, restricts protocols, validates every A/AAAA result, and prefers allowlists for trusted services.A single DNS preflight still has DNS pinning and time-of-check/time-of-use risk; network controls are also recommended.Adopted separate trust classes and connect-time peer constraints. Rejected one preflight DNS result as the only boundary.

Primary sources: Hermes url_safety.py, Hermes Security, OpenClaw Security, Claude Code Sandboxing, Claude Code WebFetch safety check, Codex network proxy, OpenCode Permissions, Gemini CLI tools, and OWASP SSRF Prevention.

Versioned local snapshot evidence: @tencent-ai/codebuddy-code@2.109.3 dist/codebuddy.js, CHANGELOG.md, dist/web-ui/docs/cn/cli/permissions.md; @google/gemini-cli@0.35.3 core/dist/src/utils/fetch.js; references/pi-mono@3eb002766fff; references/weclaw@10711d0c6b7e; and references/pi-ai.

04Adopted, modified, and rejected choices

DecisionMechanismReason
AdoptedOne pure URL/IP policy; all DNS answers must pass; DNS failure is closed; every redirect is reevaluated; errors are origin-only; decoded bodies are boundedThese checks cover the Runtime's target, redirect, credential, and resource boundaries consistently.
AdoptedDistinct untrusted-public, fixed-public-service, configured-service, and loopback-callback trust classesOwner-configured localhost/private services remain usable without granting arbitrary public consumers private-network access.
AdoptedClaude Code and CodeBuddy permission/network layering, Codex structured deny reasons, and CodeBuddy fixed channel-media allowlistsPermission answers who may request a resource; transport policy answers which peer receives the connection and credentials.
ModifiedHermes process-wide allow_private_urlsReplaced by an exact consumer plus normalized origin or canonical private/local CIDR; metadata and link-local targets remain non-exceptable.
ModifiedOpenClaw browser interception and Codex whole-process egress proxyBrowser controls remain a separate gate; a policy proxy is optional, owner-declared, separately peer constrained, visible in doctor output, and has no direct fallback.
RejectedURL-string-only checks, one DNS preflight, implicit redirects, environment proxy inheritance, TLS verification disablement, or raw fallbackEach leaves a target, rebinding, credential, or bypass path.
RejectedUser confirmation or hostname allow/deny as target enforcementNeither validates every resolved address nor constrains the connected peer.
RejectedApplying a public-only rule to every HTTP clientThis would break explicitly configured local model endpoints, MCP servers, and intranet services.
RejectedCounting Origin/Host, CORS, owner authentication, browser checks, or sandbox networking as Runtime SSRF completionThose controls protect different directions or execution boundaries.
Part III · Plan
OpenProgram plan status and future work

The Runtime URL-fetch implementation is complete through Task 8. This section records that implementation evidence first, then lists separate future boundaries. The matrix remains because those separate boundaries are excluded.

05Completed plan: implementation evidence

Registry-keyed caller

42 immutable consumers
four trust classes
exact configured or callback origin

Pure policy decision

normalized URL and origin
one complete DNS answer set
exact exception and reason code

Managed transport

approved IP peer
original Host, SNI, and certificate
manual redirect and bounded response

05.1 Transport and policy behavior

05.2 Consumer and SDK disposition evidence

DispositionConsumersEnforcement
Injected transportprovider.openai.sdk, provider.anthropic.sdk, provider.google.sdk, mcp.configured.http, mcp.configured.ssePublic SDK construction receives a scoped managed client or factory; real SDK-chain tests reach the constrained backend.
Exact originTelegram, WeChat, Feishu, Matrix, Slack, Discord, fixed/configured TTS, and other fixed/configured REST consumersThe normalized owner or shipped origin is frozen before credentials are attached; redirects cannot move credentials to another origin.
Derived URL extractionAttachment, generated-asset, and image-result consumersThe SDK or upstream response yields a URL, then Runtime performs the download or upload through a dedicated managed registry consumer.
Disabledprovider.amazon_bedrock.sdk, channel.slack.gateway_sdk, channel.discord.gateway_sdk, tts.edge_sdkStartup or invocation fails with UNMANAGED_TRANSPORT before importing or using the uninjectable network SDK. Bedrock covers both the registered stream and model-list entry before boto3/botocore credential or client activity.

05.3 Owner exceptions, policy proxy, doctor, and inventory

Owner configuration accepts only a registered consumer plus exactly one normalized origin or canonical private/local CIDR. It rejects wildcards, suffixes, credentials, unknown fields, public/default-route networks, metadata, link-local ranges, and exception forms not allowed by the consumer. Existing owner-authenticated settings paths remain the only mutation authority.

A policy proxy is usable only when owner configuration sets enforces_target_policy: true. Runtime evaluates the target before proxy use, constrains the proxy peer separately, reports delegation through doctor/audit state, and never retries direct.

Inventory exclusionOwner and narrow reason
security/safe_http.pyRuntime managed transport; the only allowed direct httpcore pool/proxy construction
functions/tools/browser/_chrome_bootstrap.pyBrowser control; exact browser opener construction and loopback CDP liveness dial
_cli_cmds/mcp.pyOwner control plane; authenticated backend opener only
cli_ink.py, _cli_cmds/doctor.py, _cli_cmds/rescue.pyOwner control plane; exact loopback worker liveness socket only

The checker fails for an unregistered raw call, active unmanaged SDK transport, registry entry without a classified consumer, or stale exclusion. Doctor exposes stable runtime-http-registry, runtime-http-owner-exceptions, runtime-http-policy-proxy, runtime-http-recent-denials, and runtime-http-unmanaged-transport labels.

05.4 Verification snapshot

CommandRecorded result
uv run --extra dev pytest -q tests/security804 passed
uv run --with pip --with boto3 pytest -q tests/meta_functions tests/providers tests/unit tests/webui tests/integration/test_mcp_client.py3482 passed, 12 skipped, 1 xfailed
uv run --extra dev --with boto3 pytest -q4923 passed, 14 skipped, 2 deselected, 1 xfailed
uv run python scripts/check_runtime_http.pyunregistered=0 active_unmanaged=0 registry_without_consumer=0 stale_exclusions=0
uv run python scripts/check_feature_matrix.py docs/reference/design/feature-matrix.htmlfeatures=160 openprogram_score=78 openprogram_gaps=73 openprogram_only=6
Publication gate. Policy parsing/address tests, real sync/async socket and TLS peer tests, DNS-rebinding prevention, redirect and credential-origin tests, response/decompression/timeout cleanup, all-consumer migration, four-way SDK classification with zero active unmanaged transports, owner-only exact exceptions, doctor/audit/static enforcement, and the 42-row compatibility contract are present. The complete repository command passes with the declared dev and optional provider dependencies. The feature matrix records because the verified scope is Runtime-owned HTTP rather than the separate browser, arbitrary-code, plugin, external-CLI, and package-manager boundaries.

06OpenProgram future plan

Future boundaryRequired work before claiming completion
Browser navigation and page-derived trafficDefine and test navigation, popup, Service Worker, background resource, redirect, download, CDP, and browser-profile policy across every browser backend; use an enforcing egress boundary where browser interception is insufficient.
Plugin and arbitrary-code networkingKeep the trust and sandbox model separate from Runtime safe HTTP; add an OS or policy-proxy egress boundary if these processes need restricted network access.
Disabled third-party SDK network featuresEnable only after the SDK supports managed transport injection or an owner-configured enforcing policy proxy has equivalent tests. Do not replace the disabled disposition with an unverified SDK guarantee.

Related documents: Sandbox design, network proxy design, and feature matrix.