{"record":{"id":"6ca5f0679d17dd8b","repo":"jdx/mise","slug":"invalid-tool-version-s-contains-forbidden-cha","errorCode":null,"errorMessage":"invalid tool version {s:?}: contains forbidden character {c:?}","messagePattern":"invalid tool version (.+?): contains forbidden character (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/toolset/tool_request.rs","lineNumber":634,"sourceCode":"/// characters (newlines split shell tokens) and `..` (filesystem traversal).\n/// Everything else is allowed so legitimate version vocabulary (npm-style\n/// semver ranges like `>=20 <21 || >=22` or `^1.0.0`, dates, channel names,\n/// `lts/hydrogen`, etc.) continues to work — those characters are only\n/// dangerous in *unquoted* shell context, which cannot occur without one of\n/// the rejected expansion characters appearing first. Leading dashes are also\n/// rejected so backend install tools cannot mistake a version for a CLI flag.\nfn validate_version_string(s: &str) -> Result<()> {\n    if s.is_empty() {\n        return Ok(());\n    }\n    if s.starts_with('-') {\n        bail!(\"invalid tool version {s:?}: must not start with '-'\");\n    }\n    if s.contains(\"..\") {\n        bail!(\"invalid tool version {s:?}: contains path-traversal sequence\");\n    }\n    if let Some(c) = s.chars().find(|c| is_forbidden_version_char(*c)) {\n        bail!(\"invalid tool version {s:?}: contains forbidden character {c:?}\");\n    }\n    Ok(())\n}\n\n/// Validate `ref:`/`branch:`/`tag:`/`rev:` values. Same character rules as\n/// version strings: branch/tag names already use the same broad vocabulary\n/// (`/`, `+`, `-`, etc.), so only shell-quote-breaking characters and leading\n/// dashes need rejection. Kept as a separate function for distinct error\n/// messages.\nfn validate_ref_string(s: &str) -> Result<()> {\n    if s.is_empty() {\n        return Ok(());\n    }\n    if s.starts_with('-') {\n        bail!(\"invalid tool ref {s:?}: must not start with '-'\");\n    }\n    if s.contains(\"..\") {\n        bail!(\"invalid tool ref {s:?}: contains path-traversal sequence\");","sourceCodeStart":616,"sourceCodeEnd":652,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/toolset/tool_request.rs#L616-L652","documentation":"validate_version_string rejects tool version strings that start with '-', contain '..' (path traversal), or contain any character matched by is_forbidden_version_char. mise throws this during ToolRequest construction (new_with_options) to prevent flag injection and path-traversal via tool versions. The message names the exact offending character.","triggerScenarios":"Calling mise with a version string like `node@--foo`, `node@../../etc`, or containing characters such as shell metacharacters, whitespace, or other disallowed symbols, e.g. `mise use node@1.2.3;rm`, or a malformed entry in .tool-versions/mise.toml.","commonSituations":"Typos in mise.toml or .tool-versions files, shell interpolation leaking spaces or semicolons into the version slot (`node@$VERSION extra`), copy-pasting a tag with a leading dash, or scripts building version strings from untrusted input.","solutions":["Inspect the error for the quoted forbidden character and remove/escape it from the version string in your config or CLI argument.","Quote shell variables to avoid stray whitespace: `mise use node@\"$VER\"`.","If you need a ref-like value (branch/tag/rev), use the proper prefix (`ref:`, `tag:`, `branch:`) rather than embedding it in a plain version."],"exampleFix":"// before (mise.toml)\nnode = \"1.2.3 beta\"\n// after\nnode = \"1.2.3\"","handlingStrategy":"validation","validationCode":"function isValidToolVersion(v) {\n  return typeof v === 'string' && v.length > 0 && !v.startsWith('-') &&\n    !v.includes('..') && !/[^A-Za-z0-9._+:@\\/-]/.test(v);\n}\nif (!isValidToolVersion(ver)) throw new Error(`bad version: ${ver}`);","typeGuard":"function isSafeVersion(v) { return typeof v === 'string' && /^v?\\d[\\w.+-]*$/.test(v); }","tryCatchPattern":null,"preventionTips":["Quote shell variables used in version slots to prevent whitespace/metachar injection.","Keep versions in mise.toml rather than composing them dynamically in scripts.","Sanitize any user/CI-supplied version before passing it to mise."],"tags":["validation","cli","version-parsing","security"],"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"}