{"record":{"id":"157c6720d758dc1b","repo":"iflytek/astron-agent","slug":"outbound-url-authority-is-invalid","errorCode":null,"errorMessage":"Outbound URL authority is invalid","messagePattern":"Outbound URL authority is invalid","errorType":"exception","errorClass":"OutboundPolicyError","httpStatus":null,"severity":"error","filePath":"core/plugin/link/infra/tool_exector/ssrf_guard.py","lineNumber":208,"sourceCode":"        raise OutboundPolicyError(\"Outbound URL is malformed\") from exc\n    _validate_parsed_http_url(parsed, port)\n    return parsed\n\n\ndef _validate_url_characters(url: str) -> None:\n    if any(ord(character) < 0x20 or ord(character) == 0x7F for character in url):\n        raise OutboundPolicyError(\"Outbound URL contains control characters\")\n\n\ndef _validate_parsed_http_url(parsed: SplitResult, port: Union[int, None]) -> None:\n    if parsed.scheme.lower() not in _ALLOWED_SCHEMES:\n        raise OutboundPolicyError(\"Only HTTP and HTTPS tool URLs are allowed\")\n    if not parsed.hostname:\n        raise OutboundPolicyError(\"Outbound URL must include a hostname\")\n    if parsed.username is not None or parsed.password is not None:\n        raise OutboundPolicyError(\"Outbound URL must not include user information\")\n    if \"\\\\\" in parsed.netloc:\n        raise OutboundPolicyError(\"Outbound URL authority is invalid\")\n    if parsed.fragment:\n        raise OutboundPolicyError(\"Outbound URL must not include a fragment\")\n    if port is not None and not 1 <= port <= 65535:\n        raise OutboundPolicyError(\"Outbound URL port is invalid\")\n\n\ndef _parse_networks(raw_value: str, setting_name: str) -> Tuple[IpNetwork, ...]:\n    networks = []\n    for entry in raw_value.split(\",\"):\n        value = entry.strip()\n        if not value:\n            continue\n        try:\n            networks.append(ipaddress.ip_network(value, strict=False))\n        except ValueError as exc:\n            raise OutboundPolicyError(f\"Invalid {setting_name} entry\") from exc\n    return tuple(networks)\n","sourceCodeStart":190,"sourceCodeEnd":226,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/core/plugin/link/infra/tool_exector/ssrf_guard.py#L190-L226","documentation":"A backslash in the URL authority (netloc) is rejected. Some parsers treat backslash as a path separator and others do not; excluding it from the netloc prevents parser-differential attacks where validation sees one host while the HTTP client connects to another.","triggerScenarios":"_parse_http_url gets a URL like https://example.com\\\\@evil.com or https:\\\\\\\\host (Windows-style backslashes in the authority), so '\\\\' is found in parsed.netloc.","commonSituations":"Windows paths pasted into a URL field (C:\\\\... used as host); attackers substituting \\\\ for // to bypass naive checks; template errors doubling backslashes.","solutions":["Replace backslashes with forward slashes: url.replace('\\\\', '/').","Verify the string is a proper http(s):// URL, not a Windows file path mistakenly passed as an endpoint.","Sanitize user input by rejecting or normalizing '\\\\' before building the URL.","Log repr(url) to see exact backslash placement, then fix the source string."],"exampleFix":"// before\nurl = r\"https:\\\\example.com\\api\"  # windows-style\n// after\nurl = \"https://example.com/api\"","handlingStrategy":"validation","validationCode":"def netloc_is_clean(url: str) -> bool:\n    return \"\\\\\" not in urlsplit(url).netloc","typeGuard":null,"tryCatchPattern":"try:\n    client.get(url)\nexcept OutboundPolicyError:\n    url = url.replace(\"\\\\\", \"/\")\n    client.get(url)","preventionTips":["Reject raw Windows paths submitted in URL fields","Normalize backslashes to forward slashes early in input handling","Be aware \\ is a common SSRF parser-confusion character; never allow it in authorities"],"tags":["security","ssrf","url-validation"],"backgroundTag":"invalid-url-format","analyzedSha":"5e758547a83371a5a4b29dadf4ac03e8dd527635","analyzedAt":"2026-09-12T08:03:51.356Z","contentChangedAt":"2026-09-12T08:03:51.356Z","schemaVersion":2},"datasetVersion":"2026-09-19T12:17:13.211Z"}