iflytek/astron-agent · error · OutboundPolicyError

Only HTTP and HTTPS tool URLs are allowed

Error message

Only HTTP and HTTPS tool URLs are allowed

What it means

The SSRF guard only permits http and https schemes for outbound tool requests. Any other scheme (file:, ftp:, gopher:, dict:, ws:) is rejected because non-HTTP schemes can be used to reach local files or internal services in SSRF attacks.

Solutions

  1. Use http:// or https:// explicitly in the configured tool URL.
  2. If the URL has no scheme, prepend https:// before passing it to the plugin.
  3. Fix the tool/plugin configuration value; only HTTP(S) endpoints are supported by policy.
  4. If another protocol is genuinely needed, it is blocked by design — route through an allowed HTTP gateway instead.

Example fix

// before
url = "ftp://files.example.com/data"
// after
url = "https://files.example.com/data"
Defensive patterns

Strategy: validation

Validate before calling

from urllib.parse import urlsplit
ALLOWED = {"http", "https"}
def has_allowed_scheme(url: str) -> bool:
    return urlsplit(url).scheme.lower() in ALLOWED

Try / catch

try:
    client.get(url)
except OutboundPolicyError:
    url = "https://" + url  # only if scheme was missing
    client.get(url)

Prevention

When it happens

Trigger: _parse_http_url receives a URL whose lowercased parsed scheme is not in _ALLOWED_SCHEMES — e.g. file:///etc/passwd, ftp://host/x, or a scheme-less string like example.com/path where urlsplit yields an empty scheme.

Common situations: Tool endpoint configured as file:// or ftp://; URL built by concatenation losing the scheme; scheme-less address given where a full http(s) URL is required.

Understand the failure class

Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.

Related errors


AI-assisted analysis of iflytek/astron-agent@5e758547a8 (2026-09-12). Data as JSON: /api/errors/69c3a131e1fdf04a. Report an issue: GitHub.

Appendix: source

Thrown at core/plugin/link/infra/tool_exector/ssrf_guard.py:202

        raise OutboundPolicyError("Outbound URL is malformed")
    _validate_url_characters(url)
    try:
        parsed = urlsplit(url)
        port = parsed.port
    except (TypeError, ValueError) as exc:
        raise OutboundPolicyError("Outbound URL is malformed") from exc
    _validate_parsed_http_url(parsed, port)
    return parsed


def _validate_url_characters(url: str) -> None:
    if any(ord(character) < 0x20 or ord(character) == 0x7F for character in url):
        raise OutboundPolicyError("Outbound URL contains control characters")


def _validate_parsed_http_url(parsed: SplitResult, port: Union[int, None]) -> None:
    if parsed.scheme.lower() not in _ALLOWED_SCHEMES:
        raise OutboundPolicyError("Only HTTP and HTTPS tool URLs are allowed")
    if not parsed.hostname:
        raise OutboundPolicyError("Outbound URL must include a hostname")
    if parsed.username is not None or parsed.password is not None:
        raise OutboundPolicyError("Outbound URL must not include user information")
    if "\\" in parsed.netloc:
        raise OutboundPolicyError("Outbound URL authority is invalid")
    if parsed.fragment:
        raise OutboundPolicyError("Outbound URL must not include a fragment")
    if port is not None and not 1 <= port <= 65535:
        raise OutboundPolicyError("Outbound URL port is invalid")


def _parse_networks(raw_value: str, setting_name: str) -> Tuple[IpNetwork, ...]:
    networks = []
    for entry in raw_value.split(","):
        value = entry.strip()
        if not value:
            continue

View on GitHub (pinned to 5e758547a8)