{"record":{"id":"28fb83bf9b6b26b9","repo":"jdx/mise","slug":"invalid-tool-version-s-contains-path-traversa","errorCode":null,"errorMessage":"invalid tool version {s:?}: contains path-traversal sequence","messagePattern":"invalid tool version (.+?): contains path-traversal sequence","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/toolset/tool_request.rs","lineNumber":721,"sourceCode":"/// The deny list is the minimum set of characters that can break out of either\n/// a single- or double-quoted shell string, or that trigger expansion *inside*\n/// double quotes: quotes themselves, backslash, backtick, and `$`. Plus control\n/// 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 '-'\");","sourceCodeStart":703,"sourceCodeEnd":739,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/toolset/tool_request.rs#L703-L739","documentation":"mise rejects tool version strings containing the '..' path-traversal sequence. Versions are used to build install paths, so a value like '../../etc' could escape the install directory. The check runs in validate_version_string during ToolRequest construction.","triggerScenarios":"Passing a version containing '..' (e.g. `mise install foo@..`, foo@1.2..3) through new_with_options or equivalent CLI/config input.","commonSituations":"Path accidentally pasted as a version; scripted substitution injecting a relative path; typo'd ellipsis or range syntax in mise.toml [tools] entries.","solutions":["Remove the '..' sequence and supply a real version identifier.","If a path was intended, use the path: prefix (path:/some/dir) instead of a version.","Audit generated configs/scripts that interpolate values into version positions."],"exampleFix":"// mise.toml before\nnode = \"../shared/node\"\n// after\nnode = \"path:../shared/node\"  # or a concrete version like \"20.11.0\"","handlingStrategy":"validation","validationCode":"function validVersion(v) {\n  return typeof v === 'string' && !v.includes('..');\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep paths and versions in separate fields; use path: for directories.","Lint mise.toml for '..' in version values.","Sanitize generated configs that interpolate user input."],"tags":["mise","validation","security","path-traversal"],"backgroundTag":"path-traversal-blocked","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}