Hmbown/CodeWhale · error

outbound origin must not target a loopback, private, or…

Error message

outbound origin must not target a loopback, private, or reserved address

What it means

If the host parses as an IP address, the validator blocks loopback, private, link-local, unspecified, broadcast, multicast, documentation ranges, carrier-grade NAT (100.64.0.0/10), and their IPv6/IPv4-mapped equivalents. This prevents credential-bearing requests from being aimed at internal network addresses (SSRF).

Solutions

  1. Give the service a public https hostname and configure that instead of the raw internal IP.
  2. Route through a reverse proxy on a public address.
  3. For local development, use a debug build with localhost/127.0.0.1, which has its own explicit path.

Example fix

// before
export DAYTONA_API_URL=http://192.168.1.10:8080
// after
export DAYTONA_API_URL=https://sandbox.example.com
Defensive patterns

Strategy: validation

Validate before calling

if let Ok(ip) = host.trim_end_matches('.').parse::<std::net::IpAddr>() {
    let private = match ip { IpAddr::V4(v4) => v4.is_private() || v4.is_loopback() || v4.is_link_local(), IpAddr::V6(v6) => v6.is_loopback() || (v6.segments()[0] & 0xfe00) == 0xfc00 || (v6.segments()[0] & 0xffc0) == 0xfe80 };
    if private { return Err("origin must be a public IP/host"); }
}

Try / catch

if let Err(e) = validate_outbound_origin(raw) {
    if e.to_string().contains("loopback, private, or reserved") {
        eprintln!("origin targets a non-public address (SSRF guard): {raw}");
    }
}

Prevention

When it happens

Trigger: Configuring an origin whose host is a raw IP like 192.168.1.10, 10.0.0.5, 169.254.169.254 (metadata service), ::1, or fd00::1.

Common situations: Self-hosted sandbox service on a LAN addressed by IP; attempting to hit a cloud metadata endpoint; IPv6 private addresses in config.

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 Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/8fd1d66666f907ff. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/cloud_dispatch.rs:1326

                    v4.is_loopback()
                        || v4.is_private()
                        || v4.is_link_local()
                        || v4.is_unspecified()
                        || v4.is_broadcast()
                        || v4.is_multicast()
                        || v4.is_documentation()
                        || (octets[0] == 100 && (octets[1] & 0b1100_0000) == 0b0100_0000)
                } else {
                    v6.is_loopback()
                        || v6.is_unspecified()
                        || v6.is_multicast()
                        || (v6.segments()[0] & 0xfe00) == 0xfc00
                        || (v6.segments()[0] & 0xffc0) == 0xfe80
                }
            }
        };
        if blocked {
            bail!("outbound origin must not target a loopback, private, or reserved address");
        }
    }
    if url.scheme() != "https" {
        bail!("outbound origin must use https");
    }
    Ok(url)
}

/// Meter one closed interval on a dispatched cloud job.
///
/// The job's sandbox id must match the provider observation. Wall-clock after
/// create is not enough: the observation has to be provider-accepted active
/// time bound to the immutable admission.
pub fn meter_cloud_job(
    job: &CloudJob,
    admission: &ComputerAdmission,
    observation: ProviderObservation,
) -> Result<ComputerMeterReceipt, ComputerMeterError> {

View on GitHub (pinned to 73e0f67d83)