Skip to content

fix(blueprint): default OpenClaw fetch guard to sandbox proxy - #5713

Merged
cv merged 13 commits into
mainfrom
fix/openclaw-fetch-guard-default-proxy
Jun 30, 2026
Merged

fix(blueprint): default OpenClaw fetch guard to sandbox proxy#5713
cv merged 13 commits into
mainfrom
fix/openclaw-fetch-guard-default-proxy

Conversation

@sandl99

@sandl99 sandl99 commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

Summary

Broadens the OpenClaw compatibility patch so resolveGuardedFetchMode() defaults omitted guarded-fetch modes to trusted_env_proxy inside OpenShell sandboxes. This avoids local DNS lookups for bare fetchWithSsrFGuard callers while preserving explicit modes and strict behavior outside OPENSHELL_SANDBOX=1.

Related Issue

Related: #396 (fetch-guard/local DNS portion only; Gemini policy/docs remain out of scope)
Fixes #4687
Related: #5129
Related: #5592

Changes

  • Patch OpenClaw's central guarded-fetch mode resolver in the sandbox image instead of rewriting individual call sites.
  • Remove the deprecated proxy: "env" compatibility branch from the patched resolver and drop the old cron-preflight call-site patch.
  • Cover additional bare fetchWithSsrFGuard users, including the Mattermost/OpenClaw call site discussed in feat(messaging): onboard Mattermost for OpenClaw #5592.
  • Update fetch-guard patch regression tests for sandbox defaults, explicit-mode precedence, out-of-sandbox strict behavior, and removal of the narrower Patch 6 rewrite.

Localized compatibility patch review

  • Invalid state: OpenClaw 2026.5.27 resolves an omitted guarded-fetch mode to strict DNS pinning. In an OpenShell proxy-only sandbox, that performs local DNS before proxy dispatch, so sandbox-only and proxy-routed names fail before policy enforcement.
  • Source boundary: NemoClaw consumes the pinned compiled OpenClaw distribution in the sandbox image; it does not own the upstream resolver source. The image build therefore classifies and patches the reviewed resolveGuardedFetchMode() shape centrally and fails closed if that shape drifts.
  • Source-fix constraint: The durable fix belongs in OpenClaw: either select trusted_env_proxy for OpenShell sandboxes at the resolver boundary or make every sandbox-sensitive caller pass that mode explicitly. A permanent NemoClaw fork of the third-party runtime is out of scope.
  • Regression proof: test/fetch-guard-patch-regression.test.ts verifies the reviewed resolver shape, explicit-mode precedence, sandbox-only default, strict behavior outside the sandbox, removal of the deprecated opt-in, representative SSRF denials, and fail-closed drift handling. The exact merged head passes all 23 focused tests.
  • Removal condition: Remove Patch 4 when the pinned OpenClaw release provides an equivalent OpenShell-aware default, or when every sandbox-sensitive caller explicitly selects trusted proxy mode and the runtime acceptance checks pass without this patch.

Security boundary and E2E

Inspection of the pinned OpenClaw 2026.5.27 implementation confirms that explicit modes still override the default, hostname validation runs before proxy dispatcher construction, loopback/metadata/private/special-use IPv4 and IPv6 literals remain rejected, and redirects are handled manually and revalidated on each hop. DNS-resolution enforcement intentionally moves to the OpenShell L7 proxy and network-policy boundary only for omitted-mode calls inside the sandbox.

A unified exact-head E2E dispatch covers cron-preflight-inference-local, inference-routing, network-policy, and common-egress-agent: https://github.com/NVIDIA/NemoClaw/actions/runs/28424214692

Type of Change

  • Code change (feature, bug fix, or refactor)
  • Code change with doc updates
  • Doc only (prose changes, no code sample modifications)
  • Doc only (includes code sample changes)

Verification

  • PR description includes the DCO sign-off declaration and every commit appears as Verified in GitHub
  • Normal commit and push hooks passed on the current head
  • Targeted test passes: 23/23
  • Tests added or updated for changed behavior
  • No secrets, API keys, or credentials committed
  • Exact-head unified E2E is passing (in progress)

Signed-off-by: San Dang sdang@nvidia.com

Signed-off-by: San Dang <sdang@nvidia.com>
@sandl99 sandl99 self-assigned this Jun 24, 2026
@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Dockerfile Patch 4 is rewritten to target resolveGuardedFetchMode() in the compiled OpenClaw dist: the deprecated params.proxy === "env" / dangerouslyAllowEnvProxyWithoutPinnedDns opt-in branch is deleted, and the STRICT fallback is changed to return TRUSTED_ENV_PROXY when OPENSHELL_SANDBOX=1. The regression test suite is updated to validate the new patched shape and sandbox-conditional behavior.

Changes

Patch 4: resolveGuardedFetchMode sandbox default

Layer / File(s) Summary
Patch 4 intent and removal criteria
Dockerfile
Patch 4 comments are updated to describe the new resolveGuardedFetchMode() defaulting behavior and revised removal criteria for bare guarded fetches in the sandbox.
Dockerfile Patch 4 patching script rewrite
Dockerfile
The Patch 4 patching script is replaced to edit resolveGuardedFetchMode(), remove the deprecated env-proxy opt-in logic, and make the STRICT fallback return TRUSTED_ENV_PROXY when OPENSHELL_SANDBOX=1.
Reviewed guarded-mode fixture and contract anchors
test/fetch-guard-patch-regression.test.ts
The reviewed guarded-mode shape, web-fetch anchors, and Patch 4 fixture are updated to match the new resolver shape and preserve an unrelated legacy params.proxy === "env" literal.
Patch 4 regression assertions
test/fetch-guard-patch-regression.test.ts
Patch 4 tests now cover sandbox-conditional omitted mode, unchanged cron preflight callsites, the “not needed” path, and fail-closed stderr output.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇 Hop hop, the sandbox knows its way,
Old env-proxy tricks have hopped away.
With OPENSHELL_SANDBOX set to one,
TRUSTED_ENV_PROXY is the run.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: defaulting OpenClaw's fetch guard to the sandbox proxy.
Linked Issues check ✅ Passed The patch addresses #4687 by routing omitted guarded fetches through the sandbox proxy, which should restore cert fetches inside NemoClaw.
Out of Scope Changes check ✅ Passed The changes stay focused on the guarded-fetch resolver and its tests, with no clear unrelated code introduced.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/openclaw-fetch-guard-default-proxy

Comment @coderabbitai help to get the list of available commands.

@github-code-quality

github-code-quality Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Overview

Languages: TypeScript

TypeScript / code-coverage/plugin

The overall coverage in the fix/openclaw-fetch-g... branch is 96%. Coverage data for the main branch is not yet available.

Show a code coverage summary of the most covered files.
File main fix/openclaw-fetch-g... f963d82 +/-
nemoclaw/src/se...cret-scanner.ts 100%
nemoclaw/src/commands/slash.ts 100%
nemoclaw/src/li...bprocess-env.ts 100%
nemoclaw/src/bl...eprint/state.ts 98%
nemoclaw/src/onboard/config.ts 98%
nemoclaw/src/bl...int/snapshot.ts 97%
nemoclaw/src/bl...print/runner.ts 95%
nemoclaw/src/co...ration-state.ts 94%
nemoclaw/src/bl...ate-networks.ts 94%
nemoclaw/src/index.ts 94%

TypeScript / code-coverage/cli

The overall coverage in the fix/openclaw-fetch-g... branch is 67%. Coverage data for the main branch is not yet available.

Show a code coverage summary of the most covered files.
File main fix/openclaw-fetch-g... f963d82 +/-
src/lib/actions...all/run-plan.ts 80%
src/lib/state/o...oard-session.ts 79%
src/lib/sandbox/config.ts 75%
src/lib/actions...dbox/rebuild.ts 74%
src/lib/state/sandbox.ts 72%
src/lib/onboard/preflight.ts 69%
src/lib/actions...licy-channel.ts 60%
src/lib/onboard...er-gpu-patch.ts 59%
src/lib/policy/index.ts 52%
src/lib/onboard.ts 20%

Updated June 30, 2026 07:40 UTC
Code Coverage is in Public Preview. Learn more and provide us with your feedback.

@github-actions

github-actions Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

E2E Advisor Recommendation

Required E2E: test-e2e-sandbox, cloud-onboard, network-policy, cron-preflight-inference-local
Optional E2E: cloud-inference, issue-4434-tui-unreachable-inference, inference-routing

Dispatch hint: cloud-onboard,network-policy,cron-preflight-inference-local

Workflow run

Full advisor summary

E2E Recommendation Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E

  • test-e2e-sandbox (medium): Builds the production sandbox image from the changed Dockerfile and runs the in-image sandbox E2E suite, catching Dockerfile patch/verifier failures and image-level runtime regressions.
  • cloud-onboard (high): Exercises the public installer and full hosted OpenClaw onboarding path that uses the optimized build context and changed Dockerfile, then verifies a healthy sandbox, inference.local, and security checks.
  • network-policy (high): Required because the PR changes OpenClaw fetch-guard proxy/SSRF behavior. This live test validates sandbox network policy allow/deny, inference.local exemption, SSRF private-address rejection, and web_fetch host-gateway behavior in a real OpenShell sandbox.
  • cron-preflight-inference-local (medium): Required because the PR removes the previous cron-specific preflight patch and replaces it with a central guarded-fetch mode default. This verifies cron preflight still reaches inference.local through the sandbox proxy without local DNS pinning.

Optional E2E

  • cloud-inference (medium): Useful adjacent confidence for live inference.local chat completion and sandbox filesystem validation after the OpenClaw fetch-guard and image-build changes.
  • issue-4434-tui-unreachable-inference (high): Useful for TUI/assistant-runtime confidence because it drives OpenClaw TUI inside the sandbox under constrained inference egress, an adjacent path to the changed proxy/fetch behavior.
  • inference-routing (medium): Useful adjacent coverage for provider routing and inference error classification, but less direct than cloud-onboard, network-policy, and cron-preflight for this Dockerfile fetch-guard patch.

New E2E recommendations

  • Google Chat inbound certificate fetch proxy path (medium): The new build-time verifier simulates the Google Chat certificate fetch through the patched fetch guard, but there does not appear to be an existing live E2E that exercises a real OpenClaw Google Chat inbound webhook/certificate-validation path inside an OpenShell sandbox.
    • Suggested test: Add a Google Chat inbound auth/certificate-fetch E2E that proves certificate retrieval routes through the sandbox L7 proxy without local DNS while preserving SSRF redirect denial.

Dispatch hint

  • Workflow: .github/workflows/e2e.yaml
  • jobs input: cloud-onboard,network-policy,cron-preflight-inference-local

@github-actions

github-actions Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Vitest E2E Scenario Recommendation

Required Vitest E2E scenarios: cron-preflight-inference-local-vitest, network-policy-vitest
Optional Vitest E2E scenarios: common-egress-agent-vitest

Dispatch required Vitest E2E scenarios:

  • gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field jobs=cron-preflight-inference-local-vitest
  • gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field jobs=network-policy-vitest

Workflow run

Full Vitest E2E advisor summary

Vitest E2E Scenario Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required Vitest E2E scenarios

  • cron-preflight-inference-local-vitest: The Dockerfile changes the OpenClaw fetch-guard patch so omitted guarded-fetch modes default to trusted_env_proxy inside OpenShell sandboxes and removes the cron-specific preflight patch. This job directly exercises the in-sandbox cron model-provider preflight against inference.local and verifies it avoids EAI_AGAIN.
    • Dispatch: gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field jobs=cron-preflight-inference-local-vitest
  • network-policy-vitest: The fetch-guard default-mode change affects sandbox proxy routing and SSRF enforcement. This job covers live network-policy behavior including inference.local exemption, private-address SSRF rejection, and OpenClaw web_fetch host-gateway allow/deny semantics.
    • Dispatch: gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field jobs=network-policy-vitest

Optional Vitest E2E scenarios

  • common-egress-agent-vitest: Adjacent coverage for real OpenClaw agent web_fetch/common-egress paths through the sandbox proxy. Useful if extra confidence is needed for broader agent fetch behavior beyond the cron and SSRF-policy targets.
    • Dispatch: gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field jobs=common-egress-agent-vitest

Relevant changed files

  • Dockerfile

@github-actions

github-actions Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor — Changes requested

Merge posture: Do not merge yet
Primary next action: Fix PRA-3: Google Chat receive-path acceptance is only proven at the lower fetch-guard layer; then add or justify PRA-T1.
Open items: 1 required · 2 warnings · 0 suggestions · 8 test follow-ups
Since last review: 0 prior items resolved · 1 still applies · 1 new item found

Action checklist

  • PRA-3 Fix: Google Chat receive-path acceptance is only proven at the lower fetch-guard layer in scripts/verify-openclaw-fetch-guard-runtime.ts:133
  • PRA-1 Resolve or justify: Source-of-truth review needed: Dockerfile Patch 4 compiled OpenClaw resolver rewrite
  • PRA-2 Resolve or justify: Compiled runtime verifier still accepts any dispatcher in scripts/verify-openclaw-fetch-guard-runtime.ts:157
  • PRA-T1 Add or justify test follow-up: Runtime validation
  • PRA-T2 Add or justify test follow-up: Runtime validation
  • PRA-T3 Add or justify test follow-up: Runtime validation
  • PRA-T4 Add or justify test follow-up: Acceptance clause
  • PRA-T5 Add or justify test follow-up: Acceptance clause
  • PRA-T6 Add or justify test follow-up: Acceptance clause
  • PRA-T7 Add or justify test follow-up: Acceptance clause
  • PRA-T8 Add or justify test follow-up: Acceptance clause

Findings index

ID Severity Category Location Required action
PRA-1 Resolve/justify architecture Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
PRA-2 Resolve/justify security scripts/verify-openclaw-fetch-guard-runtime.ts:157 Strengthen the compiled verifier to assert a stable env-proxy signal, such as the expected `EnvHttpProxyAgent` constructor/class name or another reliable marker on OpenClaw's created dispatcher. While updating this verifier, add direct initial-URL coverage for `http://169.254.169.254/\` if the compiled runtime can expose that path.
PRA-3 Required acceptance scripts/verify-openclaw-fetch-guard-runtime.ts:133 Add a secret-free receive-path validation or identify an existing in-repo test that invokes the Google Chat webhook/JWT verification path far enough to prove signing-cert retrieval reaches the patched fetch guard and proceeds past certificate fetch. Keep external real-Google-message E2E evidence out of the code-review surface; a deterministic fixture/mocked cert response is sufficient for this PR.

🚨 Required before merge

Address these before merging unless a maintainer explicitly overrides the advisor with rationale.

PRA-3 Required — Google Chat receive-path acceptance is only proven at the lower fetch-guard layer

  • Location: scripts/verify-openclaw-fetch-guard-runtime.ts:133
  • Category: acceptance
  • Problem: The linked issue's user-visible acceptance is that inbound `@openclaw/googlechat` webhook JWT verification can fetch signing certificates and proceed instead of rejecting every message. The diff validates the compiled `fetchWithSsrFGuard` path for the Google Chat cert URL, but no changed test installs or loads the Google Chat plugin, configures a channel, or simulates the inbound JWT verification path.
  • Impact: The lower-level cert-fetch prerequisite may be fixed while the actual Google Chat receive path still fails due to plugin wiring, bundled dependency behavior, channel configuration, or a different dispatcher-policy branch. That would leave `Fixes @openclaw/googlechat cert fetch fails: SSRF guard's per-request dispatcher bypasses NemoClaw's nemoclaw-http-proxy-fix.js global-agent hook #4687` partially unverified for the behavior users reported.
  • Required action: Add a secret-free receive-path validation or identify an existing in-repo test that invokes the Google Chat webhook/JWT verification path far enough to prove signing-cert retrieval reaches the patched fetch guard and proceeds past certificate fetch. Keep external real-Google-message E2E evidence out of the code-review surface; a deterministic fixture/mocked cert response is sufficient for this PR.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Inspect the changed tests listed in `test/fetch-guard-patch-regression.test.ts` and `test/sandbox-build-context.test.ts`: they exercise Dockerfile patch fixtures, the resolver, SSRF denials, cron preflight fixture behavior, and build-context staging, but none installs `@openclaw/googlechat` or calls its inbound webhook/JWT verification code.
  • Missing regression test: Add `secret-free @openclaw/googlechat inbound JWT verification reaches signing-cert retrieval through patched fetch guard and proceeds past cert fetch`, using a local fixture or mocked certificate response with no service-account secrets.
  • Done when: The required change is committed and verification passes: Inspect the changed tests listed in `test/fetch-guard-patch-regression.test.ts` and `test/sandbox-build-context.test.ts`: they exercise Dockerfile patch fixtures, the resolver, SSRF denials, cron preflight fixture behavior, and build-context staging, but none installs `@openclaw/googlechat` or calls its inbound webhook/JWT verification code.
  • Evidence: `scripts/verify-openclaw-fetch-guard-runtime.ts:133-151` calls `fetchWithSsrFGuard` directly for `GOOGLE_CHAT_CERT_URL`; the acceptance issue describes the plugin receive/JWT verification path rejecting inbound messages before replying.
Review findings by urgency: 1 required fix, 2 items to resolve/justify, 0 in-scope improvements

⚠️ Resolve or justify before merge

Investigate these in the current review; either fix them, explain why they are not applicable, or document the accepted risk.

PRA-1 Resolve/justify — Source-of-truth review needed: Dockerfile Patch 4 compiled OpenClaw resolver rewrite

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Fixture tests cover the reviewed resolver shape, sandbox-only omitted-mode default, explicit-mode precedence, caller-owned dispatcher policies, strict behavior outside the sandbox, deprecated opt-in removal, representative SSRF denials, and fail-closed drift handling. The new compiled verifier imports the patched dist, but its env-proxy dispatcher assertion is still too weak.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: `Dockerfile` rewrites `resolveGuardedFetchMode(params)` and verifies the patch marker; `test/fetch-guard-patch-regression.test.ts` covers resolver behavior and fail-closed drift. Follow-up is needed because `scripts/verify-openclaw-fetch-guard-runtime.ts:157` only checks for any dispatcher name.

PRA-2 Resolve/justify — Compiled runtime verifier still accepts any dispatcher

  • Location: scripts/verify-openclaw-fetch-guard-runtime.ts:157
  • Category: security
  • Problem: The new build-time verifier imports the patched compiled OpenClaw fetch guard, but `verifyGoogleCertProxyPath()` only records `init?.dispatcher?.constructor?.name ?? ""` and asserts that it is non-empty. That proves the fetch avoided local DNS and received some dispatcher, but it does not prove Patch 4 selected the intended env-proxy dispatcher from the configured proxy environment.
  • Impact: Patch 4 moves omitted-mode sandbox fetches from strict local DNS pinning to the trusted-env-proxy/OpenShell egress boundary. If a future OpenClaw dist shape constructs a non-env-proxy dispatcher while still skipping local DNS, this verifier could pass even though the runtime no longer uses the intended sandbox egress trust boundary or the Google Chat cert-fetch path regresses.
  • Recommended action: Strengthen the compiled verifier to assert a stable env-proxy signal, such as the expected `EnvHttpProxyAgent` constructor/class name or another reliable marker on OpenClaw's created dispatcher. While updating this verifier, add direct initial-URL coverage for `http://169.254.169.254/\` if the compiled runtime can expose that path.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read `scripts/verify-openclaw-fetch-guard-runtime.ts` around `verifyGoogleCertProxyPath()`: it assigns `dispatcherName = init?.dispatcher?.constructor?.name ?? ""` and then only calls `assert.ok(dispatcherName, ...)`. Confirm `Dockerfile` invokes `/usr/local/lib/nemoclaw/verify-openclaw-fetch-guard-runtime.mjs` after patching the compiled OpenClaw dist.
  • Missing regression test: Update the build-time verifier behavior so `compiled omitted googlechat cert fetch uses the OpenClaw EnvHttpProxyAgent from HTTPS_PROXY without local DNS` fails if `fetchImpl` receives any dispatcher other than the expected env-proxy dispatcher. Add `compiled omitted-mode trusted-env-proxy fetch rejects direct http://169.254.169.254/ before fetch and before local DNS` unless an equivalent compiled-runtime check is added elsewhere.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read `scripts/verify-openclaw-fetch-guard-runtime.ts` around `verifyGoogleCertProxyPath()`: it assigns `dispatcherName = init?.dispatcher?.constructor?.name ?? ""` and then only calls `assert.ok(dispatcherName, ...)`. Confirm `Dockerfile` invokes `/usr/local/lib/nemoclaw/verify-openclaw-fetch-guard-runtime.mjs` after patching the compiled OpenClaw dist.
  • Evidence: `scripts/verify-openclaw-fetch-guard-runtime.ts:141-157` checks the Google Chat cert URL, manual redirect, one fetch call, zero lookup calls, and a non-empty dispatcher constructor name, but it does not compare the dispatcher to an env-proxy-specific marker.

💡 In-scope improvements

These are lower-risk, not throwaway. Prefer fixing them in this PR when they are local to changed code; defer only with rationale or a linked follow-up.

  • None.
Test follow-ups to resolve or justify

If these cover changed behavior, prefer adding them in this PR; otherwise state why existing coverage is enough or link the follow-up.

  • PRA-T1 Runtime validation — compiled omitted googlechat cert fetch uses the OpenClaw EnvHttpProxyAgent from HTTPS_PROXY without local DNS. This PR changes Dockerfile patching of a compiled third-party runtime at the sandbox SSRF/proxy boundary. The fixture tests are broad and useful, and the build-time compiled verifier is the right layer, but the exact dispatcher assertion and Google Chat receive-path acceptance need stronger behavioral validation.
  • PRA-T2 Runtime validation — compiled omitted-mode trusted-env-proxy fetch rejects direct http://169.254.169.254/ before fetch and before local DNS. This PR changes Dockerfile patching of a compiled third-party runtime at the sandbox SSRF/proxy boundary. The fixture tests are broad and useful, and the build-time compiled verifier is the right layer, but the exact dispatcher assertion and Google Chat receive-path acceptance need stronger behavioral validation.
  • PRA-T3 Runtime validation — secret-free @openclaw/googlechat inbound JWT verification reaches signing-cert retrieval through patched fetch guard and proceeds past cert fetch. This PR changes Dockerfile patching of a compiled third-party runtime at the sandbox SSRF/proxy boundary. The fixture tests are broad and useful, and the build-time compiled verifier is the right layer, but the exact dispatcher assertion and Google Chat receive-path acceptance need stronger behavioral validation.
  • PRA-T4 Acceptance clause — The `@openclaw/googlechat` plugin's JWT verification step fails every time inside a NemoClaw sandbox, with the gateway log line: ``` [googlechat] [default] Google Chat webhook auth rejected: Failed to retrieve verification certificates: fetch failed ``` — add test evidence or identify existing coverage. The new compiled-runtime verifier calls `fetchWithSsrFGuard` for the Google Chat signing-cert URL under `OPENSHELL_SANDBOX=1` with proxy env configured, but it does not invoke the actual `@openclaw/googlechat` JWT verification path that emits the gateway log.
  • PRA-T5 Acceptance clause — This blocks every inbound Google Chat message — the bot receives Google's signed POST, tries to verify the JWT, can't fetch the signing certs, and rejects the request before replying. — add test evidence or identify existing coverage. The cert-fetch prerequisite is covered at the compiled fetch-guard layer; no changed test simulates an inbound signed Google Chat POST or verifies that webhook handling proceeds past certificate retrieval.
  • PRA-T6 Acceptance clause — Reproducible across NemoClaw v0.0.56 with OpenClaw 2026.5.22, and the same code path exists unchanged in `@openclaw/googlechat@2026.5.28` (current npm `latest`). — add test evidence or identify existing coverage. The Dockerfile patches the pinned runtime target `OPENCLAW_VERSION=2026.5.27`, and tests retain reviewed classifier versions including `2026.5.22` and `2026.5.27`; no changed test exercises the Google Chat plugin version range through `2026.5.28`.
  • PRA-T7 Acceptance clause — 1. Install `@openclaw/googlechat` into a NemoClaw sandbox (any version in 2026.5.22–2026.5.28). — add test evidence or identify existing coverage. No changed test installs or loads `@openclaw/googlechat`; the evidence is limited to the compiled OpenClaw fetch-guard module and Dockerfile patch fixtures.
  • PRA-T8 Acceptance clause — 2. Configure the channel with a valid service account, an audience URL, and route Google Chat at the registered webhook URL. — add test evidence or identify existing coverage. No changed test configures a Google Chat channel, service account, audience, or webhook route. A secret-free fixture could cover this path, but it is not present in the diff.
Since last review details

Current findings, using the urgency labels above:

PRA-1 Resolve/justify — Source-of-truth review needed: Dockerfile Patch 4 compiled OpenClaw resolver rewrite

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Fixture tests cover the reviewed resolver shape, sandbox-only omitted-mode default, explicit-mode precedence, caller-owned dispatcher policies, strict behavior outside the sandbox, deprecated opt-in removal, representative SSRF denials, and fail-closed drift handling. The new compiled verifier imports the patched dist, but its env-proxy dispatcher assertion is still too weak.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: `Dockerfile` rewrites `resolveGuardedFetchMode(params)` and verifies the patch marker; `test/fetch-guard-patch-regression.test.ts` covers resolver behavior and fail-closed drift. Follow-up is needed because `scripts/verify-openclaw-fetch-guard-runtime.ts:157` only checks for any dispatcher name.

PRA-2 Resolve/justify — Compiled runtime verifier still accepts any dispatcher

  • Location: scripts/verify-openclaw-fetch-guard-runtime.ts:157
  • Category: security
  • Problem: The new build-time verifier imports the patched compiled OpenClaw fetch guard, but `verifyGoogleCertProxyPath()` only records `init?.dispatcher?.constructor?.name ?? ""` and asserts that it is non-empty. That proves the fetch avoided local DNS and received some dispatcher, but it does not prove Patch 4 selected the intended env-proxy dispatcher from the configured proxy environment.
  • Impact: Patch 4 moves omitted-mode sandbox fetches from strict local DNS pinning to the trusted-env-proxy/OpenShell egress boundary. If a future OpenClaw dist shape constructs a non-env-proxy dispatcher while still skipping local DNS, this verifier could pass even though the runtime no longer uses the intended sandbox egress trust boundary or the Google Chat cert-fetch path regresses.
  • Recommended action: Strengthen the compiled verifier to assert a stable env-proxy signal, such as the expected `EnvHttpProxyAgent` constructor/class name or another reliable marker on OpenClaw's created dispatcher. While updating this verifier, add direct initial-URL coverage for `http://169.254.169.254/\` if the compiled runtime can expose that path.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read `scripts/verify-openclaw-fetch-guard-runtime.ts` around `verifyGoogleCertProxyPath()`: it assigns `dispatcherName = init?.dispatcher?.constructor?.name ?? ""` and then only calls `assert.ok(dispatcherName, ...)`. Confirm `Dockerfile` invokes `/usr/local/lib/nemoclaw/verify-openclaw-fetch-guard-runtime.mjs` after patching the compiled OpenClaw dist.
  • Missing regression test: Update the build-time verifier behavior so `compiled omitted googlechat cert fetch uses the OpenClaw EnvHttpProxyAgent from HTTPS_PROXY without local DNS` fails if `fetchImpl` receives any dispatcher other than the expected env-proxy dispatcher. Add `compiled omitted-mode trusted-env-proxy fetch rejects direct http://169.254.169.254/ before fetch and before local DNS` unless an equivalent compiled-runtime check is added elsewhere.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read `scripts/verify-openclaw-fetch-guard-runtime.ts` around `verifyGoogleCertProxyPath()`: it assigns `dispatcherName = init?.dispatcher?.constructor?.name ?? ""` and then only calls `assert.ok(dispatcherName, ...)`. Confirm `Dockerfile` invokes `/usr/local/lib/nemoclaw/verify-openclaw-fetch-guard-runtime.mjs` after patching the compiled OpenClaw dist.
  • Evidence: `scripts/verify-openclaw-fetch-guard-runtime.ts:141-157` checks the Google Chat cert URL, manual redirect, one fetch call, zero lookup calls, and a non-empty dispatcher constructor name, but it does not compare the dispatcher to an env-proxy-specific marker.

PRA-3 Required — Google Chat receive-path acceptance is only proven at the lower fetch-guard layer

  • Location: scripts/verify-openclaw-fetch-guard-runtime.ts:133
  • Category: acceptance
  • Problem: The linked issue's user-visible acceptance is that inbound `@openclaw/googlechat` webhook JWT verification can fetch signing certificates and proceed instead of rejecting every message. The diff validates the compiled `fetchWithSsrFGuard` path for the Google Chat cert URL, but no changed test installs or loads the Google Chat plugin, configures a channel, or simulates the inbound JWT verification path.
  • Impact: The lower-level cert-fetch prerequisite may be fixed while the actual Google Chat receive path still fails due to plugin wiring, bundled dependency behavior, channel configuration, or a different dispatcher-policy branch. That would leave `Fixes @openclaw/googlechat cert fetch fails: SSRF guard's per-request dispatcher bypasses NemoClaw's nemoclaw-http-proxy-fix.js global-agent hook #4687` partially unverified for the behavior users reported.
  • Required action: Add a secret-free receive-path validation or identify an existing in-repo test that invokes the Google Chat webhook/JWT verification path far enough to prove signing-cert retrieval reaches the patched fetch guard and proceeds past certificate fetch. Keep external real-Google-message E2E evidence out of the code-review surface; a deterministic fixture/mocked cert response is sufficient for this PR.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Inspect the changed tests listed in `test/fetch-guard-patch-regression.test.ts` and `test/sandbox-build-context.test.ts`: they exercise Dockerfile patch fixtures, the resolver, SSRF denials, cron preflight fixture behavior, and build-context staging, but none installs `@openclaw/googlechat` or calls its inbound webhook/JWT verification code.
  • Missing regression test: Add `secret-free @openclaw/googlechat inbound JWT verification reaches signing-cert retrieval through patched fetch guard and proceeds past cert fetch`, using a local fixture or mocked certificate response with no service-account secrets.
  • Done when: The required change is committed and verification passes: Inspect the changed tests listed in `test/fetch-guard-patch-regression.test.ts` and `test/sandbox-build-context.test.ts`: they exercise Dockerfile patch fixtures, the resolver, SSRF denials, cron preflight fixture behavior, and build-context staging, but none installs `@openclaw/googlechat` or calls its inbound webhook/JWT verification code.
  • Evidence: `scripts/verify-openclaw-fetch-guard-runtime.ts:133-151` calls `fetchWithSsrFGuard` directly for `GOOGLE_CHAT_CERT_URL`; the acceptance issue describes the plugin receive/JWT verification path rejecting inbound messages before replying.

Workflow run details

This is an automated, non-binding review; it still expects maintainers and agents to respond to each required or warning item. Treat suggestions as current-PR improvements when they touch changed code; defer only with maintainer rationale or a linked follow-up. A human maintainer must make the final merge decision.

sandl99 added 3 commits June 24, 2026 12:39
Signed-off-by: San Dang <sdang@nvidia.com>
Signed-off-by: San Dang <sdang@nvidia.com>
Signed-off-by: San Dang <sdang@nvidia.com>
@sandl99 sandl99 added area: security Security controls, permissions, secrets, or hardening integration: openclaw OpenClaw integration behavior bug labels Jun 24, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Selective E2E Results — ❌ Some jobs failed

Run: 28182597555
Target ref: fix/openclaw-fetch-guard-default-proxy
Requested jobs: cron-preflight-inference-local-e2e,messaging-compatible-endpoint-e2e,network-policy-e2e,common-egress-agent-e2e,cloud-onboard-e2e,cloud-inference-e2e,sandbox-operations-e2e,openclaw-tui-chat-correlation-e2e
Summary: 7 passed, 1 failed, 0 cancelled, 0 skipped

Job Result
cloud-inference-e2e ✅ success
cloud-onboard-e2e ✅ success
common-egress-agent-e2e ❌ failure
cron-preflight-inference-local-e2e ✅ success
messaging-compatible-endpoint-e2e ✅ success
network-policy-e2e ✅ success
openclaw-tui-chat-correlation-e2e ✅ success
sandbox-operations-e2e ✅ success

Failed jobs: common-egress-agent-e2e. Check run artifacts for logs.

@github-actions

Copy link
Copy Markdown
Contributor

Selective E2E Results — ✅ All requested jobs passed

Run: 28182597555
Target ref: fix/openclaw-fetch-guard-default-proxy
Requested jobs: cron-preflight-inference-local-e2e,messaging-compatible-endpoint-e2e,network-policy-e2e,common-egress-agent-e2e,cloud-onboard-e2e,cloud-inference-e2e,sandbox-operations-e2e,openclaw-tui-chat-correlation-e2e
Summary: 8 passed, 0 failed, 0 cancelled, 0 skipped

Job Result
cloud-inference-e2e ✅ success
cloud-onboard-e2e ✅ success
common-egress-agent-e2e ✅ success
cron-preflight-inference-local-e2e ✅ success
messaging-compatible-endpoint-e2e ✅ success
network-policy-e2e ✅ success
openclaw-tui-chat-correlation-e2e ✅ success
sandbox-operations-e2e ✅ success

@jyaunches jyaunches added v0.0.69 and removed v0.0.68 labels Jun 25, 2026
@wscurran wscurran removed the bug label Jun 25, 2026
@NVIDIA NVIDIA deleted a comment from github-actions Bot Jun 26, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Selective E2E Results — ❌ Some jobs failed

Run: 28182597555
Target ref: fix/openclaw-fetch-guard-default-proxy
Requested jobs: cron-preflight-inference-local-e2e,messaging-compatible-endpoint-e2e,network-policy-e2e,common-egress-agent-e2e,cloud-onboard-e2e,cloud-inference-e2e,sandbox-operations-e2e,openclaw-tui-chat-correlation-e2e
Summary: 7 passed, 1 failed, 0 cancelled, 0 skipped

Job Result
cloud-inference-e2e ✅ success
cloud-onboard-e2e ✅ success
common-egress-agent-e2e ❌ failure
cron-preflight-inference-local-e2e ✅ success
messaging-compatible-endpoint-e2e ✅ success
network-policy-e2e ✅ success
openclaw-tui-chat-correlation-e2e ✅ success
sandbox-operations-e2e ✅ success

Failed jobs: common-egress-agent-e2e. Check run artifacts for logs.

@sandl99
sandl99 requested a review from cv June 26, 2026 03:00
@github-actions

Copy link
Copy Markdown
Contributor

Selective E2E Results — ❌ Some jobs failed

Run: 28182597555
Target ref: fix/openclaw-fetch-guard-default-proxy
Requested jobs: cron-preflight-inference-local-e2e,messaging-compatible-endpoint-e2e,network-policy-e2e,common-egress-agent-e2e,cloud-onboard-e2e,cloud-inference-e2e,sandbox-operations-e2e,openclaw-tui-chat-correlation-e2e
Summary: 7 passed, 1 failed, 0 cancelled, 0 skipped

Job Result
cloud-inference-e2e ✅ success
cloud-onboard-e2e ✅ success
common-egress-agent-e2e ❌ failure
cron-preflight-inference-local-e2e ✅ success
messaging-compatible-endpoint-e2e ✅ success
network-policy-e2e ✅ success
openclaw-tui-chat-correlation-e2e ✅ success
sandbox-operations-e2e ✅ success

Failed jobs: common-egress-agent-e2e. Check run artifacts for logs.

1 similar comment
@github-actions

Copy link
Copy Markdown
Contributor

Selective E2E Results — ❌ Some jobs failed

Run: 28182597555
Target ref: fix/openclaw-fetch-guard-default-proxy
Requested jobs: cron-preflight-inference-local-e2e,messaging-compatible-endpoint-e2e,network-policy-e2e,common-egress-agent-e2e,cloud-onboard-e2e,cloud-inference-e2e,sandbox-operations-e2e,openclaw-tui-chat-correlation-e2e
Summary: 7 passed, 1 failed, 0 cancelled, 0 skipped

Job Result
cloud-inference-e2e ✅ success
cloud-onboard-e2e ✅ success
common-egress-agent-e2e ❌ failure
cron-preflight-inference-local-e2e ✅ success
messaging-compatible-endpoint-e2e ✅ success
network-policy-e2e ✅ success
openclaw-tui-chat-correlation-e2e ✅ success
sandbox-operations-e2e ✅ success

Failed jobs: common-egress-agent-e2e. Check run artifacts for logs.

Signed-off-by: Carlos Villela <cvillela@nvidia.com>
@github-actions

github-actions Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

E2E Target Recommendation

Required E2E targets: ubuntu-repo-cloud-openclaw
Optional E2E targets: ubuntu-repo-cloud-langchain-deepagents-code

Dispatch required E2E targets:

  • gh workflow run e2e.yaml --ref <pr-head-ref> --field targets=ubuntu-repo-cloud-openclaw

Workflow run

Full E2E target advisor summary

E2E Target Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E targets

  • ubuntu-repo-cloud-openclaw: Dockerfile and sandbox build-context changes affect the OpenClaw sandbox image build and runtime fetch-guard behavior. The Ubuntu repo cloud OpenClaw target is the smallest live-supported typed target that builds the current repo sandbox image and exercises the OpenClaw sandbox/inference path.
    • Dispatch: gh workflow run e2e.yaml --ref <pr-head-ref> --field targets=ubuntu-repo-cloud-openclaw

Optional E2E targets

  • ubuntu-repo-cloud-langchain-deepagents-code: Optional adjacent coverage for the same Dockerfile/build-context sandbox image changes under the live-supported LangChain Deep Agents Code onboarding path.
    • Dispatch: gh workflow run e2e.yaml --ref <pr-head-ref> --field targets=ubuntu-repo-cloud-langchain-deepagents-code

Relevant changed files

  • Dockerfile
  • scripts/verify-openclaw-fetch-guard-runtime.ts
  • src/lib/sandbox/build-context.ts

@github-actions

github-actions Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor (Nemotron Ultra) — Changes requested

Merge posture: Do not merge yet
Primary next action: Fix PRA-5: Patch 4 broad default may bypass cert pinning/mTLS for bare fetchWithSsrFGuard callsites; then add or justify PRA-T1.
Open items: 1 required · 12 warnings · 7 suggestions · 8 test follow-ups
Since last review: 3 prior items resolved · 7 still apply · 5 new items found

Action checklist

  • PRA-5 Fix: Patch 4 broad default may bypass cert pinning/mTLS for bare fetchWithSsrFGuard callsites in Dockerfile:210
  • PRA-1 Resolve or justify: Source-of-truth review needed: Patch 1: redirect strict-mode export to trusted-env-proxy
  • PRA-2 Resolve or justify: Source-of-truth review needed: Patch 2: env-gated bypass for assertExplicitProxyAllowed
  • PRA-3 Resolve or justify: Source-of-truth review needed: Patch 2b: allow OpenShell host gateway through web_fetch guard
  • PRA-4 Resolve or justify: Source-of-truth review needed: Patch 4: default bare SSRF fetches to trusted env proxy in sandbox
  • PRA-6 Resolve or justify: Patch 2 removal criteria lacks upstream OpenClaw issue reference in Dockerfile:185
  • PRA-7 Resolve or justify: Patch 2b removal criteria lacks upstream OpenClaw issue reference; subdomain bypass unverified in Dockerfile:185
  • PRA-8 Resolve or justify: Patch 2 bypasses entire assertExplicitProxyAllowed function, not just hostname check in Dockerfile:250
  • PRA-9 Resolve or justify: Patch 4 sed replacement fragile to minification; whole-file verification incomplete in Dockerfile:370
  • PRA-10 Resolve or justify: Version coordination with PR chore(openclaw): upgrade to 2026.6.10 and harden runtime integration #5595 (2026.6.9) needed in Dockerfile:39
  • PRA-11 Resolve or justify: All patch removal criteria lack upstream OpenClaw issue references in Dockerfile:185
  • PRA-T1 Add or justify test follow-up: Runtime validation
  • PRA-T2 Add or justify test follow-up: Runtime validation
  • PRA-T3 Add or justify test follow-up: Runtime validation
  • PRA-T4 Add or justify test follow-up: Runtime validation
  • PRA-T5 Add or justify test follow-up: Runtime validation
  • PRA-T6 Add or justify test follow-up: Missing cron preflight end-to-end test with real fetchWithSsrFGuard implementation
  • PRA-T7 Add or justify test follow-up: Missing Google Chat dispatcher policy end-to-end test
  • PRA-T8 Add or justify test follow-up: Test version constant not derived from Dockerfile ARG; drift risk
  • PRA-14 In-scope improvement: Missing cron preflight end-to-end test with real fetchWithSsrFGuard implementation in test/fetch-guard-patch-regression.test.ts:1100
  • PRA-15 In-scope improvement: Missing Google Chat dispatcher policy end-to-end test in test/fetch-guard-patch-regression.test.ts:1106
  • PRA-16 In-scope improvement: Test version constant not derived from Dockerfile ARG; drift risk in test/fetch-guard-patch-regression.test.ts:16
  • PRA-17 In-scope improvement: Runtime verifier missing coverage for host gateway, web_fetch, cron preflight, and explicit connect/proxyTls in scripts/verify-openclaw-fetch-guard-runtime.ts:1
  • PRA-18 In-scope improvement: Custom test framework duplicates Dockerfile logic; consider shared helper in test/fetch-guard-patch-regression.test.ts:1
  • PRA-19 In-scope improvement: Extract Patch 4 sed logic to Node.js patch script for robustness in Dockerfile:370
  • PRA-20 In-scope improvement: Add whole-file grep for deprecated patterns after Patch 4 application in Dockerfile:370

Findings index

ID Severity Category Location Required action
PRA-1 Resolve/justify architecture Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
PRA-2 Resolve/justify architecture Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
PRA-3 Resolve/justify architecture Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
PRA-4 Resolve/justify architecture Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
PRA-5 Required security Dockerfile:210 Add a build-time audit step that scans the OpenClaw dist for bare fetchWithSsrFGuard callsites and flags any that pass security-relevant options (dispatcherPolicy.connect, dispatcherPolicy.proxyTls, certificate validation config, mTLS settings) or are known to require direct TLS verification. Alternatively, narrow the default to only apply to callsites with specific auditContext values (like the old Patch 6 did for cron preflight), or document in removal criteria that this patch must be reverted if any callsite is found to require STRICT mode for security.
PRA-6 Resolve/justify security Dockerfile:185 Add explicit references to upstream OpenClaw issues/PRs for Patch 2's removal condition (e.g., 'openclaw/openclaw#XXXXX'). File or reference an upstream issue for the assertExplicitProxyAllowed design flaw. Add a TODO comment with check-date or link to a tracking issue in NemoClaw.
PRA-7 Resolve/justify security Dockerfile:185 Add a direct link to the upstream OpenClaw issue tracking web_fetch trusted-proxy SSRF policy surface. Verify the normalizeHostname function in the reviewed OpenClaw 2026.5.27 dist does exact matching (no suffix/prefix matching) for allowedHostnames. Add a test fixture that attempts subdomain bypass.
PRA-8 Resolve/justify security Dockerfile:250 Narrow the bypass to only skip the proxy hostname check (the resolvePinnedHostnameWithPolicy call with target's policy), not the entire function. Or verify that the L7 proxy's policy enforcement is sufficient defense-in-depth for all proxy-mediated fetches. Add a test that verifies the bypass doesn't weaken SSRF for non-proxy fetches.
PRA-9 Resolve/justify correctness Dockerfile:370 Extract Patch 4 logic into a Node.js patch script (following the pattern of patch-openclaw-tool-catalog.js) for robust AST-based transformations. At minimum, add a whole-file grep verification after Patch 4 application that searches for any remaining 'params.proxy === "env"' or 'dangerouslyAllowEnvProxyWithoutPinnedDns' patterns in the entire patched file.
PRA-10 Resolve/justify correctness Dockerfile:39 Coordinate with PR #5595. Either this PR should update the reviewed version to 2026.6.9 with new shape constants, or PR #5595 should rebase on this PR and update the patch logic. Add a comment in the test file noting the expected next version and what shape changes to watch for.
PRA-11 Resolve/justify acceptance Dockerfile:185 Add explicit upstream issue references for each patch's removal condition. For Patch 4, reference the specific OpenClaw issue that would implement the sandbox-aware default.
PRA-12 Resolve/justify correctness Dockerfile:390 Clarify the skip condition comment to explain that the presence of either the resolver function OR the legacy dangerous opt-in reference means the dist shape is not a clean 'no guarded-fetch mode resolver' layout and requires manual review. Consider adding a version-specific classifier for 2026.6.9+.
PRA-13 Resolve/justify security Dockerfile:300 Add verification that the patched hostGatewayPolicy object correctly spreads resolved.policy and adds allowedHostnames. Consider extracting Patch 2b to a Node.js patch script for robustness.
PRA-14 Improvement tests test/fetch-guard-patch-regression.test.ts:1100 Add an integration-style test that mocks fetchWithSsrFGuard with the cron preflight policy (hostnameAllowlist: ['inference.local']) and verifies it resolves via proxy when OPENSHELL_SANDBOX=1, and that SSRF denies (private IPs, .internal) are still enforced.
PRA-15 Improvement tests test/fetch-guard-patch-regression.test.ts:1106 Add a test that mocks @openclaw/googlechat's resolveGoogleAuthDispatcherPolicy and verifies the four dispatcher policy scenarios.
PRA-16 Improvement tests test/fetch-guard-patch-regression.test.ts:16 Either derive the test version from the Dockerfile ARG at test runtime (read Dockerfile and parse ARG), or add a test that fails if the Dockerfile OPENCLAW_VERSION differs from CURRENT_REVIEWED_OPENCLAW_PATCH_CLASSIFIER_VERSION without updated shape constants.
PRA-17 Improvement correctness scripts/verify-openclaw-fetch-guard-runtime.ts:1 Extend the runtime verifier to cover: (1) host.openshell.internal gateway path, (2) web_fetch with useEnvProxy, (3) cron preflight with inference.local, (4) explicit dispatcherPolicy.connect/proxyTls forcing STRICT mode. This would make the build-time verification comprehensive.
PRA-18 Improvement correctness test/fetch-guard-patch-regression.test.ts:1 Consider extracting the patch simulation logic into a shared test helper module. The current approach is acceptable for regression guarding but could be simplified.
PRA-19 Improvement correctness Dockerfile:370 Create patch-openclaw-fetch-guard-mode.js following the pattern of patch-openclaw-tool-catalog.js and patch-openclaw-chat-send.js. Move the resolver transformation logic there. Keep the Dockerfile classification logic (detecting dist shape) but delegate the transformation to the Node script.
PRA-20 Improvement correctness Dockerfile:370 Add a whole-file grep verification after Patch 4 application that searches for any remaining 'params.proxy === "env"' or 'dangerouslyAllowEnvProxyWithoutPinnedDns' patterns in the entire patched file and fails if found.

🚨 Required before merge

Address these before merging unless a maintainer explicitly overrides the advisor with rationale.

PRA-5 Required — Patch 4 broad default may bypass cert pinning/mTLS for bare fetchWithSsrFGuard callsites

  • Location: Dockerfile:210
  • Category: security
  • Problem: Patch 4 changes the default for ALL bare fetchWithSsrFGuard callsites inside the sandbox from STRICT (DNS-pinned direct) to TRUSTED_ENV_PROXY (proxied). The patch preserves STRICT only when callers explicitly pass dispatcherPolicy.connect, dispatcherPolicy.proxyTls, or an explicit mode. However, callsites that rely on STRICT's direct TLS verification for certificate pinning or mTLS WITHOUT explicitly passing these options will now silently route through the proxy, potentially bypassing certificate validation. The Google Chat cert fetch (www.googleapis.com/service\_accounts/v1/metadata/x509/...\) is a confirmed example — it previously used STRICT mode for direct TLS verification; now it uses the proxy. The new runtime verifier confirms this behavior change (test 'bare omitted-mode fetches skip pinned DNS in sandbox').
  • Impact: A callsite that needs direct TLS verification could silently route through the proxy, bypassing certificate pinning or mTLS validation, weakening SSRF/mTLS guarantees for that specific call. Unknown set of callsites in OpenClaw dist may be affected.
  • Required action: Add a build-time audit step that scans the OpenClaw dist for bare fetchWithSsrFGuard callsites and flags any that pass security-relevant options (dispatcherPolicy.connect, dispatcherPolicy.proxyTls, certificate validation config, mTLS settings) or are known to require direct TLS verification. Alternatively, narrow the default to only apply to callsites with specific auditContext values (like the old Patch 6 did for cron preflight), or document in removal criteria that this patch must be reverted if any callsite is found to require STRICT mode for security.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Run the patched OpenClaw dist and grep for fetchWithSsrFGuard callsites; verify none pass dispatcherPolicy.connect, dispatcherPolicy.proxyTls, or other STRICT-requiring options when mode is omitted. Check for patterns like 'dispatcherPolicy', 'mode: "strict"', 'tls', 'cert', 'mTLS' in call arguments.
  • Missing regression test: A test that enumerates all fetchWithSsrFGuard callsites in the reviewed OpenClaw dist and asserts none pass dispatcherPolicy.connect, dispatcherPolicy.proxyTls, or other STRICT-requiring options when mode is omitted.
  • Done when: The required change is committed and verification passes: Run the patched OpenClaw dist and grep for fetchWithSsrFGuard callsites; verify none pass dispatcherPolicy.connect, dispatcherPolicy.proxyTls, or other STRICT-requiring options when mode is omitted. Check for patterns like 'dispatcherPolicy', 'mode: "strict"', 'tls', 'cert', 'mTLS' in call arguments.
  • Evidence: Dockerfile lines 368-404 implement the new central default. Test 'defaults bare guarded fetches to trusted env proxy only inside the sandbox' (line 1106) verifies resolver behavior but does not audit actual OpenClaw dist callsites. Runtime verifier test 'bare omitted-mode fetches skip pinned DNS in sandbox' confirms Google Chat cert fetch now uses proxy without local DNS.
Review findings by urgency: 1 required fix, 12 items to resolve/justify, 7 in-scope improvements

⚠️ Resolve or justify before merge

Investigate these in the current review; either fix them, explain why they are not applicable, or document the accepted risk.

PRA-1 Resolve/justify — Source-of-truth review needed: Patch 1: redirect strict-mode export to trusted-env-proxy

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Test fails closed if strict export missing but no reviewed trusted-proxy layout (test 'fails closed when strict export disappears without a reviewed trusted fetch callsite')
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: Dockerfile lines 178-190 (comments), 298-302 (implementation), 241 (removal criteria) — no upstream issue reference

PRA-2 Resolve/justify — Source-of-truth review needed: Patch 2: env-gated bypass for assertExplicitProxyAllowed

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Test verifies bypass only activates with OPENSHELL_SANDBOX=1; proxy checks empty in sandbox (test 'rewrites strict media fetch exports and makes proxy validation sandbox-aware')
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: Dockerfile lines 191-211 (comments), 303-327 (implementation), 241 (removal criteria) — no upstream issue reference

PRA-3 Resolve/justify — Source-of-truth review needed: Patch 2b: allow OpenShell host gateway through web_fetch guard

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Test verifies host gateway allowed only with useEnvProxy + OPENSHELL_SANDBOX=1; strict path still blocks (test 'anchors web_fetch host-gateway policy to the reviewed OpenClaw 2026.5.27 SSRF contract')
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: Dockerfile lines 228-240 (comments), 345-366 (implementation), 244 (removal criteria) — no upstream issue reference; subdomain bypass unverified

PRA-4 Resolve/justify — Source-of-truth review needed: Patch 4: default bare SSRF fetches to trusted env proxy in sandbox

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Test verifies resolver returns trusted_env_proxy in sandbox, strict outside; explicit modes win; connect/proxyTls force STRICT (test 'defaults bare guarded fetches to trusted env proxy only inside the sandbox')
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: Dockerfile lines 220-234 (comments), 368-404 (implementation), 247 (removal criteria) — references fix(sandbox): cron preflight inference.local uses trusted env-proxy mode #5129 but no specific OpenClaw issue; PRA-3 blocker for broad default risk

PRA-6 Resolve/justify — Patch 2 removal criteria lacks upstream OpenClaw issue reference

  • Location: Dockerfile:185
  • Category: security
  • Problem: Patch 2 injects an env-gated early return in assertExplicitProxyAllowed that skips the proxy hostname validation against the target's SSRF allowlist. This is a localized workaround for an upstream OpenClaw design flaw. The removal criteria references no upstream OpenClaw issue/PR. Without a tracked upstream fix, this workaround may persist indefinitely and the source boundary remains unaddressed in OpenClaw.
  • Impact: Workaround may persist indefinitely without upstream tracking; source boundary (why proxy hostname should not be validated against target allowlist) unclear to future maintainers.
  • Recommended action: Add explicit references to upstream OpenClaw issues/PRs for Patch 2's removal condition (e.g., 'openclaw/openclaw#XXXXX'). File or reference an upstream issue for the assertExplicitProxyAllowed design flaw. Add a TODO comment with check-date or link to a tracking issue in NemoClaw.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Check Dockerfile comments for Patch 2 removal criteria — search for 'openclaw/openclaw#' or upstream issue references.
  • Missing regression test: A test that verifies the bypass only activates when OPENSHELL_SANDBOX=1 and that the L7 proxy's policy enforcement is sufficient defense-in-depth (already partially covered by existing tests).
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Check Dockerfile comments for Patch 2 removal criteria — search for 'openclaw/openclaw#' or upstream issue references.
  • Evidence: Dockerfile lines 191-211 (comments) and 303-327 (implementation) — removal criteria comment at line 241 has no upstream issue reference.

PRA-7 Resolve/justify — Patch 2b removal criteria lacks upstream OpenClaw issue reference; subdomain bypass unverified

  • Location: Dockerfile:185
  • Category: security
  • Problem: Patch 2b allows host.openshell.internal through web_fetch's trusted-env-proxy policy by injecting it into allowedHostnames only when OPENSHELL_SANDBOX=1 and useEnvProxy is true. This is a localized workaround. The removal criteria references no upstream OpenClaw issue. The subdomain bypass risk (host.openshell.internal.evil.com) depends on OpenClaw's normalizeHostname doing exact matching — this needs verification against the actual OpenClaw dist.
  • Impact: If normalizeHostname does suffix matching, 'host.openshell.internal.attacker.com' could bypass SSRF. Workaround lacks upstream tracking.
  • Recommended action: Add a direct link to the upstream OpenClaw issue tracking web_fetch trusted-proxy SSRF policy surface. Verify the normalizeHostname function in the reviewed OpenClaw 2026.5.27 dist does exact matching (no suffix/prefix matching) for allowedHostnames. Add a test fixture that attempts subdomain bypass.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Grep the OpenClaw 2026.5.27 dist for 'normalizeHostname' and inspect its implementation. Search for 'normalizeHostname' in the dist.
  • Missing regression test: A test fixture that attempts subdomain bypass (e.g., 'host.openshell.internal.attacker.com') against the actual patched fetch guard and verifies it's blocked.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Grep the OpenClaw 2026.5.27 dist for 'normalizeHostname' and inspect its implementation. Search for 'normalizeHostname' in the dist.
  • Evidence: Dockerfile lines 228-240 (comments) and 345-366 (implementation) — removal criteria at line 244 has no upstream issue reference. Test 'anchors web_fetch host-gateway policy' verifies reviewed SSRF policy shape but not actual dist's normalizeHostname.

PRA-8 Resolve/justify — Patch 2 bypasses entire assertExplicitProxyAllowed function, not just hostname check

  • Location: Dockerfile:250
  • Category: security
  • Problem: Patch 2's env-gated bypass skips the ENTIRE assertExplicitProxyAllowed function, not just the proxy hostname check. This means if assertExplicitProxyAllowed gains additional security checks in the future (e.g., proxy URL scheme validation, proxy authentication checks), they would also be bypassed in the sandbox. The L7 proxy provides defense-in-depth but the bypass is broader than necessary.
  • Impact: Future security checks added to assertExplicitProxyAllowed would be silently bypassed in sandbox. Defense-in-depth reduced.
  • Recommended action: Narrow the bypass to only skip the proxy hostname check (the resolvePinnedHostnameWithPolicy call with target's policy), not the entire function. Or verify that the L7 proxy's policy enforcement is sufficient defense-in-depth for all proxy-mediated fetches. Add a test that verifies the bypass doesn't weaken SSRF for non-proxy fetches.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the sed replacement for Patch 2 in Dockerfile (line 311) — it wraps the entire function body with an early return.
  • Missing regression test: A test that verifies non-proxy fetches (strict/direct mode) still enforce full SSRF checks when OPENSHELL_SANDBOX=1.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the sed replacement for Patch 2 in Dockerfile (line 311) — it wraps the entire function body with an early return.
  • Evidence: Dockerfile line 311: sed replaces entire function body with early return. Test 'rewrites strict media fetch exports and makes proxy validation sandbox-aware' verifies proxyChecks empty in sandbox but doesn't test non-proxy paths.

PRA-9 Resolve/justify — Patch 4 sed replacement fragile to minification; whole-file verification incomplete

  • Location: Dockerfile:370
  • Category: correctness
  • Problem: Patch 4 uses complex sed replacements with multi-line range matching ('/function resolveGuardedFetchMode(params)/,/return GUARDED_FETCH_MODE.STRICT;/'). Sed is fragile to minification changes, whitespace differences, or comment insertion. The verification checks for leftover 'dangerouslyAllowEnvProxyWithoutPinnedDns' and 'params.proxy === "env"' patterns, but only within the extracted resolver block, not the whole file.
  • Impact: Patch may fail to apply or apply incorrectly on minified dist variations. Deprecated patterns could survive outside resolver block.
  • Recommended action: Extract Patch 4 logic into a Node.js patch script (following the pattern of patch-openclaw-tool-catalog.js) for robust AST-based transformations. At minimum, add a whole-file grep verification after Patch 4 application that searches for any remaining 'params.proxy === "env"' or 'dangerouslyAllowEnvProxyWithoutPinnedDns' patterns in the entire patched file.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Check Dockerfile Patch 4 verification (lines 391-396) — it extracts resolver block with sed and greps that block, not the whole file.
  • Missing regression test: A test that applies Patch 4 to a fixture with the deprecated patterns outside the resolver block and verifies the build fails.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Check Dockerfile Patch 4 verification (lines 391-396) — it extracts resolver block with sed and greps that block, not the whole file.
  • Evidence: Dockerfile lines 380-396: two sed commands with multi-line range, verification only on extracted resolver block.

PRA-10 Resolve/justify — Version coordination with PR #5595 (2026.6.9) needed

PRA-11 Resolve/justify — All patch removal criteria lack upstream OpenClaw issue references

  • Location: Dockerfile:185
  • Category: acceptance
  • Problem: Removal criteria for Patches 1, 2, 2b, and 4 lack explicit references to upstream OpenClaw issues/PRs. Patch 1 references a general deprecation condition but no issue number. Patch 2 and 2b reference design flaws but no upstream tracking. Patch 4 references NemoClaw sandbox: Gemini web_search fails with EAI_AGAIN until Google host + node are allowed, and trusted proxy still does local DNS lookup #396, @openclaw/googlechat cert fetch fails: SSRF guard's per-request dispatcher bypasses NemoClaw's nemoclaw-http-proxy-fix.js global-agent hook #4687 and openclaw#5129 but the removal condition 'when OpenClaw defaults bare fetchWithSsrFGuard calls to trusted_env_proxy in an OpenShell sandbox' is vague — no specific OpenClaw issue/PR to track.
  • Impact: Cannot track upstream progress for patch removal. Maintainers cannot verify if upstream fix addresses the root cause.
  • Recommended action: Add explicit upstream issue references for each patch's removal condition. For Patch 4, reference the specific OpenClaw issue that would implement the sandbox-aware default.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Search Dockerfile removal criteria comments for 'openclaw/openclaw#' or 'NVIDIA/NemoClaw#' patterns.
  • Missing regression test: None — this is a documentation/tracking gap.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Search Dockerfile removal criteria comments for 'openclaw/openclaw#' or 'NVIDIA/NemoClaw#' patterns.
  • Evidence: Dockerfile lines 241-250 (removal criteria comments) — no 'openclaw/openclaw#' references found.

PRA-12 Resolve/justify — Patch 4 skip condition unclear — should require BOTH resolver function AND legacy opt-in absent

  • Location: Dockerfile:390
  • Category: correctness
  • Problem: Patch 4 skip condition checks for 'resolveGuardedFetchMode' function and 'dangerouslyAllowEnvProxyWithoutPinnedDns' references. The comment says 'has no guarded-fetch mode resolver' but the check is for either the resolver function OR the dangerous opt-in reference. If only the resolver is gone but dangerous opt-in remains, the dist shape is ambiguous and should fail closed.
  • Impact: Ambiguous dist shape could be silently skipped, leaving deprecated opt-in unpatched.
  • Recommended action: Clarify the skip condition comment to explain that the presence of either the resolver function OR the legacy dangerous opt-in reference means the dist shape is not a clean 'no guarded-fetch mode resolver' layout and requires manual review. Consider adding a version-specific classifier for 2026.6.9+.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read Dockerfile lines 405-412 (else branch for Patch 4) — mode_refs greps for both 'resolveGuardedFetchMode' and 'dangerouslyAllowEnvProxyWithoutPinnedDns'.
  • Missing regression test: A test that provides a fixture with resolver missing but dangerous opt-in present and verifies build fails.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read Dockerfile lines 405-412 (else branch for Patch 4) — mode_refs greps for both 'resolveGuardedFetchMode' and 'dangerouslyAllowEnvProxyWithoutPinnedDns'.
  • Evidence: Dockerfile lines 405-412: mode_refs includes both patterns; error message says 'has no guarded-fetch mode resolver' but checks for either.

PRA-13 Resolve/justify — Patch 2b sed robustness to minification variations unverified

  • Location: Dockerfile:300
  • Category: security
  • Problem: Patch 2b's sed replacement uses a complex regex that matches the exact reviewed web_fetch callsite shape. If OpenClaw 2026.5.27's dist has minification variations (e.g., different spacing, renamed variables), the sed may fail to match or match incorrectly. The verification greps for the injected marker but doesn't verify the policy object spread is correct.
  • Impact: Patch may fail to apply or produce incorrect policy object on minified dist variations.
  • Recommended action: Add verification that the patched hostGatewayPolicy object correctly spreads resolved.policy and adds allowedHostnames. Consider extracting Patch 2b to a Node.js patch script for robustness.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the Patch 2b sed replacement in Dockerfile (lines 349-351) and the grep verification that follows (line 350).
  • Missing regression test: A test that applies Patch 2b to a fixture with minification variations and verifies correct policy spreading.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the Patch 2b sed replacement in Dockerfile (lines 349-351) and the grep verification that follows (line 350).
  • Evidence: Dockerfile lines 349-351: complex sed with exact string match; verification only greps for injected marker comment.

💡 In-scope improvements

These are lower-risk, not throwaway. Prefer fixing them in this PR when they are local to changed code; defer only with rationale or a linked follow-up.

PRA-14 Improvement — Missing cron preflight end-to-end test with real fetchWithSsrFGuard implementation

  • Location: test/fetch-guard-patch-regression.test.ts:1100
  • Category: tests
  • Problem: The new runtime verifier provides excellent build-time verification but there's no end-to-end test that runs the actual cron preflight code path with the real fetchWithSsrFGuard implementation to verify it now works via the central Patch 4 default (since Patch 6 was removed). The test 'leaves cron preflight callsites unmodified because omitted mode is patched centrally' verifies the callsite is unmodified and the resolver returns trusted_env_proxy, but doesn't test the full fetchWithSsrFGuard execution path for the cron preflight.
  • Impact: Cron preflight path not verified end-to-end; regression risk if fetchWithSsrFGuard implementation changes.
  • Suggested action: Add an integration-style test that mocks fetchWithSsrFGuard with the cron preflight policy (hostnameAllowlist: ['inference.local']) and verifies it resolves via proxy when OPENSHELL_SANDBOX=1, and that SSRF denies (private IPs, .internal) are still enforced.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Check test file for cron preflight end-to-end test — search for 'cron' and 'inference.local' in test cases.
  • Missing regression test: An integration-style test that mocks fetchWithSsrFGuard with the cron preflight policy and verifies proxy resolution and SSRF denies.
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: Test file has 'leaves cron preflight callsites unmodified because omitted mode is patched centrally' (line 1323) but no full fetchWithSsrFGuard execution test for cron preflight.

PRA-15 Improvement — Missing Google Chat dispatcher policy end-to-end test

  • Location: test/fetch-guard-patch-regression.test.ts:1106
  • Category: tests
  • Problem: The Google Chat cert fetch is a critical callsite that changed from STRICT to TRUSTED_ENV_PROXY. The runtime verifier tests this path, but there's no test that mocks @openclaw/googlechat's resolveGoogleAuthDispatcherPolicy and verifies: (1) bare call defaults to trusted_env_proxy in sandbox, (2) explicit-proxy mode respected, (3) env-proxy mode respected, (4) direct mode (TLS options) respected. This would verify the dispatcherPolicy.connect/proxyTls protection works for the actual Google Chat integration.
  • Impact: Google Chat dispatcher policy scenarios not verified end-to-end; connect/proxyTls STRICT preservation untested for real integration.
  • Suggested action: Add a test that mocks @openclaw/googlechat's resolveGoogleAuthDispatcherPolicy and verifies the four dispatcher policy scenarios.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Check test file for Google Chat dispatcher policy tests — search for 'googlechat' or 'resolveGoogleAuthDispatcherPolicy'.
  • Missing regression test: A test that mocks @openclaw/googlechat's resolveGoogleAuthDispatcherPolicy and verifies all four dispatcher policy scenarios.
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: Runtime verifier tests Google Chat cert URL but only for bare call; no test for explicit-proxy, env-proxy, or direct modes.

PRA-16 Improvement — Test version constant not derived from Dockerfile ARG; drift risk

  • Location: test/fetch-guard-patch-regression.test.ts:16
  • Category: tests
  • Problem: The test constant CURRENT_REVIEWED_OPENCLAW_PATCH_CLASSIFIER_VERSION is manually maintained and can drift from the Dockerfile ARG OPENCLAW_VERSION. The test 'requires classifier review and integrity evidence when the OpenClaw build pin changes' checks they match, but this only catches drift at test time. Better to derive the test version from the Dockerfile ARG at test runtime.
  • Impact: Version drift between Dockerfile and tests could go undetected until test run.
  • Suggested action: Either derive the test version from the Dockerfile ARG at test runtime (read Dockerfile and parse ARG), or add a test that fails if the Dockerfile OPENCLAW_VERSION differs from CURRENT_REVIEWED_OPENCLAW_PATCH_CLASSIFIER_VERSION without updated shape constants.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Check test file for version derivation — search for 'readDockerfileOpenClawVersion' and 'CURRENT_REVIEWED_OPENCLAW_PATCH_CLASSIFIER_VERSION'.
  • Missing regression test: A test that reads the Dockerfile ARG at runtime and compares against the test constant.
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: Test line 16: const CURRENT_REVIEWED_OPENCLAW_PATCH_CLASSIFIER_VERSION = "2026.5.27"; line 200: readDockerfileOpenClawVersion() reads Dockerfile ARG but comparison only in 'requires classifier review' test.

PRA-17 Improvement — Runtime verifier missing coverage for host gateway, web_fetch, cron preflight, and explicit connect/proxyTls

  • Location: scripts/verify-openclaw-fetch-guard-runtime.ts:1
  • Category: correctness
  • Problem: The new runtime verifier is excellent but only tests the Google Chat cert URL and a fixed set of blocked targets. It doesn't test the host.openshell.internal gateway path (Patch 2b), the web_fetch path, or the cron preflight path with inference.local. The verifier also doesn't test that explicit dispatcherPolicy.connect/proxyTls correctly forces STRICT mode.
  • Impact: Critical fetch paths not verified at build time; regression risk for Patch 2b, web_fetch, cron preflight, and STRICT preservation.
  • Suggested action: Extend the runtime verifier to cover: (1) host.openshell.internal gateway path, (2) web_fetch with useEnvProxy, (3) cron preflight with inference.local, (4) explicit dispatcherPolicy.connect/proxyTls forcing STRICT mode. This would make the build-time verification comprehensive.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Read verify-openclaw-fetch-guard-runtime.ts and check BLOCKED_TARGETS and verifyGoogleCertProxyPath — only Google Chat cert URL is tested for positive proxy path.
  • Missing regression test: Extended runtime verifier test cases for all critical fetch paths.
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: verify-openclaw-fetch-guard-runtime.ts lines 47-57 (BLOCKED_TARGETS), lines 130-170 (verifyGoogleCertProxyPath) — only Google Chat cert URL tested for positive path.

PRA-18 Improvement — Custom test framework duplicates Dockerfile logic; consider shared helper

  • Location: test/fetch-guard-patch-regression.test.ts:1
  • Category: correctness
  • Problem: The test file has grown significantly (1434 lines) with many fixture generators and patch simulation helpers. The runDockerfilePatchBlock function extracts Dockerfile RUN commands and executes them with a fake sed. This is a custom test framework that duplicates Dockerfile logic. While effective, it creates maintenance burden and divergence risk.
  • Impact: Maintenance burden; divergence risk between Dockerfile and test simulation.
  • Suggested action: Consider extracting the patch simulation logic into a shared test helper module. The current approach is acceptable for regression guarding but could be simplified.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Review test file structure — note the dockerRunCommandBetween, runDockerfilePatchBlock, runFetchGuardPatchBlock, createSedWrapper helpers.
  • Missing regression test: None — this is a maintainability concern.
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: Test file lines 200-350: dockerRunCommandBetween, runDockerfilePatchBlock, runFetchGuardPatchBlock, createSedWrapper functions.

PRA-19 Improvement — Extract Patch 4 sed logic to Node.js patch script for robustness

  • Location: Dockerfile:370
  • Category: correctness
  • Problem: Patch 4 uses complex sed replacements that are fragile to minification. The new verify-openclaw-fetch-guard-runtime.mjs demonstrates the pattern of using Node.js for robust transformations. Extracting Patch 4 to a Node.js script would allow AST-based parsing, better testability, and eliminate regex fragility.
  • Impact: Reduces risk of patch misapplication on dist variations; improves maintainability.
  • Suggested action: Create patch-openclaw-fetch-guard-mode.js following the pattern of patch-openclaw-tool-catalog.js and patch-openclaw-chat-send.js. Move the resolver transformation logic there. Keep the Dockerfile classification logic (detecting dist shape) but delegate the transformation to the Node script.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Check Dockerfile Patch 4 implementation (lines 368-404) — all sed-based. Compare to patch-openclaw-tool-catalog.js pattern (lines 480-485).
  • Missing regression test: Unit tests for the Node.js patch script covering all dist shape variations.
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: Dockerfile lines 368-404: 36 lines of sed logic. Existing pattern at lines 480-485: node /usr/local/lib/nemoclaw/patch-openclaw-tool-catalog.js.

PRA-20 Improvement — Add whole-file grep for deprecated patterns after Patch 4 application

  • Location: Dockerfile:370
  • Category: correctness
  • Problem: Patch 4 verification only checks the extracted resolver block for leftover 'params.proxy === "env"' and 'dangerouslyAllowEnvProxyWithoutPinnedDns' patterns. A whole-file grep would catch any surviving instances elsewhere in the patched file.
  • Impact: Deprecated patterns could survive outside resolver block, causing unexpected behavior.
  • Suggested action: Add a whole-file grep verification after Patch 4 application that searches for any remaining 'params.proxy === "env"' or 'dangerouslyAllowEnvProxyWithoutPinnedDns' patterns in the entire patched file and fails if found.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Check Dockerfile Patch 4 verification (lines 391-396) — only checks extracted resolver block.
  • Missing regression test: A test that applies Patch 4 to a fixture with deprecated patterns outside resolver block and verifies build fails.
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: Dockerfile lines 391-396: patched_resolver extracted with sed, then grepped. No whole-file check.
Simplification opportunities: 3 possible cuts, net -228 lines possible

These are safe simplification checks only. Do not remove validation, security controls, data-loss prevention, or required tests.

  • PRA-18 shrink (test/fetch-guard-patch-regression.test.ts:1): dockerRunCommandBetween, runDockerfilePatchBlock, runFetchGuardPatchBlock, createSedWrapper helpers in test/fetch-guard-patch-regression.test.ts
    • Replacement: Shared test helper module imported by fetch-guard tests
    • Net: -200 lines
    • Safety boundary: Must preserve exact Dockerfile patch command extraction and sed simulation fidelity
  • PRA-19 stdlib (Dockerfile:370): Patch 4 sed logic in Dockerfile (lines 376-396)
    • Replacement: Node.js patch script patch-openclaw-fetch-guard-mode.js with AST-based transformation
    • Net: -30 lines
    • Safety boundary: Must preserve fail-closed classification logic in Dockerfile; Node script only handles transformation after classification
  • PRA-20 native (Dockerfile:370): Current resolver-block-only verification
    • Replacement: grep -Rq 'params\.proxy === "env"' "$f" || patch_fail ... on whole file
    • Net: 2 lines
    • Safety boundary: Must not weaken existing resolver-block verification; add as additional check
Test follow-ups to resolve or justify

If these cover changed behavior, prefer adding them in this PR; otherwise state why existing coverage is enough or link the follow-up.

  • PRA-T1 Runtime validation — verify runtime verifier covers host.openshell.internal gateway path. Runtime/sandbox/infrastructure paths need behavioral runtime validation: Dockerfile, scripts/verify-openclaw-fetch-guard-runtime.ts, src/lib/sandbox/build-context.ts. New runtime verifier added but has coverage gaps for host gateway, web_fetch, cron preflight, and explicit connect/proxyTls scenarios.
  • PRA-T2 Runtime validation — verify runtime verifier covers web_fetch useEnvProxy path. Runtime/sandbox/infrastructure paths need behavioral runtime validation: Dockerfile, scripts/verify-openclaw-fetch-guard-runtime.ts, src/lib/sandbox/build-context.ts. New runtime verifier added but has coverage gaps for host gateway, web_fetch, cron preflight, and explicit connect/proxyTls scenarios.
  • PRA-T3 Runtime validation — verify runtime verifier covers cron preflight inference.local. Runtime/sandbox/infrastructure paths need behavioral runtime validation: Dockerfile, scripts/verify-openclaw-fetch-guard-runtime.ts, src/lib/sandbox/build-context.ts. New runtime verifier added but has coverage gaps for host gateway, web_fetch, cron preflight, and explicit connect/proxyTls scenarios.
  • PRA-T4 Runtime validation — verify runtime verifier tests dispatcherPolicy.connect/proxyTls force STRICT. Runtime/sandbox/infrastructure paths need behavioral runtime validation: Dockerfile, scripts/verify-openclaw-fetch-guard-runtime.ts, src/lib/sandbox/build-context.ts. New runtime verifier added but has coverage gaps for host gateway, web_fetch, cron preflight, and explicit connect/proxyTls scenarios.
  • PRA-T5 Runtime validation — verify runtime verifier mocks @openclaw/googlechat resolveGoogleAuthDispatcherPolicy. Runtime/sandbox/infrastructure paths need behavioral runtime validation: Dockerfile, scripts/verify-openclaw-fetch-guard-runtime.ts, src/lib/sandbox/build-context.ts. New runtime verifier added but has coverage gaps for host gateway, web_fetch, cron preflight, and explicit connect/proxyTls scenarios.
  • PRA-T6 Missing cron preflight end-to-end test with real fetchWithSsrFGuard implementation — Add an integration-style test that mocks fetchWithSsrFGuard with the cron preflight policy (hostnameAllowlist: ['inference.local']) and verifies it resolves via proxy when OPENSHELL_SANDBOX=1, and that SSRF denies (private IPs, .internal) are still enforced.
  • PRA-T7 Missing Google Chat dispatcher policy end-to-end test — Add a test that mocks @openclaw/googlechat's resolveGoogleAuthDispatcherPolicy and verifies the four dispatcher policy scenarios.
  • PRA-T8 Test version constant not derived from Dockerfile ARG; drift risk — Either derive the test version from the Dockerfile ARG at test runtime (read Dockerfile and parse ARG), or add a test that fails if the Dockerfile OPENCLAW_VERSION differs from CURRENT_REVIEWED_OPENCLAW_PATCH_CLASSIFIER_VERSION without updated shape constants.
Since last review details

Current findings, using the urgency labels above:

PRA-1 Resolve/justify — Source-of-truth review needed: Patch 1: redirect strict-mode export to trusted-env-proxy

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Test fails closed if strict export missing but no reviewed trusted-proxy layout (test 'fails closed when strict export disappears without a reviewed trusted fetch callsite')
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: Dockerfile lines 178-190 (comments), 298-302 (implementation), 241 (removal criteria) — no upstream issue reference

PRA-2 Resolve/justify — Source-of-truth review needed: Patch 2: env-gated bypass for assertExplicitProxyAllowed

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Test verifies bypass only activates with OPENSHELL_SANDBOX=1; proxy checks empty in sandbox (test 'rewrites strict media fetch exports and makes proxy validation sandbox-aware')
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: Dockerfile lines 191-211 (comments), 303-327 (implementation), 241 (removal criteria) — no upstream issue reference

PRA-3 Resolve/justify — Source-of-truth review needed: Patch 2b: allow OpenShell host gateway through web_fetch guard

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Test verifies host gateway allowed only with useEnvProxy + OPENSHELL_SANDBOX=1; strict path still blocks (test 'anchors web_fetch host-gateway policy to the reviewed OpenClaw 2026.5.27 SSRF contract')
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: Dockerfile lines 228-240 (comments), 345-366 (implementation), 244 (removal criteria) — no upstream issue reference; subdomain bypass unverified

PRA-4 Resolve/justify — Source-of-truth review needed: Patch 4: default bare SSRF fetches to trusted env proxy in sandbox

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Test verifies resolver returns trusted_env_proxy in sandbox, strict outside; explicit modes win; connect/proxyTls force STRICT (test 'defaults bare guarded fetches to trusted env proxy only inside the sandbox')
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: Dockerfile lines 220-234 (comments), 368-404 (implementation), 247 (removal criteria) — references fix(sandbox): cron preflight inference.local uses trusted env-proxy mode #5129 but no specific OpenClaw issue; PRA-3 blocker for broad default risk

PRA-5 Required — Patch 4 broad default may bypass cert pinning/mTLS for bare fetchWithSsrFGuard callsites

  • Location: Dockerfile:210
  • Category: security
  • Problem: Patch 4 changes the default for ALL bare fetchWithSsrFGuard callsites inside the sandbox from STRICT (DNS-pinned direct) to TRUSTED_ENV_PROXY (proxied). The patch preserves STRICT only when callers explicitly pass dispatcherPolicy.connect, dispatcherPolicy.proxyTls, or an explicit mode. However, callsites that rely on STRICT's direct TLS verification for certificate pinning or mTLS WITHOUT explicitly passing these options will now silently route through the proxy, potentially bypassing certificate validation. The Google Chat cert fetch (www.googleapis.com/service\_accounts/v1/metadata/x509/...\) is a confirmed example — it previously used STRICT mode for direct TLS verification; now it uses the proxy. The new runtime verifier confirms this behavior change (test 'bare omitted-mode fetches skip pinned DNS in sandbox').
  • Impact: A callsite that needs direct TLS verification could silently route through the proxy, bypassing certificate pinning or mTLS validation, weakening SSRF/mTLS guarantees for that specific call. Unknown set of callsites in OpenClaw dist may be affected.
  • Required action: Add a build-time audit step that scans the OpenClaw dist for bare fetchWithSsrFGuard callsites and flags any that pass security-relevant options (dispatcherPolicy.connect, dispatcherPolicy.proxyTls, certificate validation config, mTLS settings) or are known to require direct TLS verification. Alternatively, narrow the default to only apply to callsites with specific auditContext values (like the old Patch 6 did for cron preflight), or document in removal criteria that this patch must be reverted if any callsite is found to require STRICT mode for security.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Run the patched OpenClaw dist and grep for fetchWithSsrFGuard callsites; verify none pass dispatcherPolicy.connect, dispatcherPolicy.proxyTls, or other STRICT-requiring options when mode is omitted. Check for patterns like 'dispatcherPolicy', 'mode: "strict"', 'tls', 'cert', 'mTLS' in call arguments.
  • Missing regression test: A test that enumerates all fetchWithSsrFGuard callsites in the reviewed OpenClaw dist and asserts none pass dispatcherPolicy.connect, dispatcherPolicy.proxyTls, or other STRICT-requiring options when mode is omitted.
  • Done when: The required change is committed and verification passes: Run the patched OpenClaw dist and grep for fetchWithSsrFGuard callsites; verify none pass dispatcherPolicy.connect, dispatcherPolicy.proxyTls, or other STRICT-requiring options when mode is omitted. Check for patterns like 'dispatcherPolicy', 'mode: "strict"', 'tls', 'cert', 'mTLS' in call arguments.
  • Evidence: Dockerfile lines 368-404 implement the new central default. Test 'defaults bare guarded fetches to trusted env proxy only inside the sandbox' (line 1106) verifies resolver behavior but does not audit actual OpenClaw dist callsites. Runtime verifier test 'bare omitted-mode fetches skip pinned DNS in sandbox' confirms Google Chat cert fetch now uses proxy without local DNS.

PRA-6 Resolve/justify — Patch 2 removal criteria lacks upstream OpenClaw issue reference

  • Location: Dockerfile:185
  • Category: security
  • Problem: Patch 2 injects an env-gated early return in assertExplicitProxyAllowed that skips the proxy hostname validation against the target's SSRF allowlist. This is a localized workaround for an upstream OpenClaw design flaw. The removal criteria references no upstream OpenClaw issue/PR. Without a tracked upstream fix, this workaround may persist indefinitely and the source boundary remains unaddressed in OpenClaw.
  • Impact: Workaround may persist indefinitely without upstream tracking; source boundary (why proxy hostname should not be validated against target allowlist) unclear to future maintainers.
  • Recommended action: Add explicit references to upstream OpenClaw issues/PRs for Patch 2's removal condition (e.g., 'openclaw/openclaw#XXXXX'). File or reference an upstream issue for the assertExplicitProxyAllowed design flaw. Add a TODO comment with check-date or link to a tracking issue in NemoClaw.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Check Dockerfile comments for Patch 2 removal criteria — search for 'openclaw/openclaw#' or upstream issue references.
  • Missing regression test: A test that verifies the bypass only activates when OPENSHELL_SANDBOX=1 and that the L7 proxy's policy enforcement is sufficient defense-in-depth (already partially covered by existing tests).
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Check Dockerfile comments for Patch 2 removal criteria — search for 'openclaw/openclaw#' or upstream issue references.
  • Evidence: Dockerfile lines 191-211 (comments) and 303-327 (implementation) — removal criteria comment at line 241 has no upstream issue reference.

PRA-7 Resolve/justify — Patch 2b removal criteria lacks upstream OpenClaw issue reference; subdomain bypass unverified

  • Location: Dockerfile:185
  • Category: security
  • Problem: Patch 2b allows host.openshell.internal through web_fetch's trusted-env-proxy policy by injecting it into allowedHostnames only when OPENSHELL_SANDBOX=1 and useEnvProxy is true. This is a localized workaround. The removal criteria references no upstream OpenClaw issue. The subdomain bypass risk (host.openshell.internal.evil.com) depends on OpenClaw's normalizeHostname doing exact matching — this needs verification against the actual OpenClaw dist.
  • Impact: If normalizeHostname does suffix matching, 'host.openshell.internal.attacker.com' could bypass SSRF. Workaround lacks upstream tracking.
  • Recommended action: Add a direct link to the upstream OpenClaw issue tracking web_fetch trusted-proxy SSRF policy surface. Verify the normalizeHostname function in the reviewed OpenClaw 2026.5.27 dist does exact matching (no suffix/prefix matching) for allowedHostnames. Add a test fixture that attempts subdomain bypass.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Grep the OpenClaw 2026.5.27 dist for 'normalizeHostname' and inspect its implementation. Search for 'normalizeHostname' in the dist.
  • Missing regression test: A test fixture that attempts subdomain bypass (e.g., 'host.openshell.internal.attacker.com') against the actual patched fetch guard and verifies it's blocked.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Grep the OpenClaw 2026.5.27 dist for 'normalizeHostname' and inspect its implementation. Search for 'normalizeHostname' in the dist.
  • Evidence: Dockerfile lines 228-240 (comments) and 345-366 (implementation) — removal criteria at line 244 has no upstream issue reference. Test 'anchors web_fetch host-gateway policy' verifies reviewed SSRF policy shape but not actual dist's normalizeHostname.

PRA-8 Resolve/justify — Patch 2 bypasses entire assertExplicitProxyAllowed function, not just hostname check

  • Location: Dockerfile:250
  • Category: security
  • Problem: Patch 2's env-gated bypass skips the ENTIRE assertExplicitProxyAllowed function, not just the proxy hostname check. This means if assertExplicitProxyAllowed gains additional security checks in the future (e.g., proxy URL scheme validation, proxy authentication checks), they would also be bypassed in the sandbox. The L7 proxy provides defense-in-depth but the bypass is broader than necessary.
  • Impact: Future security checks added to assertExplicitProxyAllowed would be silently bypassed in sandbox. Defense-in-depth reduced.
  • Recommended action: Narrow the bypass to only skip the proxy hostname check (the resolvePinnedHostnameWithPolicy call with target's policy), not the entire function. Or verify that the L7 proxy's policy enforcement is sufficient defense-in-depth for all proxy-mediated fetches. Add a test that verifies the bypass doesn't weaken SSRF for non-proxy fetches.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the sed replacement for Patch 2 in Dockerfile (line 311) — it wraps the entire function body with an early return.
  • Missing regression test: A test that verifies non-proxy fetches (strict/direct mode) still enforce full SSRF checks when OPENSHELL_SANDBOX=1.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the sed replacement for Patch 2 in Dockerfile (line 311) — it wraps the entire function body with an early return.
  • Evidence: Dockerfile line 311: sed replaces entire function body with early return. Test 'rewrites strict media fetch exports and makes proxy validation sandbox-aware' verifies proxyChecks empty in sandbox but doesn't test non-proxy paths.

PRA-9 Resolve/justify — Patch 4 sed replacement fragile to minification; whole-file verification incomplete

  • Location: Dockerfile:370
  • Category: correctness
  • Problem: Patch 4 uses complex sed replacements with multi-line range matching ('/function resolveGuardedFetchMode(params)/,/return GUARDED_FETCH_MODE.STRICT;/'). Sed is fragile to minification changes, whitespace differences, or comment insertion. The verification checks for leftover 'dangerouslyAllowEnvProxyWithoutPinnedDns' and 'params.proxy === "env"' patterns, but only within the extracted resolver block, not the whole file.
  • Impact: Patch may fail to apply or apply incorrectly on minified dist variations. Deprecated patterns could survive outside resolver block.
  • Recommended action: Extract Patch 4 logic into a Node.js patch script (following the pattern of patch-openclaw-tool-catalog.js) for robust AST-based transformations. At minimum, add a whole-file grep verification after Patch 4 application that searches for any remaining 'params.proxy === "env"' or 'dangerouslyAllowEnvProxyWithoutPinnedDns' patterns in the entire patched file.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Check Dockerfile Patch 4 verification (lines 391-396) — it extracts resolver block with sed and greps that block, not the whole file.
  • Missing regression test: A test that applies Patch 4 to a fixture with the deprecated patterns outside the resolver block and verifies the build fails.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Check Dockerfile Patch 4 verification (lines 391-396) — it extracts resolver block with sed and greps that block, not the whole file.
  • Evidence: Dockerfile lines 380-396: two sed commands with multi-line range, verification only on extracted resolver block.

PRA-10 Resolve/justify — Version coordination with PR #5595 (2026.6.9) needed

PRA-11 Resolve/justify — All patch removal criteria lack upstream OpenClaw issue references

  • Location: Dockerfile:185
  • Category: acceptance
  • Problem: Removal criteria for Patches 1, 2, 2b, and 4 lack explicit references to upstream OpenClaw issues/PRs. Patch 1 references a general deprecation condition but no issue number. Patch 2 and 2b reference design flaws but no upstream tracking. Patch 4 references NemoClaw sandbox: Gemini web_search fails with EAI_AGAIN until Google host + node are allowed, and trusted proxy still does local DNS lookup #396, @openclaw/googlechat cert fetch fails: SSRF guard's per-request dispatcher bypasses NemoClaw's nemoclaw-http-proxy-fix.js global-agent hook #4687 and openclaw#5129 but the removal condition 'when OpenClaw defaults bare fetchWithSsrFGuard calls to trusted_env_proxy in an OpenShell sandbox' is vague — no specific OpenClaw issue/PR to track.
  • Impact: Cannot track upstream progress for patch removal. Maintainers cannot verify if upstream fix addresses the root cause.
  • Recommended action: Add explicit upstream issue references for each patch's removal condition. For Patch 4, reference the specific OpenClaw issue that would implement the sandbox-aware default.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Search Dockerfile removal criteria comments for 'openclaw/openclaw#' or 'NVIDIA/NemoClaw#' patterns.
  • Missing regression test: None — this is a documentation/tracking gap.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Search Dockerfile removal criteria comments for 'openclaw/openclaw#' or 'NVIDIA/NemoClaw#' patterns.
  • Evidence: Dockerfile lines 241-250 (removal criteria comments) — no 'openclaw/openclaw#' references found.

PRA-12 Resolve/justify — Patch 4 skip condition unclear — should require BOTH resolver function AND legacy opt-in absent

  • Location: Dockerfile:390
  • Category: correctness
  • Problem: Patch 4 skip condition checks for 'resolveGuardedFetchMode' function and 'dangerouslyAllowEnvProxyWithoutPinnedDns' references. The comment says 'has no guarded-fetch mode resolver' but the check is for either the resolver function OR the dangerous opt-in reference. If only the resolver is gone but dangerous opt-in remains, the dist shape is ambiguous and should fail closed.
  • Impact: Ambiguous dist shape could be silently skipped, leaving deprecated opt-in unpatched.
  • Recommended action: Clarify the skip condition comment to explain that the presence of either the resolver function OR the legacy dangerous opt-in reference means the dist shape is not a clean 'no guarded-fetch mode resolver' layout and requires manual review. Consider adding a version-specific classifier for 2026.6.9+.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read Dockerfile lines 405-412 (else branch for Patch 4) — mode_refs greps for both 'resolveGuardedFetchMode' and 'dangerouslyAllowEnvProxyWithoutPinnedDns'.
  • Missing regression test: A test that provides a fixture with resolver missing but dangerous opt-in present and verifies build fails.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read Dockerfile lines 405-412 (else branch for Patch 4) — mode_refs greps for both 'resolveGuardedFetchMode' and 'dangerouslyAllowEnvProxyWithoutPinnedDns'.
  • Evidence: Dockerfile lines 405-412: mode_refs includes both patterns; error message says 'has no guarded-fetch mode resolver' but checks for either.

PRA-13 Resolve/justify — Patch 2b sed robustness to minification variations unverified

  • Location: Dockerfile:300
  • Category: security
  • Problem: Patch 2b's sed replacement uses a complex regex that matches the exact reviewed web_fetch callsite shape. If OpenClaw 2026.5.27's dist has minification variations (e.g., different spacing, renamed variables), the sed may fail to match or match incorrectly. The verification greps for the injected marker but doesn't verify the policy object spread is correct.
  • Impact: Patch may fail to apply or produce incorrect policy object on minified dist variations.
  • Recommended action: Add verification that the patched hostGatewayPolicy object correctly spreads resolved.policy and adds allowedHostnames. Consider extracting Patch 2b to a Node.js patch script for robustness.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the Patch 2b sed replacement in Dockerfile (lines 349-351) and the grep verification that follows (line 350).
  • Missing regression test: A test that applies Patch 2b to a fixture with minification variations and verifies correct policy spreading.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the Patch 2b sed replacement in Dockerfile (lines 349-351) and the grep verification that follows (line 350).
  • Evidence: Dockerfile lines 349-351: complex sed with exact string match; verification only greps for injected marker comment.

PRA-14 Improvement — Missing cron preflight end-to-end test with real fetchWithSsrFGuard implementation

  • Location: test/fetch-guard-patch-regression.test.ts:1100
  • Category: tests
  • Problem: The new runtime verifier provides excellent build-time verification but there's no end-to-end test that runs the actual cron preflight code path with the real fetchWithSsrFGuard implementation to verify it now works via the central Patch 4 default (since Patch 6 was removed). The test 'leaves cron preflight callsites unmodified because omitted mode is patched centrally' verifies the callsite is unmodified and the resolver returns trusted_env_proxy, but doesn't test the full fetchWithSsrFGuard execution path for the cron preflight.
  • Impact: Cron preflight path not verified end-to-end; regression risk if fetchWithSsrFGuard implementation changes.
  • Suggested action: Add an integration-style test that mocks fetchWithSsrFGuard with the cron preflight policy (hostnameAllowlist: ['inference.local']) and verifies it resolves via proxy when OPENSHELL_SANDBOX=1, and that SSRF denies (private IPs, .internal) are still enforced.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Check test file for cron preflight end-to-end test — search for 'cron' and 'inference.local' in test cases.
  • Missing regression test: An integration-style test that mocks fetchWithSsrFGuard with the cron preflight policy and verifies proxy resolution and SSRF denies.
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: Test file has 'leaves cron preflight callsites unmodified because omitted mode is patched centrally' (line 1323) but no full fetchWithSsrFGuard execution test for cron preflight.

PRA-15 Improvement — Missing Google Chat dispatcher policy end-to-end test

  • Location: test/fetch-guard-patch-regression.test.ts:1106
  • Category: tests
  • Problem: The Google Chat cert fetch is a critical callsite that changed from STRICT to TRUSTED_ENV_PROXY. The runtime verifier tests this path, but there's no test that mocks @openclaw/googlechat's resolveGoogleAuthDispatcherPolicy and verifies: (1) bare call defaults to trusted_env_proxy in sandbox, (2) explicit-proxy mode respected, (3) env-proxy mode respected, (4) direct mode (TLS options) respected. This would verify the dispatcherPolicy.connect/proxyTls protection works for the actual Google Chat integration.
  • Impact: Google Chat dispatcher policy scenarios not verified end-to-end; connect/proxyTls STRICT preservation untested for real integration.
  • Suggested action: Add a test that mocks @openclaw/googlechat's resolveGoogleAuthDispatcherPolicy and verifies the four dispatcher policy scenarios.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Check test file for Google Chat dispatcher policy tests — search for 'googlechat' or 'resolveGoogleAuthDispatcherPolicy'.
  • Missing regression test: A test that mocks @openclaw/googlechat's resolveGoogleAuthDispatcherPolicy and verifies all four dispatcher policy scenarios.
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: Runtime verifier tests Google Chat cert URL but only for bare call; no test for explicit-proxy, env-proxy, or direct modes.

PRA-16 Improvement — Test version constant not derived from Dockerfile ARG; drift risk

  • Location: test/fetch-guard-patch-regression.test.ts:16
  • Category: tests
  • Problem: The test constant CURRENT_REVIEWED_OPENCLAW_PATCH_CLASSIFIER_VERSION is manually maintained and can drift from the Dockerfile ARG OPENCLAW_VERSION. The test 'requires classifier review and integrity evidence when the OpenClaw build pin changes' checks they match, but this only catches drift at test time. Better to derive the test version from the Dockerfile ARG at test runtime.
  • Impact: Version drift between Dockerfile and tests could go undetected until test run.
  • Suggested action: Either derive the test version from the Dockerfile ARG at test runtime (read Dockerfile and parse ARG), or add a test that fails if the Dockerfile OPENCLAW_VERSION differs from CURRENT_REVIEWED_OPENCLAW_PATCH_CLASSIFIER_VERSION without updated shape constants.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Check test file for version derivation — search for 'readDockerfileOpenClawVersion' and 'CURRENT_REVIEWED_OPENCLAW_PATCH_CLASSIFIER_VERSION'.
  • Missing regression test: A test that reads the Dockerfile ARG at runtime and compares against the test constant.
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: Test line 16: const CURRENT_REVIEWED_OPENCLAW_PATCH_CLASSIFIER_VERSION = "2026.5.27"; line 200: readDockerfileOpenClawVersion() reads Dockerfile ARG but comparison only in 'requires classifier review' test.

PRA-17 Improvement — Runtime verifier missing coverage for host gateway, web_fetch, cron preflight, and explicit connect/proxyTls

  • Location: scripts/verify-openclaw-fetch-guard-runtime.ts:1
  • Category: correctness
  • Problem: The new runtime verifier is excellent but only tests the Google Chat cert URL and a fixed set of blocked targets. It doesn't test the host.openshell.internal gateway path (Patch 2b), the web_fetch path, or the cron preflight path with inference.local. The verifier also doesn't test that explicit dispatcherPolicy.connect/proxyTls correctly forces STRICT mode.
  • Impact: Critical fetch paths not verified at build time; regression risk for Patch 2b, web_fetch, cron preflight, and STRICT preservation.
  • Suggested action: Extend the runtime verifier to cover: (1) host.openshell.internal gateway path, (2) web_fetch with useEnvProxy, (3) cron preflight with inference.local, (4) explicit dispatcherPolicy.connect/proxyTls forcing STRICT mode. This would make the build-time verification comprehensive.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Read verify-openclaw-fetch-guard-runtime.ts and check BLOCKED_TARGETS and verifyGoogleCertProxyPath — only Google Chat cert URL is tested for positive proxy path.
  • Missing regression test: Extended runtime verifier test cases for all critical fetch paths.
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: verify-openclaw-fetch-guard-runtime.ts lines 47-57 (BLOCKED_TARGETS), lines 130-170 (verifyGoogleCertProxyPath) — only Google Chat cert URL tested for positive path.

PRA-18 Improvement — Custom test framework duplicates Dockerfile logic; consider shared helper

  • Location: test/fetch-guard-patch-regression.test.ts:1
  • Category: correctness
  • Problem: The test file has grown significantly (1434 lines) with many fixture generators and patch simulation helpers. The runDockerfilePatchBlock function extracts Dockerfile RUN commands and executes them with a fake sed. This is a custom test framework that duplicates Dockerfile logic. While effective, it creates maintenance burden and divergence risk.
  • Impact: Maintenance burden; divergence risk between Dockerfile and test simulation.
  • Suggested action: Consider extracting the patch simulation logic into a shared test helper module. The current approach is acceptable for regression guarding but could be simplified.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Review test file structure — note the dockerRunCommandBetween, runDockerfilePatchBlock, runFetchGuardPatchBlock, createSedWrapper helpers.
  • Missing regression test: None — this is a maintainability concern.
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: Test file lines 200-350: dockerRunCommandBetween, runDockerfilePatchBlock, runFetchGuardPatchBlock, createSedWrapper functions.

PRA-19 Improvement — Extract Patch 4 sed logic to Node.js patch script for robustness

  • Location: Dockerfile:370
  • Category: correctness
  • Problem: Patch 4 uses complex sed replacements that are fragile to minification. The new verify-openclaw-fetch-guard-runtime.mjs demonstrates the pattern of using Node.js for robust transformations. Extracting Patch 4 to a Node.js script would allow AST-based parsing, better testability, and eliminate regex fragility.
  • Impact: Reduces risk of patch misapplication on dist variations; improves maintainability.
  • Suggested action: Create patch-openclaw-fetch-guard-mode.js following the pattern of patch-openclaw-tool-catalog.js and patch-openclaw-chat-send.js. Move the resolver transformation logic there. Keep the Dockerfile classification logic (detecting dist shape) but delegate the transformation to the Node script.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Check Dockerfile Patch 4 implementation (lines 368-404) — all sed-based. Compare to patch-openclaw-tool-catalog.js pattern (lines 480-485).
  • Missing regression test: Unit tests for the Node.js patch script covering all dist shape variations.
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: Dockerfile lines 368-404: 36 lines of sed logic. Existing pattern at lines 480-485: node /usr/local/lib/nemoclaw/patch-openclaw-tool-catalog.js.

PRA-20 Improvement — Add whole-file grep for deprecated patterns after Patch 4 application

  • Location: Dockerfile:370
  • Category: correctness
  • Problem: Patch 4 verification only checks the extracted resolver block for leftover 'params.proxy === "env"' and 'dangerouslyAllowEnvProxyWithoutPinnedDns' patterns. A whole-file grep would catch any surviving instances elsewhere in the patched file.
  • Impact: Deprecated patterns could survive outside resolver block, causing unexpected behavior.
  • Suggested action: Add a whole-file grep verification after Patch 4 application that searches for any remaining 'params.proxy === "env"' or 'dangerouslyAllowEnvProxyWithoutPinnedDns' patterns in the entire patched file and fails if found.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Check Dockerfile Patch 4 verification (lines 391-396) — only checks extracted resolver block.
  • Missing regression test: A test that applies Patch 4 to a fixture with deprecated patterns outside resolver block and verifies build fails.
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: Dockerfile lines 391-396: patched_resolver extracted with sed, then grepped. No whole-file check.

Workflow run details

This is an automated, non-binding review; it still expects maintainers and agents to respond to each required or warning item. Treat suggestions as current-PR improvements when they touch changed code; defer only with maintainer rationale or a linked follow-up. A human maintainer must make the final merge decision.

@github-actions

Copy link
Copy Markdown
Contributor

Vitest E2E Target Results — ✅ All requested jobs passed

Run: 28424214692
Workflow ref: fix/openclaw-fetch-guard-default-proxy
Requested targets: (default — all supported)
Requested jobs: cron-preflight-inference-local,inference-routing,network-policy,common-egress-agent
Summary: 4 passed, 0 failed, 0 cancelled, 0 skipped

Job Result
common-egress-agent ✅ success
cron-preflight-inference-local ✅ success
inference-routing ✅ success
network-policy ✅ success

@github-actions

Copy link
Copy Markdown
Contributor

Vitest E2E Target Results — ✅ All requested jobs passed

Run: 28425869865
Workflow ref: fix/openclaw-fetch-guard-default-proxy
Requested targets: (default — all supported)
Requested jobs: cron-preflight-inference-local,inference-routing,network-policy,common-egress-agent
Summary: 4 passed, 0 failed, 0 cancelled, 0 skipped

Job Result
common-egress-agent ✅ success
cron-preflight-inference-local ✅ success
inference-routing ✅ success
network-policy ✅ success

sandl99 and others added 3 commits June 30, 2026 12:38
Signed-off-by: San Dang <sdang@nvidia.com>
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
Signed-off-by: San Dang <sdang@nvidia.com>
@github-actions

Copy link
Copy Markdown
Contributor

Vitest E2E Target Results — ✅ All selected jobs passed

Run: 28427201204
Workflow ref: fix/openclaw-fetch-guard-default-proxy
Requested targets: ubuntu-repo-cloud-openclaw
Requested jobs: (default — all default-enabled free-standing jobs; explicit-only jobs such as jetson-nvmap-gpu and sandbox-rlimits-connect are skipped unless selected)
Summary: 1 passed, 0 failed, 0 cancelled, 0 skipped

Job Result
live ✅ success

@github-actions

Copy link
Copy Markdown
Contributor

Vitest E2E Target Results — ✅ All requested jobs passed

Run: 28427258935
Workflow ref: fix/openclaw-fetch-guard-default-proxy
Requested targets: (default — all supported)
Requested jobs: cron-preflight-inference-local,network-policy,model-router-provider-routed-inference
Summary: 3 passed, 0 failed, 0 cancelled, 0 skipped

Job Result
cron-preflight-inference-local ✅ success
model-router-provider-routed-inference ✅ success
network-policy ✅ success

Signed-off-by: San Dang <sdang@nvidia.com>
@cv

cv commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

Maintainer status — hard defer

Current head: fa2120f35af993db0418be45fb97259c39c24b22

Exact-head verification is green:

  • Required typed E2E ubuntu-repo-cloud-openclaw: run 28427201204 — passed.
  • Focused E2E cron-preflight-inference-local, network-policy, and model-router-provider-routed-inference: run 28427258935 — all passed.
  • Required CI, security scanning, self-hosted sandbox image builds, and test-e2e-sandbox: green at this head.

The PR is still not merge-ready because both exact-head review advisors report merge_after_fixes:

  • GPT-5.5: 0 required fixes, 2 unresolved warnings. The open security evidence gap is the real patched compiled OpenClaw/env-proxy path, including no-local-DNS behavior, private/metadata redirect denial, and the Google Chat receive/JWT path.
  • Nemotron Ultra: 1 required fix and 9 unresolved warnings. Required PRA-3 is a build-time audit of omitted-mode fetchWithSsrFGuard callsites for strict-only semantics such as dispatcherPolicy.connect, dispatcherPolicy.proxyTls, certificate pinning, mTLS, or direct connectivity.

Sequencing is also unresolved with #5595, which upgrades OpenClaw to 2026.6.9 and overlaps the same Dockerfile and fetch-guard classifier tests. The landing order and exact 2026.6.9 patch shape must be coordinated, followed by a fresh advisor/CI pass.

Status: defer; do not merge until the advisor gates and #5595 sequencing are resolved or explicitly adjudicated by a maintainer.

Signed-off-by: San Dang <sdang@nvidia.com>
@cv

cv commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

Maintainer security gate for exact head fa2120f: do not merge into v0.0.71.

The pinned openclaw@2026.5.27 artifact contains 93 fetchWithSsrFGuard calls. 86 use a plain object with no mode or dispatcher policy, 4 more can dynamically omit mode, and only 3 are always explicit. This PR globally reclassifies omitted-mode calls from STRICT to TRUSTED_ENV_PROXY inside the sandbox. That removes resolvePinnedHostnameWithPolicy, private/reserved-address rejection, and DNS pinning from paths that include webhooks, downloads, media, provider endpoints, browser/CDP, and messaging APIs. The current tests assert zero pinned-DNS resolution and cover only literal blocked hosts; they do not cover a public-looking name resolving or rebinding to loopback, link-local, metadata, or private space.

This is also a regression from current main: the PR replaces the existing strict-preserving managed-proxy Patch 4 and narrow cron Patch 6. It should retain those mainline patches. Any additional exception must be reduced to audited callsite-specific trusted mode for demonstrably operator-controlled endpoints, with exact 2026.5.27 published-dist proof and negative DNS-answer/rebinding tests. PR #5595 later ports the strict-preserving design to 2026.6.9 and must not be mechanically combined with this broad rewrite.

No CI, approval, or E2E result can override this source-level SSRF boundary failure. The branch needs a security-preserving redesign before further release consideration.

@cv
cv merged commit c17616f into main Jun 30, 2026
42 checks passed
@cv
cv deleted the fix/openclaw-fetch-guard-default-proxy branch June 30, 2026 08:55
cv added a commit that referenced this pull request Jun 30, 2026
…proxy (#6051)

Reverts #5713, merged by accident

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Improved sandbox proxy handling so unconfigured strict network
requests are routed correctly in OpenShell environments.
* Added safer cron preflight behavior to avoid breaking DNS-pinned
strict-mode runs in proxy-only sandboxes.

* **Chores**
* Removed an unused runtime verification step and simplified the build
process.
* Updated related automation and test coverage to match the new proxy
and patching behavior.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Signed-off-by: Carlos Villela <cv@lixo.org>
Hadar301 pushed a commit to Hadar301/NemoClaw-OpenShift that referenced this pull request Jul 12, 2026
…#5713)

## Summary

Broadens the OpenClaw compatibility patch so `resolveGuardedFetchMode()`
defaults omitted guarded-fetch modes to `trusted_env_proxy` inside
OpenShell sandboxes. This avoids local DNS lookups for bare
`fetchWithSsrFGuard` callers while preserving explicit modes and strict
behavior outside `OPENSHELL_SANDBOX=1`.

## Related Issue

Related: NVIDIA#396 (fetch-guard/local DNS portion only; Gemini policy/docs
remain out of scope)
Fixes NVIDIA#4687
Related: NVIDIA#5129
Related: NVIDIA#5592

## Changes

- Patch OpenClaw's central guarded-fetch mode resolver in the sandbox
image instead of rewriting individual call sites.
- Remove the deprecated `proxy: "env"` compatibility branch from the
patched resolver and drop the old cron-preflight call-site patch.
- Cover additional bare `fetchWithSsrFGuard` users, including the
Mattermost/OpenClaw call site discussed in NVIDIA#5592.
- Update fetch-guard patch regression tests for sandbox defaults,
explicit-mode precedence, out-of-sandbox strict behavior, and removal of
the narrower Patch 6 rewrite.

## Localized compatibility patch review

- **Invalid state:** OpenClaw 2026.5.27 resolves an omitted
guarded-fetch mode to strict DNS pinning. In an OpenShell proxy-only
sandbox, that performs local DNS before proxy dispatch, so sandbox-only
and proxy-routed names fail before policy enforcement.
- **Source boundary:** NemoClaw consumes the pinned compiled OpenClaw
distribution in the sandbox image; it does not own the upstream resolver
source. The image build therefore classifies and patches the reviewed
`resolveGuardedFetchMode()` shape centrally and fails closed if that
shape drifts.
- **Source-fix constraint:** The durable fix belongs in OpenClaw: either
select `trusted_env_proxy` for OpenShell sandboxes at the resolver
boundary or make every sandbox-sensitive caller pass that mode
explicitly. A permanent NemoClaw fork of the third-party runtime is out
of scope.
- **Regression proof:** `test/fetch-guard-patch-regression.test.ts`
verifies the reviewed resolver shape, explicit-mode precedence,
sandbox-only default, strict behavior outside the sandbox, removal of
the deprecated opt-in, representative SSRF denials, and fail-closed
drift handling. The exact merged head passes all 23 focused tests.
- **Removal condition:** Remove Patch 4 when the pinned OpenClaw release
provides an equivalent OpenShell-aware default, or when every
sandbox-sensitive caller explicitly selects trusted proxy mode and the
runtime acceptance checks pass without this patch.

## Security boundary and E2E

Inspection of the pinned OpenClaw 2026.5.27 implementation confirms that
explicit modes still override the default, hostname validation runs
before proxy dispatcher construction,
loopback/metadata/private/special-use IPv4 and IPv6 literals remain
rejected, and redirects are handled manually and revalidated on each
hop. DNS-resolution enforcement intentionally moves to the OpenShell L7
proxy and network-policy boundary only for omitted-mode calls inside the
sandbox.

A unified exact-head E2E dispatch covers
`cron-preflight-inference-local`, `inference-routing`, `network-policy`,
and `common-egress-agent`:
https://github.com/NVIDIA/NemoClaw/actions/runs/28424214692

## Type of Change

- [x] Code change (feature, bug fix, or refactor)
- [ ] Code change with doc updates
- [ ] Doc only (prose changes, no code sample modifications)
- [ ] Doc only (includes code sample changes)

## Verification

- [x] PR description includes the DCO sign-off declaration and every
commit appears as `Verified` in GitHub
- [x] Normal commit and push hooks passed on the current head
- [x] Targeted test passes: 23/23
- [x] Tests added or updated for changed behavior
- [x] No secrets, API keys, or credentials committed
- [ ] Exact-head unified E2E is passing (in progress)

---

Signed-off-by: San Dang <sdang@nvidia.com>

---------

Signed-off-by: San Dang <sdang@nvidia.com>
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
Co-authored-by: Carlos Villela <cvillela@nvidia.com>
Hadar301 pushed a commit to Hadar301/NemoClaw-OpenShift that referenced this pull request Jul 12, 2026
…proxy (NVIDIA#6051)

Reverts NVIDIA#5713, merged by accident

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Improved sandbox proxy handling so unconfigured strict network
requests are routed correctly in OpenShell environments.
* Added safer cron preflight behavior to avoid breaking DNS-pinned
strict-mode runs in proxy-only sandboxes.

* **Chores**
* Removed an unused runtime verification step and simplified the build
process.
* Updated related automation and test coverage to match the new proxy
and patching behavior.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Signed-off-by: Carlos Villela <cv@lixo.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: security Security controls, permissions, secrets, or hardening integration: openclaw OpenClaw integration behavior

Projects

None yet

Development

Successfully merging this pull request may close these issues.

@openclaw/googlechat cert fetch fails: SSRF guard's per-request dispatcher bypasses NemoClaw's nemoclaw-http-proxy-fix.js global-agent hook

4 participants