Hmbown/CodeWhale · error

outbound origin must not embed credentials

Error message

outbound origin must not embed credentials

What it means

The origin validator rejects URLs carrying userinfo (user:pass@host) so credentials never ride along inside the origin itself. Credentials must be supplied out of band (headers/env), not embedded in the URL.

Solutions

  1. Remove the user:password@ portion from the URL and pass the credential via the appropriate header or env var.
  2. Check env var contents: strip any '@'-style credential suffix before setting DAYTONA_API_URL.
  3. Move secrets out of config files into the credential store / environment.

Example fix

// before
export DAYTONA_API_URL=https://user:token@api.example.com
// after
export DAYTONA_API_URL=https://api.example.com
export DAYTONA_API_KEY=token
Defensive patterns

Strategy: validation

Validate before calling

fn has_userinfo(raw: &str) -> bool {
    reqwest::Url::parse(raw.trim()).map(|u| !u.username().is_empty() || u.password().is_some()).unwrap_or(false)
}

Try / catch

if has_userinfo(raw) {
    eprintln!("strip user:pass@ from the origin; pass credentials via headers/env");
}

Prevention

When it happens

Trigger: Configuring an origin like https://user:token@api.example.com or https://admin@host/ as the remote endpoint or toolbox URL.

Common situations: Copying a URL that worked in a browser/curl with embedded basic-auth; legacy tooling that expected credentials in the URL; secrets committed into config files.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/61c7156428685877. Report an issue: GitHub.

Appendix: source

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

/// - explicit loopback hosts (`localhost`, `127.0.0.1`, `::1`) are allowed
///   only in debug builds, as the escape hatch for local smoke tests against
///   a self-hosted sandbox service; release builds reject them outright.
/// - the host must not be a private / link-local / reserved / multicast
///   address or a `.local` / `.internal` name, and no userinfo may ride
///   along.
///
/// DNS-resolved rebinding is out of scope and documented as such.
pub fn validate_outbound_origin(raw: &str) -> Result<reqwest::Url> {
    let trimmed = raw.trim();
    if trimmed.is_empty() || trimmed.len() > MAX_REMOTE_BYTES {
        bail!("outbound origin is empty or oversized");
    }
    let url = reqwest::Url::parse(trimmed).context("outbound origin is not a valid URL")?;
    if !matches!(url.scheme(), "http" | "https") {
        bail!("outbound origin must be http or https");
    }
    if !url.username().is_empty() || url.password().is_some() {
        bail!("outbound origin must not embed credentials");
    }
    let host = url
        .host_str()
        .context("outbound origin has no host")?
        .trim_end_matches('.')
        .to_ascii_lowercase();
    // `Url::host_str` keeps IPv6 brackets; strip them for the checks below.
    let host = host
        .strip_prefix('[')
        .and_then(|inner| inner.strip_suffix(']'))
        .map(str::to_string)
        .unwrap_or(host);
    let loopback_name = host == "localhost" || host == "127.0.0.1" || host == "::1";
    if loopback_name {
        if cfg!(debug_assertions) {
            return Ok(url);
        }
        bail!("loopback origins are not allowed in release builds");

View on GitHub (pinned to 73e0f67d83)