Hmbown/CodeWhale · error

remote url must not embed userinfo

Error message

remote url must not embed userinfo

What it means

validate_git_remote_url refuses URLs that embed userinfo (remote_has_userinfo), i.e. credentials in the form scheme://user:pass@host. Embedding secrets in remote URLs leaks them into git config, logs, and process listings, so this form is banned outright.

Solutions

  1. Remove the userinfo and use the plain https://host/org/repo.git form; supply credentials via the git credential helper or environment instead.
  2. Regenerate/revoke any token that was embedded in the URL — it should be considered leaked.
  3. Use SSH remotes (git@github.com:org/repo.git) with key auth rather than token-in-URL.
  4. Redact before displaying: redact_remote_url exists for the display path; never print the raw URL.

Example fix

// before
let url = "https://ghp_SECRET@github.com/org/repo.git";
validate_git_remote_url(url)?;
// after
let url = "https://github.com/org/repo.git"; // auth via credential helper
validate_git_remote_url(url)?;
Defensive patterns

Strategy: validation

Validate before calling

fn embeds_userinfo(url: &str) -> bool {
    // crude check: credentials before host in an authority component
    url.contains('@') && !url.starts_with("git@")
}

Try / catch

match validate_git_remote_url(raw) {
    Err(e) if e.to_string().contains("userinfo") => {
        eprintln!("remove embedded credentials; use a credential helper instead");
        eprintln!("display form: {}", redact_remote_url(raw));
    }
    other => { /* ... */ }
}

Prevention

When it happens

Trigger: Calling validate_git_remote_url / safe_git_remote_url / clone_repository with a URL containing an `user:password@` (or `token@`) component before the host — commonly an HTTPS URL with a PAT baked in, or an SSH URL with an explicit user plus secret-looking segment detected by the helper.

Common situations: Copy-pasting an authenticated clone URL from a CI secret or a token-scoped URL provided by a forge; storing a PAT inside the remote to 'make it work'; a template that interpolates credentials into the URL.

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


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

Appendix: source

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

pub fn safe_git_remote_url(raw: &str) -> bool {
    validate_git_remote_url(raw).is_ok()
}

/// Classify and validate `job.remote_url` before any `git clone` or
/// sandbox clone. Returns the trimmed URL on success.
pub fn validate_git_remote_url(raw: &str) -> Result<String> {
    let url = raw.trim();
    if url.is_empty() || url.len() > MAX_REMOTE_BYTES {
        bail!("remote url is empty or oversized");
    }
    if url.starts_with('-') {
        bail!("remote url must not start with '-'");
    }
    if url.chars().any(char::is_control) {
        bail!("remote url contains control characters");
    }
    if remote_has_userinfo(url) {
        bail!("remote url must not embed userinfo");
    }
    if looks_like_network_git_url(url) && classify_url(url).is_none() {
        bail!("remote url is not a supported forge");
    }
    Ok(url.to_string())
}

/// Display form of a remote: userinfo is never printed.
pub fn redact_remote_url(raw: &str) -> String {
    redact_url_userinfo(raw)
}

fn remote_has_userinfo(url: &str) -> bool {
    if let Ok(parsed) = reqwest::Url::parse(url) {
        return !parsed.username().is_empty() || parsed.password().is_some();
    }
    // scp-style `user:token@host:path` (plain `git@host:path` is identity, not a secret).
    if let Some((userinfo, _host)) = url.split_once('@') {

View on GitHub (pinned to 73e0f67d83)