iflytek/astron-agent · error · RemoteResourcePolicyError
Remote resource URL authority is invalid
Error message
Remote resource URL authority is invalid
What it means
RemoteResourcePolicyError raised by _validate_parsed_resource_url when the URL's netloc (authority) contains a backslash character. The SSRF-safe download module in safe_download.py rejects backslashes in the authority because different HTTP parsers handle '\\' inconsistently, which can let an attacker smuggle a hostname past validation (e.g. 'https://example.com\\@evil.com/'). The check runs after scheme, hostname, and user-info checks during URL parsing.
Solutions
- Remove or percent-encode backslashes from the URL before passing it to fetch_public_resource; build URLs with yarl.URL instead of string concatenation
- Validate/sanitize the caller-supplied URL on the input side (reject or encode '\\' before it reaches the download path)
- If the backslash is part of a path (not the authority), ensure it is properly placed after the host and percent-encoded as %5C
Example fix
// before
url = f"https://{windows_path}" # e.g. https://cdn\\host/file
await fetch_public_resource(url)
// after
from yarl import URL
safe = str(URL(f"https://cdn.example.com/{windows_path.replace('\\', '/')}").with_scheme('https'))
await fetch_public_resource(safe) Defensive patterns
Strategy: validation
Validate before calling
def is_safe_url_authority(url: str) -> bool:
from urllib.parse import urlsplit
try:
netloc = urlsplit(url).netloc
except ValueError:
return False
return bool(netloc) and "\\" not in netloc and url.isprintable() Type guard
def has_clean_authority(url: str) -> bool:
from urllib.parse import urlsplit
return "\\" not in urlsplit(url).netloc Try / catch
from plugin.aitools.common.clients.safe_download import RemoteResourcePolicyError
try:
data = await fetch_public_resource(url)
except RemoteResourcePolicyError as e:
log.warning("Rejected URL authority: %s", e) Prevention
- Build URLs with yarl.URL or urllib.parse instead of string concatenation
- Normalize Windows-style separators to '/' before placing values into URLs
- Sanitize LLM/user output before using it as a URL component
When it happens
Trigger: Passing a URL string to fetch_public_resource() (or any caller of _parse_resource_url) whose authority segment contains a literal backslash, e.g. 'https://bad\\host.example.com/file' or 'https://trusted.com\\@attacker.com/x'.
Common situations: User-supplied file URLs built by string concatenation where a Windows-style path fragment (C:\\...) leaks into the host portion; LLM/tool output containing escaped characters; template interpolation that injects backslashes into the URL before download.
Understand the failure class
Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.
Related errors
- HTTPClientError
- Remote resource URL must not include a fragment
- Skill resource URL is not allowed
- MODEL_URL_CHECK_FAILED
- MODEL_URL_CHECK_FAILED
AI-assisted analysis of iflytek/astron-agent@5e758547a8 (2026-09-12).
Data as JSON: /api/errors/d1b43bdf8f2132e3.
Report an issue: GitHub.
Appendix: source
Thrown at core/plugin/aitools/common/clients/safe_download.py:219
raise RemoteResourcePolicyError("Remote resource URL is malformed")
def _validate_parsed_resource_url(
parsed: SplitResult,
port: Optional[int],
) -> None:
if parsed.scheme.lower() not in _ALLOWED_SCHEMES:
raise RemoteResourcePolicyError(
"Only HTTP and HTTPS remote resources are allowed"
)
if not parsed.hostname:
raise RemoteResourcePolicyError("Remote resource URL must include a hostname")
if parsed.username is not None or parsed.password is not None:
raise RemoteResourcePolicyError(
"Remote resource URL must not include user information"
)
if "\\" in parsed.netloc:
raise RemoteResourcePolicyError("Remote resource URL authority is invalid")
if parsed.fragment:
raise RemoteResourcePolicyError(
"Remote resource URL must not include a fragment"
)
if port is not None and not 1 <= port <= 65535:
raise RemoteResourcePolicyError("Remote resource URL port is invalid")
def _normalize_hostname(hostname: str) -> str:
value = hostname.strip().lower().rstrip(".")
if _parse_ip(value) is not None:
return value
try:
normalized = URL.build(scheme="http", host=value).raw_host
except (TypeError, ValueError, UnicodeError) as exc:
raise RemoteResourcePolicyError("Remote resource hostname is invalid") from exc
if not normalized:
raise RemoteResourcePolicyError("Remote resource hostname is invalid")View on GitHub (pinned to 5e758547a8)