tinyhumansai/openhuman · error · anyhow::Error
debug Composio base URL must be HTTPS or loopback HTTP
Error message
debug Composio base URL must be HTTPS or loopback HTTP
What it means
Constructor validation in the debug-only ComposioTool::new_with_base_urls_for_loopback: each of base_v2/base_v3 must either start with https:// or be an http URL whose parsed host is loopback (localhost, 127.0.0.0/8, ::1) with no embedded userinfo. Host checking is done by parsing (is_loopback_http_base), not prefix matching, specifically so userinfo smuggling like http://127.0.0.1:8080@evil.com cannot route the x-api-key header to evil.com.
Source
Thrown at src/openhuman/integrations/composio/tools/direct.rs:110
pub(crate) fn auth_key_fingerprint(&self) -> u64 {
crate::openhuman::integrations::composio::direct_auth::fingerprint_api_key(&self.api_key)
}
/// Debug-test seam for raw integration coverage: construct a direct
/// Composio tool against explicit v2/v3 base URLs. Non-HTTPS URLs are
/// accepted only for loopback hosts and only in debug builds.
#[cfg(debug_assertions)]
pub fn new_with_base_urls_for_loopback(
api_key: &str,
default_entity_id: Option<&str>,
security: Arc<SecurityPolicy>,
base_v2: String,
base_v3: String,
) -> anyhow::Result<Self> {
for base in [&base_v2, &base_v3] {
if !base.starts_with("https://") && !is_loopback_http_base(base) {
anyhow::bail!("debug Composio base URL must be HTTPS or loopback HTTP");
}
}
Ok(Self::new_internal(
api_key,
default_entity_id,
security,
base_v2,
base_v3,
true,
))
}
/// Test-only seam: construct with an explicit Composio v3 base URL so
/// unit tests can point the direct `/tools` request — including the
/// `tags` filter — at a local mock instead of `backend.composio.dev`.
///
/// `#[cfg(test)]`-gated on purpose: `list_tool_schemas_v3` attaches the
/// `x-api-key` header to whatever `base_v3` holds, so the only way toView on GitHub (pinned to 7491200858)
Solutions
- Point the base at a loopback host: http://127.0.0.1:<port>, http://localhost:<port>, or http://[::1]:<port>, with no userinfo
- Or serve the mock over https and keep any host you like
- Remember the constructor only exists under cfg(debug_assertions) — release builds must use ComposioTool::new with the pinned HTTPS endpoints
Example fix
// before
let tool = ComposioTool::new_with_base_urls_for_loopback(key, None, sec,
"http://10.0.0.5:8080/api/v2".into(), "http://10.0.0.5:8080/api/v3".into())?;
// after — loopback mock in a debug build
let tool = ComposioTool::new_with_base_urls_for_loopback(key, None, sec,
"http://127.0.0.1:8080/api/v2".into(), "http://127.0.0.1:8080/api/v3".into())?; Defensive patterns
Strategy: validation
Validate before calling
#[cfg(debug_assertions)]
{
// Both bases must be https OR loopback http (127.0.0.1 / localhost / [::1], no userinfo)
for base in [&base_v2, &base_v3] {
assert!(base.starts_with("https://") || is_loopback_http_base(base),
"base {base} is neither https nor loopback");
}
} Type guard
fn is_safe_debug_base(raw: &str) -> bool {
if raw.starts_with("https://") { return true; }
let Ok(u) = url::Url::parse(&format!("{}/", raw.trim_end_matches('/'))) else { return false };
u.scheme() == "http"
&& u.username().is_empty()
&& u.password().is_none()
&& matches!(u.host(),
Some(url::Host::Domain(h)) if h.eq_ignore_ascii_case("localhost")
|| matches!(u.host(), Some(url::Host::Ipv4(ip)) if ip.is_loopback())
|| matches!(u.host(), Some(url::Host::Ipv6(ip)) if ip.is_loopback()))
} Try / catch
match ComposioTool::new_with_base_urls_for_loopback(key, None, sec, v2, v3) {
Ok(tool) => tool,
Err(e) if format!("{e:#}").contains("HTTPS or loopback") => {
// test harness misconfig — bind the mock to 127.0.0.1 or serve TLS
panic!("test base URL rejected: {e:#}");
}
Err(e) => return Err(e),
} Prevention
- Bind local Composio mocks to 127.0.0.1 / [::1] / localhost — never a LAN or docker-bridge IP — when using the debug constructor
- Never put credentials in mock base URLs; the loopback check rejects userinfo by design
- Gate every use of new_with_base_urls_for_loopback behind cfg(debug_assertions) so it cannot leak into release builds
When it happens
Trigger: A debug build constructs the tool with a base such as http://staging.composio.dev/... or http://192.168.1.10:8080 (LAN host, not loopback), or a loopback-looking URL containing user:pass@ — is_loopback_http_base returns false and the constructor bails.
Common situations: Pointing tests at a mock on a LAN IP or docker host (host.docker.internal, 172.17.x.x) instead of a loopback address; reusing a staging http URL in a dev build; copy-pasting a proxy URL with credentials.
Related errors
- Refusing to transmit sensitive data over non-HTTPS URL: URL
- OpenRouter OAuth callback state did not match the request.
- OpenRouter OAuth listener returned an invalid redirect URL.
- OpenRouter OAuth requires the desktop app. Use an API key in
- Failed to fetch repositories
AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17).
Data as JSON: /api/errors/f9b59898501c6ab0.
Report an issue: GitHub.