From 931ca437ff2b8e29c3a8f8c0f91cec4329888270 Mon Sep 17 00:00:00 2001 From: sg-architect Date: Tue, 21 Jul 2026 16:43:19 +0800 Subject: [PATCH] fix(url_safety): allow DNS failure in proxy/sandbox environments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the runtime blocks direct DNS (NVIDIA OpenShell, Docker + Squid, corporate proxy with DNS-only-via-proxy), socket.getaddrinfo() fails and is_safe_url() blocks *all* requests — including legitimate public URLs via the configured proxy. Add _proxy_is_configured() helper that checks HTTPS_PROXY, HTTP_PROXY, http_proxy, https_proxy, ALL_PROXY, all_proxy. When DNS fails AND a proxy is configured, delegate DNS resolution to the proxy rather than blocking outright. Blocked hostnames (metadata.google.internal, 169.254.169.254, etc.) are checked BEFORE DNS resolution, so cloud metadata endpoints remain blocked regardless of proxy status. Fixes #32217 --- tools/url_safety.py | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/tools/url_safety.py b/tools/url_safety.py index 27dcc55efd1..a301fdc3f20 100644 --- a/tools/url_safety.py +++ b/tools/url_safety.py @@ -39,6 +39,21 @@ from utils import is_truthy_value logger = logging.getLogger(__name__) +# ── Proxy detection ────────────────────────────────────────── +# Proxy environment variables that indicate the runtime should +# delegate DNS to a proxy rather than attempting direct resolution. +_PROXY_ENV_VARS = ( + "HTTPS_PROXY", "https_proxy", + "HTTP_PROXY", "http_proxy", + "ALL_PROXY", "all_proxy", +) + + +def _proxy_is_configured() -> bool: + """Return True when at least one HTTP proxy env var is set.""" + return any(os.environ.get(v) for v in _PROXY_ENV_VARS) + + def normalize_url_for_request(url: str) -> str: """Return an ASCII-safe HTTP URL for Hermes-owned URL tools. @@ -420,8 +435,21 @@ def is_safe_url(url: str) -> bool: try: addr_info = socket.getaddrinfo(hostname, None, socket.AF_UNSPEC, socket.SOCK_STREAM) except socket.gaierror: - # DNS resolution failed — fail closed. If DNS can't resolve it, - # the HTTP client will also fail, so blocking loses nothing. + # DNS resolution failed. In sandbox / proxy environments + # (NVIDIA OpenShell, Docker + Squid, etc.) the host may + # block direct DNS — only HTTP(S) through the proxy is + # permitted. When a proxy is configured, delegate DNS to + # the proxy rather than blocking the request outright. + # The hostname was already checked against + # _BLOCKED_HOSTNAMES above so metadata endpoints remain + # blocked regardless. + if _proxy_is_configured(): + logger.debug( + "DNS resolution failed for %s — proxy configured, " + "allowing through for proxy-side resolution", + hostname, + ) + return True logger.warning("Blocked request — DNS resolution failed for: %s", hostname) return False