fix(net): skip DNS pinning before trusted env proxy dispatch#59007
fix(net): skip DNS pinning before trusted env proxy dispatch#59007steipete merged 1 commit intoopenclaw:mainfrom
Conversation
Greptile SummaryThis PR fixes a race condition in
Confidence Score: 5/5Safe to merge — the fix is minimal, targeted, and backed by regression tests covering both the proxy and fallback paths. No P0 or P1 issues found. The logic change is straightforward and matches the described intent: moving DNS resolution into the non-proxy branch avoids failing on local DNS in proxy-only sandboxes. The existing SSRF guarantees are preserved in STRICT mode and in the TRUSTED_ENV_PROXY fallback path. The test additions adequately cover both the new behavior and the regression case. No files require special attention. Reviews (1): Last reviewed commit: "fix(net): skip DNS pinning before truste..." | Re-trigger Greptile |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 03fd2bc1b2
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| const canUseTrustedEnvProxy = | ||
| mode === GUARDED_FETCH_MODE.TRUSTED_ENV_PROXY && hasProxyEnvConfigured(); | ||
| if (canUseTrustedEnvProxy) { |
There was a problem hiding this comment.
Gate trusted-proxy fast path on effective proxy vars
This branch now bypasses resolvePinnedHostnameWithPolicy whenever hasProxyEnvConfigured() is true, but that predicate is broader than EnvHttpProxyAgent behavior (for example ALL_PROXY/all_proxy can satisfy it even though the agent ignores them). In that environment, trusted mode skips DNS pinning and hostname/private-network policy checks and still dispatches with EnvHttpProxyAgent without an actually configured HTTP(S) proxy, which is a security regression from the previous flow that enforced SSRF policy before deciding the dispatcher. Use an EnvHttpProxyAgent-matching proxy check (for example hasEnvHttpProxyConfigured("https")) before taking this fast path.
Useful? React with 👍 / 👎.
|
Thanks for looking at this - we're clearly hitting the same root cause. A few things this PR doesn't cover that #58034 does:
These gaps are security-relevant (Codex flagged #1 as P1 here too), so they'd need addressing before this could merge safely. #58034 already covers all four. |
|
Production confirmation from a proxy-only OpenShell deployment (4 sandboxes, OpenClaw 2026.4.5) We've been hitting this exact DNS-before-proxy ordering bug since deploying OpenClaw behind an HTTP CONNECT proxy in OpenShell sandboxes where DNS is unavailable (the proxy handles resolution via Symptoms we see without a fix:
Our workaround: We maintain a Python patch script ( Production evidence:
This is the correct upstream fix. Would love to see it merged so we can stop maintaining the patch. Happy to test any iterations. Related issues from our deployment:
|
03fd2bc to
2a915fb
Compare
|
Landed via temp rebase onto main.
Thanks @cluster2600! |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2a915fb22d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const pinned = await resolvePinnedHostnameWithPolicy(parsedUrl.hostname, { | ||
| lookupFn: params.lookupFn, | ||
| policy: params.policy, | ||
| }); | ||
| dispatcher = createPinnedDispatcher(pinned, params.dispatcherPolicy, params.policy); |
There was a problem hiding this comment.
Keep hostname policy checks when pinDns is disabled
Moving resolvePinnedHostnameWithPolicy into the final else branch causes the pinDns === false path to skip SSRF validation entirely, not just DNS pinning. In that mode, requests no longer run hostname allowlist or private/special-use IP checks before dispatch, so callers that disable pinning can now reach blocked targets (for example localhost/internal hosts) that were rejected before this commit. Preserve the policy-resolution check (or an equivalent validation step) even when pinDns is false.
Useful? React with 👍 / 👎.
Patches fetchWithWebToolsNetworkGuard in the openclaw container image to set useEnvProxy when HTTPS_PROXY is in the environment. Without this, web_fetch does DNS pinning before checking for a proxy and fails with EAI_AGAIN in OpenShell proxy-only sandboxes. Upstream fix: openclaw/openclaw#59007 (merged but not yet released as of 2026.4.10). Remove this patch once we upgrade to a release with it. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
Fixes
fetchWithSsrFGuard()so trusted env-proxy mode can actually reachEnvHttpProxyAgentbefore any local DNS lookup is attempted.This fixes the remaining proxy-only sandbox failure tracked in #59005. It is the same production gap described in #58034, but rebased cleanly on current
mainand with the fallback test tightened so hostALL_PROXY/all_proxyvalues cannot accidentally satisfy the proxy branch.What changed
Why
#50650fixed the strict-mode env-proxy path, but bothmainandv2026.3.31still resolve DNS before entering the trusted env-proxy branch:In proxy-only sandboxes, that ordering means the request fails on local DNS and never reaches the trusted proxy.
Testing
pnpm exec vitest run --config vitest.unit.config.ts src/infra/net/fetch-guard.ssrf.test.tspnpm checkNotes