{"record":{"id":"aaeedfb784f09444","repo":"jdx/mise","slug":"ref-must-not-start-with","errorCode":null,"errorMessage":"`ref` must not start with `-`","messagePattern":"`ref` must not start with `-`","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/repos.rs","lineNumber":135,"sourceCode":"                if let Component::Normal(segment) = component {\n                    resolved.push(segment);\n                }\n            }\n            resolved\n        };\n        let Some(url) = config.url.map(|s| s.trim().to_string()) else {\n            bail!(\"must set `url`\");\n        };\n        if url.is_empty() {\n            bail!(\"must set a non-empty `url`\");\n        }\n        if url.starts_with('-') {\n            bail!(\"`url` must not start with `-`\");\n        }\n        let git_ref = config.git_ref.map(|s| s.trim().to_string());\n        let git_ref = match git_ref {\n            Some(git_ref) if git_ref.is_empty() => bail!(\"`ref` must not be empty\"),\n            Some(git_ref) if git_ref.starts_with('-') => bail!(\"`ref` must not start with `-`\"),\n            other => other,\n        };\n        Ok(Self {\n            path_raw,\n            path,\n            url,\n            git_ref,\n        })\n    }\n}\n\nimpl std::fmt::Display for RepoRequest {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"{}\", file::display_path(&self.path))\n    }\n}\n\npub(crate) async fn status(requests: &[RepoRequest]) -> Result<Vec<RepoStatus>> {","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/repos.rs#L117-L153","documentation":"Injection-safety validation in system repos from_toml(): the repo config's `ref` field starts with '-' after trimming, which a git command line could interpret as an option flag. The bail rejects ref values that could become argument injection.","triggerScenarios":"Calling from_toml with `git_ref = \"--force\"` or any hyphen-leading value.","commonSituations":"Pasting git options into the ref field; shifted/generated config fields; malicious repo configs.","solutions":["Use only a branch name, tag, or SHA for `ref` (optionally prefixed with an explicit `refs/heads/`, `refs/tags/`, or SHA form).","Remove any git flags from the ref value.","Audit the config file for misplaced fields."],"exampleFix":"// before\n[[repos]]\npath = \"repo\"\nurl = \"https://github.com/org/repo.git\"\nref = \"--track\"\n\n// after\n[[repos]]\npath = \"repo\"\nurl = \"https://github.com/org/repo.git\"\nref = \"main\"","handlingStrategy":"validation","validationCode":"fn is_safe_ref(r: &str) -> bool {\n    let r = r.trim();\n    !r.is_empty() && !r.starts_with('-')\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use only branch/tag/SHA values for ref","Never paste git flags into the ref field","Sanitize user-supplied refs before writing config"],"tags":["config","security","argument-injection"],"backgroundTag":"invalid-argument-value","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}