{"record":{"id":"cbf4163796520e08","repo":"jdx/mise","slug":"setup-repository-url-must-be-nonempty-and-must-not","errorCode":null,"errorMessage":"setup repository URL must be nonempty and must not start with '-'","messagePattern":"setup repository URL must be nonempty and must not start with '-'","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/sync/network.rs","lineNumber":23,"sourceCode":"\nuse eyre::{Result, bail};\n\nuse crate::system::history::shadow::HistoryRepo;\n\n/// The fetched setup branch head.\npub(crate) const UPSTREAM_REF: &str = \"refs/remotes/origin/setup\";\n\n/// A Git transport failed, as distinct from an invalid local configuration,\n/// encryption policy, or reconciliation plan.\n#[derive(Debug, thiserror::Error)]\n#[error(\"{0}\")]\npub(crate) struct NetworkError(pub String);\n\n/// Authentication belongs in a credential helper or SSH agent, never in\n/// persisted connection URLs or the errors recorded in history health.\npub(crate) fn validate_url(value: &str) -> Result<()> {\n    if value.trim().is_empty() || value.trim_start().starts_with('-') {\n        bail!(\"setup repository URL must be nonempty and must not start with '-'\");\n    }\n    let http_like = value\n        .trim_start()\n        .get(..5)\n        .is_some_and(|prefix| prefix.eq_ignore_ascii_case(\"http:\"))\n        || value\n            .trim_start()\n            .get(..6)\n            .is_some_and(|prefix| prefix.eq_ignore_ascii_case(\"https:\"));\n    if http_like && url::Url::parse(value).is_err() {\n        bail!(\"invalid HTTP setup repository URL; use a Git credential helper for authentication\");\n    }\n    if let Ok(url) = url::Url::parse(value) {\n        let http = matches!(url.scheme(), \"http\" | \"https\");\n        if url.password().is_some()\n            || (http\n                && (!url.username().is_empty()\n                    || url.query().is_some()","sourceCodeStart":5,"sourceCodeEnd":41,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/history/sync/network.rs#L5-L41","documentation":"`validate_url` in src/system/history/sync/network.rs guards every git network operation (fetch, push, ls-remote, symbolic-head) for the setup repository. A URL that is empty/whitespace, or that starts with `-` after leading whitespace, is rejected before it is ever passed to a git subprocess. This prevents an attacker-controlled or misconfigured value from being interpreted by git as a command-line option (e.g. `--upload-pack=...`) rather than a URL.","triggerScenarios":"Calling `Remote::new(repo, value)` followed by `fetch`, `fetch_tip`, `push`, `symbolic_head`, or `ls_remote` where `value` is `\"\"`, whitespace-only, or begins with a `-` (option injection attempt), e.g. a URL of `\"--upload-pack=bad\"`.","commonSituations":"An empty `history` remote URL in settings or an environment/config template that left the placeholder unfilled; a malicious or corrupted config value attempting option injection; a script concatenating flags into the URL field; a mis-parsed YAML/TOML value that trimmed the real URL.","solutions":["Set a real, nonempty setup repository URL (e.g. `git@github.com:user/dotfiles.git`, `https://github.com/user/dotfiles.git`, or a local path) in your settings/config.","Ensure the URL does not begin with `-`; if a leading `-` is genuine, it is not a valid git remote value here — fix or escape the source of the value.","Check for unfilled placeholders or template variables in your config that resolve to empty strings."],"exampleFix":"// before (config)\nhistory.remote = \"--upload-pack=evil\"\n\n// after\nhistory.remote = \"git@github.com:user/dotfiles.git\"","handlingStrategy":"validation","validationCode":"fn is_safe_remote_url(v: &str) -> bool {\n    !v.trim().is_empty() && !v.trim_start().starts_with('-')\n}","typeGuard":null,"tryCatchPattern":"// Rust\nmatch validate_url(url) {\n    Ok(()) => remote.fetch(\"main\")?,\n    Err(e) => eprintln!(\"fix the history.remote setting: {e}\"),\n}","preventionTips":["Never place the remote URL in a position where flags or empty placeholders can end up as the value","Fill config templates completely so placeholders never resolve to empty strings","Treat any URL starting with `-` as hostile; remote URLs must begin with a scheme, `user@host`, or a path","Validate the remote value once at config-load time instead of at every network call"],"tags":["git","security","validation","url","option-injection"],"backgroundTag":"invalid-url-format","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}