iflytek/astron-agent · error · OutboundPolicyError
Outbound hostname is blocked
Error message
Outbound hostname is blocked
What it means
OutboundPolicy.validate_url checks the URL's hostname against the configured domain blacklist before DNS resolution. If the normalized hostname equals a blacklisted rule or is a subdomain of one (matching on label boundaries, including wildcard '*.rule' entries), it raises OutboundPolicyError('Outbound hostname is blocked'). This is the first line of the SSRF/egress defense for tool HTTP calls.
Solutions
- Check DOMAIN_BLACK_LIST (and any '*.domain' wildcard entries) in the link-service environment for the hostname from the tool URL
- If the domain is safe and required, remove or narrow the blacklist entry, or re-register the tool against an allowed domain
- Verify hostname normalization (case, trailing dot, IDNA) is not causing an unintended match
Example fix
// before (env) DOMAIN_BLACK_LIST=internal.example.com // after (allow a required subdomain) DOMAIN_BLACK_LIST=other-internal.example.com
Defensive patterns
Strategy: validation
Validate before calling
def domain_allowed(host, blocked_domains):
h = host.lower().rstrip('.')
return not any(h == d or h.endswith('.' + d) for d in blocked_domains) Try / catch
try:
result = await run.do_call(span)
except CallThirdApiException as e:
if 'hostname is blocked' in str(e.err):
raise DomainBlockedError(e.err) from e
raise Prevention
- Review the tool's domain against DOMAIN_BLACK_LIST at registration time
- Document the blacklist for teams registering new tools
- Use exact, narrow blacklist entries and review wildcard rules periodically
When it happens
Trigger: Calling create_socket_factory or HttpRun._validate_destination with a URL whose host matches an entry in DOMAIN_BLACK_LIST (env), including any subdomain — e.g. blacklist 'evil.com' blocks 'api.evil.com' too.
Common situations: Ops blacklisted a domain that a tool legitimately needs; a suffix collision (e.g. blacklist contains 'notreal.com' and tool uses 'real.com' is NOT matched, but 'x.notreal.com' would be); tool was registered to a domain later added to the blacklist.
Related errors
- MODEL_URL_ILLEGAL_FAILED
- Skill resource URL is not allowed
- MODEL_URL_CHECK_FAILED
- MODEL_URL_CHECK_FAILED
- TOOLBOX_URL_SHORT_NOT_SUPPORTED
AI-assisted analysis of iflytek/astron-agent@5e758547a8 (2026-09-12).
Data as JSON: /api/errors/d549c7cbcb65d0a6.
Report an issue: GitHub.
Appendix: source
Thrown at core/plugin/link/infra/tool_exector/ssrf_guard.py:84
const.IP_WHITE_LIST_KEY,
)
blocked_domains = _parse_domains(os.getenv(const.DOMAIN_BLACK_LIST_KEY, ""))
allowed_private_endpoints = _parse_private_endpoints(
os.getenv(const.PRIVATE_ENDPOINT_ALLOW_LIST_KEY, "")
)
return cls(
blocked_networks,
allowed_literal_networks,
blocked_domains,
allowed_private_endpoints,
)
def validate_url(self, url: str) -> SplitResult:
"""Validate URL syntax and any literal destination before DNS resolution."""
parsed = _parse_http_url(url)
normalized_host = _normalize_hostname(parsed.hostname or "")
if self.is_domain_blocked(normalized_host):
raise OutboundPolicyError("Outbound hostname is blocked")
literal = _parse_ip(normalized_host)
if literal is not None:
self.validate_address(
literal,
allow_private_endpoint=self.is_private_endpoint_allowed(parsed),
allow_literal_exception=True,
)
return parsed
def is_private_endpoint_allowed(self, parsed: SplitResult) -> bool:
"""Return whether deployment configuration authorizes this exact private endpoint."""
# Private exceptions intentionally support only exact plain paths. Keeping
# semicolons in ``SplitResult.path`` prevents matrix parameters (including
# a trailing empty ``;``) from comparing equal to the configured path.
return (
";" not in parsed.path
and _endpoint(parsed) in self.allowed_private_endpointsView on GitHub (pinned to 5e758547a8)