{"record":{"id":"006429e8ad875516","repo":"iflytek/astron-agent","slug":"remote-resource-url-must-not-include-user-information","errorCode":null,"errorMessage":"Remote resource URL must not include user information","messagePattern":"Remote resource URL must not include user information","errorType":"exception","errorClass":"RemoteResourcePolicyError","httpStatus":null,"severity":"error","filePath":"core/plugin/aitools/common/clients/safe_download.py","lineNumber":215,"sourceCode":"def _validate_url_characters(url: str) -> None:\n    if not isinstance(url, str) or any(\n        ord(character) < 0x20 or ord(character) == 0x7F for character in url\n    ):\n        raise RemoteResourcePolicyError(\"Remote resource URL is malformed\")\n\n\ndef _validate_parsed_resource_url(\n    parsed: SplitResult,\n    port: Optional[int],\n) -> None:\n    if parsed.scheme.lower() not in _ALLOWED_SCHEMES:\n        raise RemoteResourcePolicyError(\n            \"Only HTTP and HTTPS remote resources are allowed\"\n        )\n    if not parsed.hostname:\n        raise RemoteResourcePolicyError(\"Remote resource URL must include a hostname\")\n    if parsed.username is not None or parsed.password is not None:\n        raise RemoteResourcePolicyError(\n            \"Remote resource URL must not include user information\"\n        )\n    if \"\\\\\" in parsed.netloc:\n        raise RemoteResourcePolicyError(\"Remote resource URL authority is invalid\")\n    if parsed.fragment:\n        raise RemoteResourcePolicyError(\n            \"Remote resource URL must not include a fragment\"\n        )\n    if port is not None and not 1 <= port <= 65535:\n        raise RemoteResourcePolicyError(\"Remote resource URL port is invalid\")\n\n\ndef _normalize_hostname(hostname: str) -> str:\n    value = hostname.strip().lower().rstrip(\".\")\n    if _parse_ip(value) is not None:\n        return value\n    try:\n        normalized = URL.build(scheme=\"http\", host=value).raw_host","sourceCodeStart":197,"sourceCodeEnd":233,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/core/plugin/aitools/common/clients/safe_download.py#L197-L233","documentation":"_validate_parsed_resource_url rejects URLs containing userinfo (user:password@host). Embedding credentials in the URL is both a credential-leak risk (logged, proxied) and a parser-differential SSRF vector (browsers and servers may disagree on where the host begins), so the library refuses such URLs.","triggerScenarios":"URL like 'https://user:pass@files.example.com/file' or 'http://admin@host/x' — parsed.username or parsed.password is not None.","commonSituations":"Old-style basic-auth-in-URL object storage links; copy-pasted URLs from tools that embed tokens in the authority; attempts to smuggle a different host via 'https://evil.com\\@good.com/' style payloads.","solutions":["Remove credentials from the URL; authenticate via presigned query parameters or headers instead.","Use a public, unauthenticated URL for the resource.","If the upstream requires basic auth, fetch it yourself with an authenticated aiohttp/httpx call rather than this SSRF-guarded downloader."],"exampleFix":"// before\nawait fetch_public_resource(\"https://user:pass@files.example.com/report.pdf\")\n// after\nawait fetch_public_resource(\"https://files.example.com/signed/report.pdf?token=...\")","handlingStrategy":"validation","validationCode":"from urllib.parse import urlsplit\np = urlsplit(url)\nassert p.username is None and p.password is None, \"strip credentials from URL\"","typeGuard":"def is_credential_free(u):\n    try:\n        p = urlsplit(u)\n        return p.username is None and p.password is None\n    except (TypeError, ValueError):\n        return False","tryCatchPattern":"try:\n    data = await fetch_public_resource(url)\nexcept HTTPClientException as e:\n    if \"user information\" in str(e):\n        ...  # strip credentials, use presigned URL instead","preventionTips":["Never embed basic-auth in URLs; use signed URLs or headers","Reject '@' in netloc during input validation","Rotate any credentials previously embedded in URLs"],"tags":["url","security","credentials","ssrf","validation"],"backgroundTag":"invalid-url","analyzedSha":"5e758547a83371a5a4b29dadf4ac03e8dd527635","analyzedAt":"2026-09-12T08:03:51.356Z","contentChangedAt":"2026-09-12T08:03:51.356Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}