{"record":{"id":"f4f7a4d0aab8901f","repo":"iflytek/astron-agent","slug":"invalid-domain-black-list-entry","errorCode":null,"errorMessage":"Invalid DOMAIN_BLACK_LIST entry","messagePattern":"Invalid DOMAIN_BLACK_LIST entry","errorType":"validation","errorClass":"OutboundPolicyError","httpStatus":null,"severity":"error","filePath":"core/plugin/link/infra/tool_exector/ssrf_guard.py","lineNumber":239,"sourceCode":"        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\n\ndef _parse_domains(raw_value: str) -> Tuple[str, ...]:\n    domains = []\n    for entry in raw_value.split(\",\"):\n        value = entry.strip().lower().rstrip(\".\")\n        if value.startswith(\"*.\"):\n            value = value[2:]\n        if value.startswith(\".\"):\n            value = value[1:]\n        if not value:\n            continue\n        if \"://\" in value or \"/\" in value:\n            raise OutboundPolicyError(\"Invalid DOMAIN_BLACK_LIST entry\")\n        try:\n            # Use the same IDNA normalization as aiohttp/yarl applies to request hosts.\n            # Python's built-in ``idna`` codec follows IDNA2003 and would otherwise\n            # collapse distinct hosts such as faß.de and fass.de.\n            domains.append(_normalize_hostname(value))\n        except OutboundPolicyError as exc:\n            raise OutboundPolicyError(\"Invalid DOMAIN_BLACK_LIST entry\") from exc\n    return tuple(domains)\n\n\ndef _parse_private_endpoints(raw_value: str) -> Tuple[Endpoint, ...]:\n    endpoints = []\n    for entry in raw_value.split(\",\"):\n        value = entry.strip()\n        if not value:\n            continue\n        try:\n            parsed = _parse_http_url(value)","sourceCodeStart":221,"sourceCodeEnd":257,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/core/plugin/link/infra/tool_exector/ssrf_guard.py#L221-L257","documentation":"When parsing DOMAIN_BLACK_LIST from the environment, each entry must be a bare hostname after wildcard/leading-dot stripping. An entry containing '://' or '/' is rejected because it looks like a URL or path rather than a hostname — the blacklist matches hosts, not full URLs.","triggerScenarios":"from_environment → _parse_domains encounters an entry like https://evil.com, evil.com/api, or http://10.0.0.1 after stripping '*.': '://' or '/' remains, raising immediately.","commonSituations":"Pasting a full URL into a domain blacklist env var; including a path pattern like evil.com/admin; mixing URL and host formats in one comma-separated list.","solutions":["Use bare hostnames only: evil.com instead of https://evil.com.","Strip scheme and path: urllib.parse.urlsplit(entry).hostname to extract just the host.","If path-based blocking is needed, it is not supported by this setting — handle at a different layer.","Fix the env var so every comma-separated token is a hostname (wildcards like *.evil.com are allowed)."],"exampleFix":"// before\nDOMAIN_BLACK_LIST=https://evil.com,evil.com/admin\n// after\nDOMAIN_BLACK_LIST=evil.com","handlingStrategy":"validation","validationCode":"def valid_domain_entries(raw: str) -> bool:\n    for entry in raw.split(\",\"):\n        v = entry.strip().lower().rstrip(\".\").lstrip(\"*.\").lstrip(\".\")\n        if v and (\"://\" in v or \"/\" in v):\n            return False\n    return True","typeGuard":null,"tryCatchPattern":"try:\n    policy = OutboundPolicy.from_environment()\nexcept OutboundPolicyError as e:\n    raise ConfigError(f\"bad DOMAIN_BLACK_LIST: {e}\") from e","preventionTips":["Configure bare hostnames only (evil.com, *.evil.com), never full URLs or paths","Extract hosts with urlsplit(entry).hostname when migrating from URL lists","Document that path-based blocking is unsupported in this setting"],"tags":["security","ssrf","env-config","domain"],"backgroundTag":"invalid-env-var-value","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"}