tinyhumansai/openhuman · error · anyhow::Error
Refusing to transmit sensitive data over non-HTTPS URL: URL
Error message
Refusing to transmit sensitive data over non-HTTPS URL: URL scheme must be https
What it means
Security guard in the direct Composio tool: ensure_https refuses any URL that does not literally start with 'https://' before a request carrying the x-api-key header is transmitted. It exists so a mis-configured base URL (env var, injected config, hand-built string) can never leak the API key over plaintext HTTP. The only sanctioned exception is loopback HTTP in debug builds (new_with_base_urls_for_loopback / allow_insecure_loopback).
Source
Thrown at src/openhuman/integrations/composio/tools/direct.rs:24
// This is opt-in. Users who prefer sovereign/local-only mode skip this entirely.
// The Composio API key is stored in the encrypted secret store.
use crate::openhuman::security::policy::ToolOperation;
use crate::openhuman::security::SecurityPolicy;
use crate::openhuman::tools::traits::{Tool, ToolCategory, ToolResult};
use anyhow::Context;
use async_trait::async_trait;
use reqwest::Client;
use serde::{Deserialize, Serialize};
use serde_json::json;
use std::sync::Arc;
const COMPOSIO_API_BASE_V2: &str = "https://backend.composio.dev/api/v2";
const COMPOSIO_API_BASE_V3: &str = "https://backend.composio.dev/api/v3";
fn ensure_https(url: &str) -> anyhow::Result<()> {
if !url.starts_with("https://") {
anyhow::bail!(
"Refusing to transmit sensitive data over non-HTTPS URL: URL scheme must be https"
);
}
Ok(())
}
fn is_loopback_http_url(url: &str) -> bool {
// Parse rather than prefix-match: a raw `starts_with("http://127.0.0.1:")`
// is fooled by userinfo smuggling like
// `http://127.0.0.1:8080@evil.com/api/v3/tools`, which reqwest routes to the
// *parsed* host (`evil.com`). Verify the actual scheme + host and reject any
// embedded credentials so the insecure-loopback path can never leak the
// `x-api-key` header to a non-loopback host.
let Ok(parsed) = url::Url::parse(url) else {
return false;
};
if parsed.scheme() != "http" {
return false;View on GitHub (pinned to 7491200858)
Solutions
- Use https:// base URLs for any non-loopback host — production pins https://backend.composio.dev/api/v2 and /api/v3
- For local mock servers, use the debug-only new_with_base_urls_for_loopback constructor with a 127.0.0.1, ::1, or localhost host
- Make sure the scheme string is lowercase 'https://' — the guard is a literal prefix match
- Audit any env/config override of Composio base URLs before shipping
Example fix
// before
let base = std::env::var("COMPOSIO_BASE")?; // "http://composio-mirror.internal"
// after — enforce https for non-loopback hosts before constructing the tool
if !base.starts_with("https://") {
anyhow::bail!("COMPOSIO_BASE must use https (loopback http allowed only via the debug constructor)");
} Defensive patterns
Strategy: validation
Validate before calling
if !base.starts_with("https://") {
anyhow::bail!("Composio base URL must be https:// (loopback http only via the debug constructor)");
} Type guard
fn is_https_url(raw: &str) -> bool {
url::Url::parse(raw).map(|u| u.scheme() == "https").unwrap_or(false)
} Try / catch
match tool.list_actions(None).await {
Ok(items) => { /* ... */ }
Err(e) if format!("{e:#}").contains("non-HTTPS") => {
// configuration defect — fail loudly, never downgrade to http
return Err(e);
}
Err(e) => { /* normal API error handling */ }
} Prevention
- Never accept Composio base URLs from config without asserting the https:// prefix
- Use ComposioTool::new (pinned HTTPS endpoints) everywhere except debug loopback testing
- Keep the scheme lowercase when building URL strings — the guard is a literal prefix match
- Treat this error as a security stop, not an inconvenience: do not catch-and-continue
When it happens
Trigger: ComposioTool is built with base URLs (or issues a request URL) using http:// — e.g. pointing v2/v3 bases at an http:// staging host in a release build — so ensure_request_url -> ensure_https bails before send(). Also fires for a non-lowercase 'HTTPS://' prefix because the check is a case-sensitive starts_with.
Common situations: Local mock server wired into a release build; base URL injected via config or env with a typo ('http://' instead of 'https://'); a proxy or config rewrite mangling the scheme; hand-concatenated URL strings with wrong casing.
Related errors
- debug Composio base URL must be HTTPS or loopback HTTP
- OpenRouter OAuth callback state did not match the request.
- Failed to fetch repositories
- Failed to list branches
- Failed to fetch repositories
AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17).
Data as JSON: /api/errors/77b97eee03fa5d0e.
Report an issue: GitHub.