iflytek/astron-agent · error · RemoteResourcePolicyError
Remote resource address is unsafe
Error message
Remote resource address is unsafe
What it means
RemoteResourcePolicyError raised by _validate_destination_address when the target IP is in an explicitly forbidden range: unspecified (0.0.0.0/::), loopback, link-local, multicast, reserved, IPv6 site-local, or any network in _NEVER_CONNECT_NETWORKS (documentation ranges, 6to4, NAT64, etc.). This is the core SSRF guard — these addresses could reach internal infrastructure or loop back to the server itself.
Solutions
- Use a genuinely public URL (the resolved address must be a global unicast address)
- If downloading from your own S3/object storage is intended, configure OSS_TYPE=s3 with OSS_DOWNLOAD_HOST and OSS_BUCKET_NAME/OSS_BUCKET_CONSOLE so private storage origins are whitelisted via _is_configured_storage_url
- Expose the internal resource through a public endpoint instead of the private address
- For local testing, use a public test server (e.g. an HTTPS URL on a public host) rather than localhost
Example fix
// before
await fetch_public_resource("http://127.0.0.1:9000/files/report.pdf") # loopback
// after
# serve through the configured public storage origin
await fetch_public_resource("https://s3.example.com/my-bucket/report.pdf")
# with OSS_TYPE=s3, OSS_DOWNLOAD_HOST=https://s3.example.com, OSS_BUCKET_NAME=my-bucket Defensive patterns
Strategy: try-catch
Validate before calling
import ipaddress, socket
def resolves_to_public(url: str) -> bool:
from urllib.parse import urlsplit
host = urlsplit(url).hostname or ""
try:
infos = socket.getaddrinfo(host, None)
except socket.gaierror:
return False
for info in infos:
addr = ipaddress.ip_address(info[4][0])
if not addr.is_global or addr.is_loopback or addr.is_link_local:
return False
return True Try / catch
from plugin.aitools.common.clients.safe_download import RemoteResourcePolicyError
from plugin.aitools.common.exceptions.exceptions import HTTPClientException
try:
data = await fetch_public_resource(url)
except HTTPClientException as e:
# fetch_public_resource wraps RemoteResourcePolicyError into HTTPClientException
log.warning("Download target rejected (SSRF policy): %s", e)
return None Prevention
- Never pass localhost, 169.254.169.254, or private IPs to the public download API
- Beware hostnames that resolve to private IPs (DNS rebinding); the socket-level check will reject them at connect time
- Serve internal files through a public endpoint or the configured storage origin instead
When it happens
Trigger: fetch_public_resource called with a URL whose host resolves (or is a literal) to a forbidden address, e.g. 'http://127.0.0.1:8000', 'http://169.254.169.254/latest/meta-data' (cloud metadata), 'http://10.0.0.5/file', 'http://[::1]/', or DNS resolving a public-looking hostname to a private IP (caught in the socket_factory at connect time).
Common situations: Pointing the downloader at a local dev server during testing; cloud-metadata SSRF attempts via attacker-supplied URLs; internal service URLs mistakenly given to a public-download API; DNS rebinding where a hostname resolves to a private IP.
Related errors
- HTTPClientError
- MODEL_URL_CHECK_FAILED
- Resolved remote resource address is invalid
- Remote resource returned HTTP
- Remote resource URL authority is invalid
AI-assisted analysis of iflytek/astron-agent@5e758547a8 (2026-09-12).
Data as JSON: /api/errors/8760c35d3292a3aa.
Report an issue: GitHub.
Appendix: source
Thrown at core/plugin/aitools/common/clients/safe_download.py:263
return None
def _validate_destination_address(
address: IpAddress,
*,
allow_private_storage: bool,
) -> None:
canonical = _canonical_address(address)
unsafe_properties = (
canonical.is_unspecified,
canonical.is_loopback,
canonical.is_link_local,
canonical.is_multicast,
canonical.is_reserved,
bool(getattr(canonical, "is_site_local", False)),
)
if any(unsafe_properties) or _matches_any(address, _NEVER_CONNECT_NETWORKS):
raise RemoteResourcePolicyError("Remote resource address is unsafe")
if not allow_private_storage and not canonical.is_global:
raise RemoteResourcePolicyError("Remote resource address is unsafe")
def _is_configured_storage_url(candidate: SplitResult) -> bool:
"""Authorize only objects under the server-configured S3 download origin/bucket."""
if os.getenv("OSS_TYPE", "ifly_gateway_storage").strip().lower() != "s3":
return False
origin_value = os.getenv("OSS_DOWNLOAD_HOST", "").strip()
buckets = {
value
for setting in ("OSS_BUCKET_NAME", "OSS_BUCKET_CONSOLE")
if (value := os.getenv(setting, "").strip())
and value == value.lower()
and _S3_BUCKET_PATTERN.fullmatch(value) is not None
}
if not origin_value or not buckets:
return FalseView on GitHub (pinned to 5e758547a8)