{"record":{"id":"7f53c9595ea7e540","repo":"invoke-ai/InvokeAI","slug":"refusing-to-download-from-host-it-resolves-to","errorCode":null,"errorMessage":"Refusing to download from '{host}': it resolves to a non-public address. Set `allow_private_download_urls` in invokeai.yaml to permit downloads from loopback and private-network addresses.","messagePattern":"Refusing to download from '(.+?)': it resolves to a non-public address\\. Set `allow_private_download_urls` in invokeai\\.yaml to permit downloads from loopback and private-network addresses\\.","errorType":"exception","errorClass":"UnsafeDownloadURLException","httpStatus":400,"severity":"error","filePath":"invokeai/app/util/ssrf.py","lineNumber":180,"sourceCode":"            values.append(int(digits, base))\n        except ValueError:\n            return None\n\n    widths = {1: (32,), 2: (8, 24), 3: (8, 8, 16), 4: (8, 8, 8, 8)}[len(values)]\n    if any(value >= 1 << width for value, width in zip(values, widths, strict=True)):\n        return None\n\n    address = 0\n    for value, width in zip(values, widths, strict=True):\n        address = (address << width) | value\n    return ipaddress.IPv4Address(address)\n\n\ndef check_address(ip: IpAddress, host: str) -> None:\n    \"\"\"Raise if `ip` is not an address we are willing to connect to.\"\"\"\n    if _is_blocked(ip):\n        logger.warning(\"Blocked download host %s resolving to non-public address %s\", host, ip)\n        raise UnsafeDownloadURLException(\n            f\"Refusing to download from '{host}': it resolves to a non-public address. \"\n            \"Set `allow_private_download_urls` in invokeai.yaml to permit downloads from loopback \"\n            \"and private-network addresses.\"\n        )\n\n\ndef validate_download_url(url: str, allow_private_urls: bool = False) -> None:\n    \"\"\"Reject `url` up front if it obviously points somewhere only the server can reach.\n\n    Every address the host resolves to must be public — a hostname with both a public and a\n    loopback record is rejected, because we cannot control which one the HTTP client picks.\n\n    An unresolvable host is allowed through to the HTTP client, so that offline test\n    environments and mocked sessions keep working. That is only safe because the session\n    from `build_guarded_session()` re-checks the address it actually connects to.\n    \"\"\"\n    parts = urlsplit(str(url))\n","sourceCodeStart":162,"sourceCodeEnd":198,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/util/ssrf.py#L162-L198","documentation":"As an SSRF protection, InvokeAI resolves the download URL's host and refuses to connect if the resulting IP is loopback, private, link-local, or otherwise non-public. check_address() raises UnsafeDownloadURLException for such addresses; downloads can be explicitly permitted from private addresses via config.","triggerScenarios":"Downloading a model from a URL whose hostname resolves to 127.0.0.1, 10.x, 192.168.x, 169.254.x, or any mapped non-public address while allow_private_download_urls is false (default).","commonSituations":"Pointing InvokeAI at a local mirror/proxy like http://localhost:8080/model.safetensors or an internal network NAS; testing with a local model server; DNS rebinding to a private IP.","solutions":["If the private source is intended, set allow_private_download_urls: true in invokeai.yaml","Use a public URL for the model download","Download the model manually into the models directory and import it locally","Verify DNS resolution of the host; if it unexpectedly resolves private, fix DNS or use the correct public hostname"],"exampleFix":"// before (invokeai.yaml)\n# allow_private_download_urls not set\nurl = 'http://localhost:8080/model.safetensors'  # UnsafeDownloadURLException\n// after (invokeai.yaml)\nallow_private_download_urls: true","handlingStrategy":"validation","validationCode":"import socket, ipaddress\n\ndef is_public_host(url):\n    host = urlparse(url).hostname\n    for info in socket.getaddrinfo(host, None):\n        ip = ipaddress.ip_address(info[4][0])\n        if not ip.is_global:\n            return False\n    return True","typeGuard":null,"tryCatchPattern":"from invokeai.app.util.ssrf import UnsafeDownloadURLException\ntry:\n    download(url)\nexcept UnsafeDownloadURLException as e:\n    if 'non-public address' in str(e):\n        # either switch to a public URL or set allow_private_download_urls in invokeai.yaml\n        ...\n    else:\n        raise","preventionTips":["Only point downloads at public hosts by default","Set allow_private_download_urls: true consciously, only for trusted local mirrors","Prefer importing models from local disk over URL download for internal sources"],"tags":["security","ssrf","network","download"],"backgroundTag":"private-address-download-blocked","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}