{"record":{"id":"74a0ee7048ef2662","repo":"oraios/serena","slug":"refusing-to-download-from-host-hostname-or-unk","errorCode":null,"errorMessage":"Refusing to download from host '{hostname or '<unknown>'}'; allowed hosts: {sorted(normalized_allowed_hosts)}","messagePattern":"Refusing to download from host '(.+?)'; allowed hosts: (.+?)","errorType":"exception","errorClass":"SolidLSPException","httpStatus":null,"severity":"error","filePath":"src/solidlsp/ls_utils.py","lineNumber":585,"sourceCode":"        if expected_sha256 is None:\n            return\n\n        actual_sha256 = FileUtils.calculate_sha256(file_path)\n        if actual_sha256.lower() != expected_sha256.lower():\n            raise SolidLSPException(f\"Checksum verification failed for '{file_path}': expected {expected_sha256}, got {actual_sha256}\")\n\n    @staticmethod\n    def _validate_download_host(url: str, allowed_hosts: Sequence[str] | None) -> None:\n        \"\"\"\n        Validates that a download URL resolves to one of the configured hosts.\n        \"\"\"\n        if not allowed_hosts:\n            return\n\n        hostname = urlparse(url).hostname\n        normalized_allowed_hosts = {host.lower() for host in allowed_hosts}\n        if hostname is None or hostname.lower() not in normalized_allowed_hosts:\n            raise SolidLSPException(\n                f\"Refusing to download from host '{hostname or '<unknown>'}'; allowed hosts: {sorted(normalized_allowed_hosts)}\"\n            )\n\n    @staticmethod\n    def _validate_extraction_path(member_name: str, target_path: str) -> str:\n        \"\"\"\n        Validates that an archive member stays within the extraction root and returns its destination path.\n        \"\"\"\n        normalized_parts = Path(member_name).parts\n        if any(part == \"..\" for part in normalized_parts):\n            raise SolidLSPException(f\"Unsafe archive member '{member_name}': path traversal is not allowed\")\n\n        absolute_target_path = os.path.abspath(target_path)\n        absolute_member_path = os.path.abspath(os.path.join(target_path, member_name))\n        if not (absolute_member_path.startswith(absolute_target_path + os.sep) or absolute_member_path == absolute_target_path):\n            raise SolidLSPException(f\"Unsafe archive member '{member_name}': path escapes extraction directory\")\n\n        return absolute_member_path","sourceCodeStart":567,"sourceCodeEnd":603,"githubUrl":"https://github.com/oraios/serena/blob/7fcbca7e62555ec2287ddb2f083caee805848ea6/src/solidlsp/ls_utils.py#L567-L603","documentation":"Raised by _validate_download_host when the hostname of the download URL is not in the configured allowlist (allowed_hosts). This SSRF/supply-chain guard refuses downloads from unapproved hosts, using case-insensitive exact hostname match.","triggerScenarios":"download_file_verified called with allowed_hosts configured while the URL points to a different host, a subdomain not exactly listed, or a URL with no hostname (e.g. a malformed/relative URL).","commonSituations":"Upstream download URL moves to a new CDN domain while the config allowlist still lists the old host; typo in configured host; mirror URLs not added to the allowlist.","solutions":["Add the new hostname (lowercase, exact) to the allowed_hosts configuration","Fix the download URL to point at an allowlisted host","If the URL is malformed, correct it so urlparse can extract a hostname"],"exampleFix":"// before\nallowed_hosts = [\"github.com\"]\n// after\nallowed_hosts = [\"github.com\", \"objects.githubusercontent.com\"]","handlingStrategy":"validation","validationCode":"from urllib.parse import urlparse\nhostname = urlparse(url).hostname\nallowed = {h.lower() for h in allowed_hosts}\nassert hostname and hostname.lower() in allowed, f\"host {hostname!r} not in allowlist\"","typeGuard":"def host_is_allowed(url: str, allowed_hosts: list[str]) -> bool:\n    h = urlparse(url).hostname\n    return bool(h and h.lower() in {x.lower() for x in allowed_hosts})","tryCatchPattern":"try:\n    download_file_verified(url, path, allowed_hosts=allowed_hosts)\nexcept SolidLSPException as e:\n    if \"Refusing to download from host\" in str(e):\n        raise ConfigError(f\"URL host not allowlisted; update allowed_hosts for {url}\") from e\n    raise","preventionTips":["Keep allowed_hosts in sync with upstream CDN domains (including subdomains)","Use exact hostnames — the check is exact-match, not suffix match","Centralize download URLs in config so allowlist and URLs change together"],"tags":["security","download","ssrf","configuration"],"backgroundTag":"download-host-not-allowed","analyzedSha":"7fcbca7e62555ec2287ddb2f083caee805848ea6","analyzedAt":"2026-08-29T00:04:09.619Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}