{"record":{"id":"45caf72dfa878e62","repo":"xai-org/grok-build","slug":"what-value-must-not-start-with","errorCode":null,"errorMessage":"{what} '{value}' must not start with '-'","messagePattern":"(.+?) '(.+?)' must not start with '-'","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/codegen/xai-grok-workspace/src/session/git.rs","lineNumber":3085,"sourceCode":"    if merge_in_progress(git_root).await? {\n        let files = git_cli(git_root, &[\"diff\", \"--name-only\", \"--diff-filter=U\"])\n            .await?\n            .lines()\n            .map(str::to_owned)\n            .collect();\n        return Ok(GitSyncBaseResult {\n            outcome: GitSyncBaseOutcome::Conflicts { files },\n        });\n    }\n    anyhow::bail!(\"merge of base ref '{base}' failed: {merge_out}\")\n}\n/// Reject a ref/branch value that could be parsed as a git option (leading `-`)\n/// or that carries whitespace/control characters or `..`. A boundary guard for\n/// client-influenced refs (notably `base_ref`) so they cannot be smuggled in as\n/// flags; combined with `--end-of-options` at each call site.\nfn ensure_ref_arg_safe(value: &str, what: &str) -> Result<()> {\n    anyhow::ensure!(!value.is_empty(), \"{what} must not be empty\");\n    anyhow::ensure!(\n        !value.starts_with('-'),\n        \"{what} '{value}' must not start with '-'\"\n    );\n    anyhow::ensure!(\n        !value.chars().any(|c| c.is_whitespace() || c.is_control()),\n        \"{what} '{value}' contains whitespace or control characters\"\n    );\n    anyhow::ensure!(\n        !value.contains(\"..\"),\n        \"{what} '{value}' must not contain '..'\"\n    );\n    Ok(())\n}\n/// Seed a committed `.gitignore` (secrets never enter git)\n/// when a fresh conversation branch is created and the repo has none. Distinct\n/// from [`seed_default_excludes`], which seeds the *local-only* `info/exclude`\n/// as a `stage_all` backstop; this file is meant to be committed, so it also\n/// protects explicit user commits and BYO-remote exports. Never overwrites an","sourceCodeStart":3067,"sourceCodeEnd":3103,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-workspace/src/session/git.rs#L3067-L3103","documentation":"ensure_ref_arg_safe rejects any ref value beginning with '-' because git would parse such an argument as an option/flag rather than a ref name (argument injection). The library throws this to prevent client-influenced refs from being smuggled into the git command line as flags; call sites additionally pass --end-of-options as defense in depth.","triggerScenarios":"Passing a caller-supplied ref/branch string starting with '-' (e.g. \"--upload-pack=evil\", \"-o\", \"-C/tmp\") into any git operation that validates it via ensure_ref_arg_safe in crates/codegen/xai-grok-workspace/src/session/git.rs:3085.","commonSituations":"A malicious or buggy client sends a branch name like \"--exec=cmd\"; an upstream system echoes back a git output line that includes a flag; test fixtures accidentally use \"-test-branch\" as a name.","solutions":["Remove the leading '-' — use a valid ref name (letters, digits, '/', '_', '-', '.', not starting with '-') .","Sanitize or reject client input at the API boundary with the same rule the library uses (starts_with('-')).","If you control both sides and truly need an odd name, rename the ref to something that does not collide with option syntax."],"exampleFix":"// before\nlet branch = user_input.trim().to_string();\ngit_ops.merge_to_main(&root, &branch, \"main\", false).await?;\n// after\nlet branch = user_input.trim().to_string();\nanyhow::ensure!(!branch.starts_with('-'), \"invalid branch name\");\ngit_ops.merge_to_main(&root, &branch, \"main\", false).await?;","handlingStrategy":"validation","validationCode":"if ref_name.starts_with('-') { return Err(format!(\"ref '{}' may not start with '-'\", ref_name)); }","typeGuard":null,"tryCatchPattern":"// treat as client input error, not retryable\nmatch result {\n    Err(e) if e.to_string().contains(\"must not start with '-'\") => return Err(HttpError::bad_request(e.to_string())),\n    other => other,\n}","preventionTips":["Never accept raw strings as refs from untrusted input without checking the leading character.","Build branch names through a sanitizer that strips option-like prefixes.","Log rejected inputs — a leading '-' in a ref field often signals attempted injection."],"tags":["git","security","argument-injection","validation"],"backgroundTag":"git-argument-injection","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}