openclaw - ✅(Solved) Fix [Feature]: Support allowPrivateNetwork for models.providers[].request configuration [1 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#62147Fetched 2026-04-08 03:08:22
View on GitHub
Comments
0
Participants
1
Timeline
0
Reactions
0
Author
Participants

Add allowPrivateNetwork support to models.providers[].request configuration to enable LLM provider transport to access private/internal network endpoints.

Error Message

Error log: [agent/embedded] embedded run agent end: runId=xxx isError=true model=gpt-4o-mini provider=openai error=terminated rawError=terminated

Root Cause

When using a custom LLM provider with baseUrl pointing to a private network address (e.g., Docker internal network, Kubernetes service, or corporate internal API), OpenClaw's SSRF protection blocks the request because the hostname resolves to a private IP address (RFC1918 ranges: 10.x.x.x, 172.16-31.x.x, 192.168.x.x).

PR fix notes

PR #63671: feat(models): allow private network via models.providers.*.request

Description (problem / solution / changelog)

Add optional request.allowPrivateNetwork for operator-controlled self-hosted OpenAI-compatible bases (LAN/overlay/split DNS). Plumbs the flag into resolveProviderRequestPolicyConfig for streaming provider HTTP so fetchWithSsrFGuard can allow private-resolved model URLs when explicitly enabled. Embedded OpenAI Responses WebSocket uses the same request object (headers/TLS); it does not use the HTTP fetch SSRF stack.

Updates zod schema, config help/labels, unit tests for sanitize/merge, and threads provider request into the embedded WebSocket stream path (stream-resolution.ts).

Summary

Describe the problem and fix in 2–5 bullets:

If this PR fixes a plugin beta-release blocker, title it fix(<plugin-id>): beta blocker - <summary> and link the matching Beta blocker: <plugin-name> - <summary> issue labeled beta-blocker. Contributors cannot label PRs, so the title is the PR-side signal for maintainers and automation.

  • Problem: Operators using self-hosted OpenAI-compatible APIs whose baseUrl resolves to private/CGNAT addresses were blocked by default SSRF-style protections, with no config-level way to opt in per provider.
  • Why it matters: Legitimate LAN, split DNS, and overlay setups need an explicit, auditable switch; disabling SSRF globally is unsafe.
  • What changed: New optional models.providers.<id>.request.allowPrivateNetwork (sanitized/merged like other request fields), wired through resolveProviderRequestPolicyConfig into provider HTTP fetch so fetchWithSsrFGuard respects the flag when true. Embedded OpenAI Responses WebSocket receives the model’s request via managerOptions for headers/TLS continuity (not the same SSRF gate as HTTP). Shared ConfiguredProviderRequest still exposes this field on some non-model surfaces that do not forward request.allowPrivateNetwork yet — acknowledged in review; follow-up to narrow schema or wire those paths separately.
  • What did NOT change (scope boundary): Default behavior remains deny-private unless explicitly enabled; no broad SSRF relaxation beyond the provider request path described; unrelated providers/channels unchanged.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #62147
  • Related #
  • This PR fixes a bug or regression

Root Cause (if applicable)

For bug fixes or regressions, explain why this happened, not just what changed. Otherwise write N/A. If the cause is unclear, write Unknown.

  • Root cause: N/A (feature addition, not a regression fix).
  • Missing detection / guardrail: N/A
  • Contributing context (if known): N/A

Regression Test Plan (if applicable)

For bug fixes or regressions, name the smallest reliable test coverage that should catch this. Otherwise write N/A.

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: src/agents/provider-request-config.test.ts (sanitize + merge behavior for allowPrivateNetwork).
  • Scenario the test should lock in: Config values normalize to boolean; merge precedence matches other request fields; invalid values do not silently enable private network access.
  • Why this is the smallest reliable guardrail: Logic is centralized in provider request resolution; unit tests catch mis-merge/sanitize without needing live private endpoints.
  • Existing test that already covers this (if any): New/updated tests in provider-request-config.test.ts as listed above.
  • If no new test is added, why not: N/A — tests added/updated for sanitize/merge.

User-visible / Behavior Changes

List user-visible changes (including defaults/config).
If none, write None.

  • New optional config: models.providers.<providerId>.request.allowPrivateNetwork (boolean). When omitted or false, behavior matches prior defaults (private-resolved model URLs remain blocked by the HTTP fetch SSRF policy). When true, provider HTTP streaming can reach private-resolved model baseUrls via fetchWithSsrFGuard (operator opt-in). OpenAI Responses WebSocket uses the same request for handshake headers/TLS; it does not use that HTTP fetch SSRF path.

Diagram (if applicable)

For UI changes or non-trivial logic flows, include a small ASCII diagram reviewers can scan quickly. Otherwise write N/A.

N/A

Security Impact (required)

  • New permissions/capabilities? Yes — per-provider opt-in to relax SSRF policy for model baseUrl resolution to private addresses when explicitly set (HTTP fetch path).
  • Secrets/tokens handling changed? No
  • New/changed network calls? No new endpoints; same calls may be allowed to targets that were previously blocked when the flag is true.
  • Command/tool execution surface changed? No
  • Data access scope changed? No
  • If any Yes, explain risk + mitigation: Risk: misconfiguration could expose traffic to unintended private hosts. Mitigation: default remains off; flag is per-provider and must be set deliberately; operators should only enable for trusted self-hosted bases.

Repro + Verification

Environment

  • OS: (your OS)
  • Runtime/container: (e.g. devcontainer / local Node version matching engines)
  • Model/provider: Self-hosted OpenAI-compatible with baseUrl resolving to RFC1918/CGNAT (or your test harness).
  • Integration/channel (if any): N/A
  • Relevant config (redacted): models.providers.<id>.baseUrl + models.providers.<id>.request.allowPrivateNetwork: true

Steps

  1. Configure a provider with a private-resolved baseUrl and request.allowPrivateNetwork: true.
  2. Exercise model usage over provider HTTP streaming (the path that uses buildGuardedModelFetch / fetchWithSsrFGuard). Optionally exercise OpenAI Responses WebSocket; headers/TLS come from request, not the HTTP SSRF gate.
  3. Confirm HTTP traffic succeeds where it previously failed under default SSRF policy; with flag absent/false, behavior should match pre-change.

Expected

  • With flag true: model HTTP calls to a trusted private baseUrl succeed when DNS resolves privately (subject to the fetch guard).
  • With flag false/omitted: behavior unchanged from before this PR (private resolution still blocked by policy on HTTP fetch).

Actual

  • (Fill after you verify locally or rely on CI.)

Evidence

Attach at least one:

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

(Adjust checkboxes to what you attach.)

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios: Config parses; sanitize/merge unit tests; (add manual run if you did one).
  • Edge cases checked: Omitted flag, false, true; invalid inputs rejected or normalized per tests.
  • What you did not verify: Full E2E against a real private baseUrl in production-like network (if applicable).

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

If a bot review conversation is addressed by this PR, resolve that conversation yourself. Do not leave bot review conversation cleanup for maintainers.

Compatibility / Migration

  • Backward compatible? Yes — default unchanged when the new field is omitted.
  • Config/env changes? Yes — optional new field under models.providers.*.request.
  • Migration needed? No
  • If yes, exact upgrade steps: N/A

Risks and Mitigations

List only real risks for this PR. Add/remove entries as needed. If none, write None.

  • Risk: Operator sets allowPrivateNetwork on a provider whose baseUrl is not fully trusted, widening SSRF exposure to internal networks.
    • Mitigation: Document as operator-only; default off; pair with network controls and trusted baseUrl where possible.

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • docs/gateway/configuration-reference.md (modified, +1/-0)
  • src/agents/openai-ws-connection.ts (modified, +4/-3)
  • src/agents/openai-ws-stream.test.ts (modified, +81/-0)
  • src/agents/openai-ws-stream.ts (modified, +37/-0)
  • src/agents/pi-embedded-runner/stream-resolution.ts (modified, +4/-0)
  • src/agents/provider-request-config.test.ts (modified, +31/-0)
  • src/agents/provider-request-config.ts (modified, +38/-7)
  • src/agents/provider-transport-fetch.ts (modified, +3/-1)
  • src/config/schema.base.generated.ts (modified, +13/-2)
  • src/config/schema.help.ts (modified, +3/-1)
  • src/config/schema.labels.ts (modified, +1/-0)
  • src/config/schema.test.ts (modified, +20/-0)
  • src/config/types.provider-request.ts (modified, +3/-1)
  • src/config/zod-schema.core.ts (modified, +14/-6)
  • src/plugins/runtime/model-auth-types.ts (modified, +2/-2)
  • src/plugins/types.ts (modified, +2/-2)

Code Example

[agent/embedded] embedded run agent end: runId=xxx isError=true model=gpt-4o-mini provider=openai error=terminated rawError=terminated

---

{
  "models": {
    "providers": {
      "openai": {
        "baseUrl": "http://internal-proxy:8000/v1",
        "apiKey": "xxx",
        "request": {
          "allowPrivateNetwork": true
        }
      }
    }
  }
}
RAW_BUFFERClick to expand / collapse

Summary

Add allowPrivateNetwork support to models.providers[].request configuration to enable LLM provider transport to access private/internal network endpoints.

Problem to solve

When using a custom LLM provider with baseUrl pointing to a private network address (e.g., Docker internal network, Kubernetes service, or corporate internal API), OpenClaw's SSRF protection blocks the request because the hostname resolves to a private IP address (RFC1918 ranges: 10.x.x.x, 172.16-31.x.x, 192.168.x.x).

Current behavior:

  • Provider baseUrl: "http://openclaw-fleet:8000/proxy/...
  • Hostname resolves to 172.21.6.2 (Docker internal network)
  • SSRF guard throws SsrFBlockedError: Blocked: resolves to private/internal/special-use IP address
  • No configuration option to allow this

Error log:

[agent/embedded] embedded run agent end: runId=xxx isError=true model=gpt-4o-mini provider=openai error=terminated rawError=terminated

Proposed solution

Add allowPrivateNetwork option to ConfiguredModelProviderRequest (or ProviderRequestTransportOverrides) and wire it through to the SSRF guard in buildGuardedModelFetch.

Configuration example:

{
  "models": {
    "providers": {
      "openai": {
        "baseUrl": "http://internal-proxy:8000/v1",
        "apiKey": "xxx",
        "request": {
          "allowPrivateNetwork": true
        }
      }
    }
  }
}

Code changes needed:

  1. Add allowPrivateNetwork?: boolean to ProviderRequestTransportOverrides type
  2. Update resolveModelRequestPolicy to pass allowPrivateNetwork from model request config
  3. Ensure buildGuardedModelFetch uses allowPrivateNetwork in SSRF policy

Alternatives considered

  • Use public IP addresses — defeats the purpose of internal deployments, adds latency
  • Add hostname to allowedHostnames — requires code change per deployment

Impact

  • Enables Fleet-style proxy architecture where OpenClaw connects to a local proxy via Docker internal network
  • Supports on-prem deployments with internal LLM gateways
  • Backward compatible: defaults to false, preserving existing SSRF protection

Additional information

Related issues:

  • #53469 — Private network access for web tools
  • #56920 — Custom inference servers

This is a blocker for Fleet's proxy architecture where OpenClaw instances need to connect to the Fleet Manager proxy via Docker internal network.

extent analysis

TL;DR

Add the allowPrivateNetwork option to the models.providers[].request configuration to enable access to private network endpoints.

Guidance

  • Update the ProviderRequestTransportOverrides type to include the allowPrivateNetwork option as a boolean.
  • Modify the resolveModelRequestPolicy function to pass the allowPrivateNetwork value from the model request configuration.
  • Ensure the buildGuardedModelFetch function uses the allowPrivateNetwork value in the SSRF policy to allow or block requests to private networks.
  • Configure the allowPrivateNetwork option to true in the model provider configuration, as shown in the proposed solution's configuration example.

Example

{
  "models": {
    "providers": {
      "openai": {
        "baseUrl": "http://internal-proxy:8000/v1",
        "apiKey": "xxx",
        "request": {
          "allowPrivateNetwork": true
        }
      }
    }
  }
}

Notes

This solution assumes that the allowPrivateNetwork option is added to the correct configuration and code files, and that the SSRF guard is properly updated to use this option.

Recommendation

Apply the workaround by adding the allowPrivateNetwork option to the model provider configuration and updating the relevant code files, as this will enable access to private network endpoints while maintaining existing SSRF protection.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING