hermes - 💡(How to fix) Fix SSRF check blocks web tools inside NVIDIA OpenShell sandbox (DNS unavailable by design)

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

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

GitHub issue graph ai analysis

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

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

Helpful · Quick feedback

Loading…

When running Hermes Agent inside an NVIDIA OpenShell sandbox, the web_extract and web_search tools always fail with:

"error": "Blocked: URL targets a private or internal network address"

This happens because OpenShell sandboxes route all egress through an L7 proxy (HTTPS_PROXY=http://10.200.0.1:3128). Direct DNS resolution (socket.getaddrinfo) is intentionally blocked at the network level — only HTTP/HTTPS traffic through the proxy is allowed.

Error Message

try: addr_info = socket.getaddrinfo(hostname, None, socket.AF_UNSPEC, socket.SOCK_STREAM) except socket.gaierror: # DNS resolution failed — fail closed. logger.warning("Blocked request — DNS resolution failed for: %s", hostname) return False

Root Cause

In tools/url_safety.py, the is_safe_url() function resolves the hostname via socket.getaddrinfo() before any HTTP request is made. When DNS fails, the function returns False (fail-closed, line ~288):

try:
    addr_info = socket.getaddrinfo(hostname, None, socket.AF_UNSPEC, socket.SOCK_STREAM)
except socket.gaierror:
    # DNS resolution failed — fail closed.
    logger.warning("Blocked request — DNS resolution failed for: %s", hostname)
    return False

The security.allow_private_urls: true config and HERMES_ALLOW_PRIVATE_URLS=true env var only skip the private IP check — they do NOT skip the DNS resolution step. So when DNS fails entirely (as in OpenShell), the request is still blocked.

Fix Action

Workaround

Currently the only workaround is patching tools/url_safety.py directly, which breaks on updates.

Code Example

"error": "Blocked: URL targets a private or internal network address"

---

try:
    addr_info = socket.getaddrinfo(hostname, None, socket.AF_UNSPEC, socket.SOCK_STREAM)
except socket.gaierror:
    # DNS resolution failed — fail closed.
    logger.warning("Blocked request — DNS resolution failed for: %s", hostname)
    return False

---

except socket.gaierror:
    if allow_all_private:
        # User opted out of SSRF checks; proxy will resolve DNS
        logger.debug("DNS failed but allow_private_urls=true, permitting: %s", hostname)
        return True
    logger.warning("Blocked request — DNS resolution failed for: %s", hostname)
    return False

---

# Install OpenShell
curl -LsSf https://raw.githubusercontent.com/NVIDIA/OpenShell/main/install.sh | sh

# Create sandbox
openshell sandbox create --name test --from base

# Install Hermes inside
openshell sandbox exec -n test -- pip install "hermes-agent[bedrock]"

# Configure with Firecrawl
openshell sandbox exec -n test -- hermes config set web.provider firecrawl
openshell sandbox exec -n test -- hermes config set security.allow_private_urls true

# This will always fail:
openshell sandbox exec -n test -- hermes -z "Use web_extract on https://example.com"
# → "Blocked: URL targets a private or internal network address"
RAW_BUFFERClick to expand / collapse

Summary

When running Hermes Agent inside an NVIDIA OpenShell sandbox, the web_extract and web_search tools always fail with:

"error": "Blocked: URL targets a private or internal network address"

This happens because OpenShell sandboxes route all egress through an L7 proxy (HTTPS_PROXY=http://10.200.0.1:3128). Direct DNS resolution (socket.getaddrinfo) is intentionally blocked at the network level — only HTTP/HTTPS traffic through the proxy is allowed.

Root Cause

In tools/url_safety.py, the is_safe_url() function resolves the hostname via socket.getaddrinfo() before any HTTP request is made. When DNS fails, the function returns False (fail-closed, line ~288):

try:
    addr_info = socket.getaddrinfo(hostname, None, socket.AF_UNSPEC, socket.SOCK_STREAM)
except socket.gaierror:
    # DNS resolution failed — fail closed.
    logger.warning("Blocked request — DNS resolution failed for: %s", hostname)
    return False

The security.allow_private_urls: true config and HERMES_ALLOW_PRIVATE_URLS=true env var only skip the private IP check — they do NOT skip the DNS resolution step. So when DNS fails entirely (as in OpenShell), the request is still blocked.

Environment

  • Hermes Agent v0.14.0
  • NVIDIA OpenShell v0.0.47 (Docker compute driver)
  • Ubuntu 24.04 arm64
  • Web provider: Firecrawl (FIRECRAWL_API_KEY set)

How OpenShell networking works

OpenShell sandboxes enforce network policy through a transparent proxy:

  • All HTTP/HTTPS traffic goes through HTTPS_PROXY=http://10.200.0.1:3128
  • The proxy resolves DNS on behalf of the container
  • Direct DNS (socket.getaddrinfo) is blocked at the network level
  • httpx, requests, curl all work fine (they use the proxy)
  • Only raw socket DNS resolution fails

This is by design — OpenShell uses the proxy to enforce per-endpoint network policies.

What works

  • httpx.post("https://api.firecrawl.dev/v1/scrape", ...)200 OK (uses proxy)
  • curl https://api.firecrawl.dev/works (uses proxy)
  • Hermes inference via Bedrock → works (boto3 uses proxy)

What fails

  • socket.getaddrinfo("news.ycombinator.com", None)gaierror: Temporary failure in name resolution
  • Therefore is_safe_url()False for ANY URL
  • Therefore web_extract and web_search → always blocked

Proposed Fix

When security.allow_private_urls: true (or HERMES_ALLOW_PRIVATE_URLS=true), the DNS resolution failure should be treated as non-blocking, since:

  1. The user has explicitly opted out of SSRF protection
  2. The actual HTTP request will use the proxy (which resolves DNS itself)
  3. The docstring already mentions "corporate proxies" as a valid use case

Suggested change in is_safe_url():

except socket.gaierror:
    if allow_all_private:
        # User opted out of SSRF checks; proxy will resolve DNS
        logger.debug("DNS failed but allow_private_urls=true, permitting: %s", hostname)
        return True
    logger.warning("Blocked request — DNS resolution failed for: %s", hostname)
    return False

This preserves fail-closed behavior by default while allowing proxy-based environments (OpenShell, corporate proxies, VPNs) to function when the user explicitly enables the toggle.

Workaround

Currently the only workaround is patching tools/url_safety.py directly, which breaks on updates.

Reproduction

# Install OpenShell
curl -LsSf https://raw.githubusercontent.com/NVIDIA/OpenShell/main/install.sh | sh

# Create sandbox
openshell sandbox create --name test --from base

# Install Hermes inside
openshell sandbox exec -n test -- pip install "hermes-agent[bedrock]"

# Configure with Firecrawl
openshell sandbox exec -n test -- hermes config set web.provider firecrawl
openshell sandbox exec -n test -- hermes config set security.allow_private_urls true

# This will always fail:
openshell sandbox exec -n test -- hermes -z "Use web_extract on https://example.com"
# → "Blocked: URL targets a private or internal network address"

Vote matrix · Quick signals

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

Still need to ship something?

×6

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

Back to top recommendations

TRENDING