{"record":{"id":"caa69c7e6e162387","repo":"iflytek/astron-agent","slug":"outbound-url-port-is-invalid","errorCode":null,"errorMessage":"Outbound URL port is invalid","messagePattern":"Outbound URL port is invalid","errorType":"exception","errorClass":"OutboundPolicyError","httpStatus":null,"severity":"error","filePath":"core/plugin/link/infra/tool_exector/ssrf_guard.py","lineNumber":212,"sourceCode":"\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\n\ndef _parse_domains(raw_value: str) -> Tuple[str, ...]:\n    domains = []\n    for entry in raw_value.split(\",\"):","sourceCodeStart":194,"sourceCodeEnd":230,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/core/plugin/link/infra/tool_exector/ssrf_guard.py#L194-L230","documentation":"An explicit port in the URL must be in the valid TCP range 1–65535. (Non-numeric ports make urlsplit .port raise ValueError, handled earlier as 'malformed'.) This error fires when a numeric port outside the range, such as 0 or 70000, reaches validation.","triggerScenarios":"_parse_http_url gets a URL like http://host:0/, http://host:65536/, or http://host:-1/ — the parsed port is not None and fails the 1 <= port <= 65535 check.","commonSituations":"Port from a misconfigured env var (extra digits, 0 placeholder); port copy-pasted from another protocol context; string concatenation producing an oversized port number.","solutions":["Correct the port to 1–65535 (or omit it to use 80/443 defaults).","Validate the port before composing the URL: 1 <= int(port) <= 65535.","Check the environment variable or config supplying the port for typos.","Clamp or reject out-of-range values at config load time if the port is dynamic."],"exampleFix":"// before\nurl = f\"https://api.example.com:{port}/v1\"  # port = 70000\n// after\nif not (1 <= port <= 65535):\n    raise ValueError(f\"invalid port {port}\")\nurl = f\"https://api.example.com:{port}/v1\"","handlingStrategy":"validation","validationCode":"def port_in_range(url: str) -> bool:\n    try:\n        port = urlsplit(url).port\n    except ValueError:\n        return False\n    return port is None or 1 <= port <= 65535","typeGuard":null,"tryCatchPattern":"try:\n    client.get(url)\nexcept OutboundPolicyError as e:\n    raise ConfigError(f\"invalid port in endpoint: {e}\") from e","preventionTips":["Validate ports as ints in 1-65535 when loading config","Omit the port for default 80/443 instead of using placeholders like 0","Watch for string concatenation producing malformed port segments"],"tags":["security","ssrf","url-validation","port"],"backgroundTag":"value-out-of-range","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"}