Hmbown/CodeWhale · error
plain http is only allowed for loopback hosts; use https
Error message
plain http is only allowed for loopback hosts; use https
What it means
validate_bundle_url only permits plain http for loopback hosts (localhost, 127.0.0.1, ::1, etc. per is_loopback_bundle_host); any other host must use https. This prevents bundle contents — which become executable configuration — from traveling unencrypted across a network where they could be tampered with or observed.
Solutions
- Serve the bundle over https (enable TLS on the host or front it with a TLS-terminating proxy).
- For local testing, bind the server to 127.0.0.1/localhost so plain http is permitted.
- Use `ssh -L` or another tunnel so the bundle appears on loopback over http.
- Install a self-signed/internal-CA certificate and use https with the CA trusted.
Example fix
// before let url = "http://config.internal.example/bundle.toml"; // after let url = "https://config.internal.example/bundle.toml"; // local testing only: // let url = "http://127.0.0.1:8080/bundle.toml";
Defensive patterns
Strategy: validation
Validate before calling
let url = reqwest::Url::parse(input)?;
let host = url.host_str().context("missing host")?;
if url.scheme() == "http" && !(host == "localhost" || host == "127.0.0.1" || host == "::1") {
return Err(anyhow!("non-loopback http bundle URLs are not allowed"));
} Type guard
fn is_https_or_loopback(u: &reqwest::Url) -> bool {
match u.scheme() {
"https" => true,
"http" => matches!(u.host_str(), Some("localhost") | Some("127.0.0.1") | Some("::1")),
_ => false,
}
} Prevention
- Default to https for every hosted bundle.
- For local development bind servers to 127.0.0.1 so loopback http is allowed.
- Document internal mirrors with their https endpoints, not raw http addresses.
When it happens
Trigger: fetch_bundle called with an http:// URL pointing at a non-loopback host (e.g. http://config.internal.example/bundle.toml); the same check applies to redirect targets via validate_bundle_redirect.
Common situations: Pointing the bundle URL at an internal HTTP-only mirror; using an http LAN address for a quick test from another machine; legacy infrastructure without TLS on the config host.
Understand the failure class
Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.
Related errors
- bundle URLs may not include credentials
- bundle redirects may not change URL scheme
- returned an untrusted verification URI
- fleet alert URL from
- invalid Supabase endpoint
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/f87dd23e98e7d128.
Report an issue: GitHub.
Appendix: source
Thrown at crates/cli/src/config_bundles.rs:825
.map_err(|_| anyhow!("reading remote bundle failed"))?;
if buffer.len() as u64 > MAX_BUNDLE_BYTES {
bail!("remote bundle exceeds the {MAX_BUNDLE_BYTES} byte limit; refused");
}
Ok(buffer)
}
fn validate_bundle_url(url: &reqwest::Url) -> Result<()> {
if !matches!(url.scheme(), "http" | "https") {
bail!("unsupported bundle URL scheme; use https");
}
if !url.username().is_empty() || url.password().is_some() {
bail!("bundle URLs may not include credentials");
}
let host = url.host_str().context("bundle URL must include a host")?;
match url.scheme() {
"https" => Ok(()),
"http" if is_loopback_bundle_host(host) => Ok(()),
"http" => bail!("plain http is only allowed for loopback hosts; use https"),
_ => unreachable!("scheme was validated above"),
}
}
fn validate_bundle_redirect(initial_scheme: &str, next_url: &reqwest::Url) -> Result<()> {
validate_bundle_url(next_url)?;
if next_url.scheme() != initial_scheme {
bail!("bundle redirects may not change URL scheme");
}
Ok(())
}
fn is_loopback_bundle_host(host: &str) -> bool {
let normalized = host
.strip_prefix('[')
.and_then(|value| value.strip_suffix(']'))
.unwrap_or(host);
normalized.eq_ignore_ascii_case("localhost")View on GitHub (pinned to 73e0f67d83)