Skip to content

SSRF guard pinned DNS dispatcher causes model fetch timeouts when autoSelectFamily is enabled #87763

Description

@georgenaz

Summary

Starting from OpenClaw 2026.5.12, the SSRF guard's pinned DNS dispatcher conflicts with Node.js's autoSelectFamily (Happy Eyeballs / RFC 8305), causing model fetch requests to time out after 120 seconds. This makes the gateway completely unresponsive to messages on affected providers.

Environment

  • OpenClaw versions affected: 2026.5.12, 5.18, 5.22, 5.26, 5.27
  • OpenClaw version working: 2026.5.7 (pre-SSRF guard)
  • Node.js: v24.15.0
  • OS: Ubuntu 25.04, Linux 6.14.0-37-generic (x64)
  • Provider: Custom OpenAI-compatible (openai-completions API), baseUrl https://hydragpt.ru/v1
  • IPv6: Available on host, IPv6 route present via SLAAC

Problem

After upgrading from 5.7 to any version ≥5.12, the gateway cannot reach the model provider. Every model fetch request times out at exactly 120 seconds:

[model-fetch] start provider=hydragpt api=openai-completions model=glm-5p1 method=POST url=https://hydragpt.ru/v1/chat/completions timeoutMs=120000 proxy=none policy=custom
... 120 seconds pass ...
[fetch-timeout] fetch timeout after 120000ms operation=fetchWithSsrFGuard url=https://hydragpt.ru/v1/chat/completions
[model-fetch] error provider=hydragpt api=openai-completions model=glm-5p1 elapsedMs=120102 name=TimeoutError message=request timed out
Embedded agent failed before reply: LLM idle timeout (120s): no response from model

Key observation: The provider's request counter on their side does NOT increment — the request never reaches the server at all. The TCP connection is never established.

CLI inference works fine: openclaw infer model run --prompt "hello" --model hydragpt/glm-5p1 returns a response instantly on the same machine and same version. Only the gateway is affected.

Root Cause Analysis

The SSRF guard (introduced in 5.12) creates a pinned DNS dispatcher using undici's Agent with a custom lookup function and autoSelectFamily: true. This combination fails:

1. dedupeAndPreferIpv4 reorders addresses

In ssrf-B5bGsnx-.js, resolvePinnedHostnameWithPolicy calls dedupeAndPreferIpv4 which puts IPv4 addresses before IPv6:

// DNS returns IPv6 first (Node.js default):
// [IPv6: 2606:4700:3037::6815:870, IPv6: 2606:4700:3034::ac43:9d56, IPv4: 104.21.8.112, IPv4: 172.67.157.86]

// dedupeAndPreferIpv4 reorders to:
// [IPv4: 104.21.8.112, IPv4: 172.67.157.86, IPv6: 2606:4700:3037::6815:870, IPv6: 2606:4700:3034::ac43:9d56]

2. Pinned lookup + autoSelectFamily = broken

In undici-runtime-BdHHFzbs.js, withHttp1OnlyDispatcherOptions sets autoSelectFamily from the Node.js system default (true on Node 20+). When undici's autoSelectFamily mechanism calls the pinned lookup with {all: true}, the interaction breaks:

Reproduction:

const undici = require('undici');

const pinnedLookup = (hostname, options, callback) => {
  // Simplified: always return IPv4 only
  callback(null, '104.21.8.112', 4);
};

// This FAILS with "TypeError: Invalid IP address: undefined"
const agent = new undici.Agent({
  allowH2: false,
  connect: {
    lookup: pinnedLookup,
    autoSelectFamily: true,
    autoSelectFamilyAttemptTimeout: 300,
  },
});

// This WORKS
const agent = new undici.Agent({
  allowH2: false,
  connect: {
    lookup: pinnedLookup,
    autoSelectFamily: false,
  },
});

When the pinned lookup returns a single (address, family) result instead of an array for {all: true}, or when autoSelectFamily tries to perform Happy Eyeballs with a lookup that doesn't properly support the dual-family resolution pattern, the connection attempt produces Invalid IP address: undefined or simply hangs until timeout.

3. Telegram module has a workaround, model fetch does not

The Telegram subsystem has its own IPv6 fallback mechanism:

[telegram] fetch fallback: enabling sticky IPv4-only dispatcher (codes=UND_ERR_CONNECT_TIMEOUT)

The model fetch path through buildGuardedModelFetchfetchWithSsrFGuard has no such fallback — it simply hangs until the 120s timeout.

4. Why CLI inference works

openclaw infer model run uses a different code path that does not go through the gateway's SSRF-guarded fetch pipeline, so it connects successfully.

Workaround

Setting NODE_OPTIONS=--no-network-family-autoselection in the gateway systemd service disables Happy Eyeballs, which allows the pinned lookup to work without interference. However, this is a partial workaround because:

  • It forces all connections through the first resolved address (IPv4 when dedupeAndPreferIpv4 is used)
  • For environments where IPv6 is preferred or required (e.g., Telegram in regions with IPv4 blocking), this degrades connectivity
  • The Telegram module loses its ability to try IPv6 when IPv4 fails

Suggested Fix

  1. Short-term: The model fetch path should have the same IPv4/IPv6 fallback mechanism that the Telegram module already implements. If the primary connection attempt fails with a timeout, retry with the alternate address family.

  2. Medium-term: The createPinnedLookup function in ssrf-B5bGsnx-.js should properly support the {all: true} callback format that autoSelectFamily expects, returning an array of {address, family} records. The current implementation handles opts.all but the interaction with undici's Happy Eyeballs still breaks.

  3. Consider: Whether dedupeAndPreferIpv4 is the right default ordering for all environments. In IPv6-capable environments, keeping the system's natural DNS ordering (IPv6 first) may be preferable, especially for services known to work better over IPv6.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High-priority user-facing bug, regression, or broken workflow.clawsweeper:needs-maintainer-reviewClawSweeper marked this issue as needing maintainer review before automation.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.clawsweeper:needs-security-reviewClawSweeper marked this issue as needing security-sensitive review.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:auth-providerAuth, provider routing, model choice, or SecretRef resolution may break.impact:securitySecurity boundary, credential, authz, sandbox, or sensitive-data risk.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions