jdx/mise · error

invalid tool ref : contains path-traversal sequence

Error message

invalid tool ref {s:?}: contains path-traversal sequence

What it means

Ref strings (ref:/branch:/tag:/rev: values) may not contain the '..' path-traversal sequence, since refs feed into path and argument construction. validate_ref_string rejects any such value during ToolRequest creation.

Solutions

  1. Use a single concrete ref name without '..'.
  2. For git ranges/refspecs, resolve to a concrete branch/tag/commit first and reference that.
  3. Fix generators/scripts emitting '..' into version fields.

Example fix

// before
node = { version = "ref:main..dev" }
// after
node = { version = "ref:dev" }
Defensive patterns

Strategy: validation

Validate before calling

function validRef(r) {
  return typeof r === 'string' && !r.includes('..');
}

Prevention

When it happens

Trigger: A ref value containing '..' (e.g. ref:../evil, branch:a..b) passed through new_with_options or config parsing.

Common situations: Pasting a relative path into a ref field; git refspecs or ranges (a..b) supplied where a single ref name is required; generated config interpolation errors.

Understand the failure class

Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.

Related errors


AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17). Data as JSON: /api/errors/4369fcb759977369. Report an issue: GitHub.

Appendix: source

Thrown at src/toolset/tool_request.rs:742

        bail!("invalid tool version {s:?}: contains forbidden character {c:?}");
    }
    Ok(())
}

/// Validate `ref:`/`branch:`/`tag:`/`rev:` values. Same character rules as
/// version strings: branch/tag names already use the same broad vocabulary
/// (`/`, `+`, `-`, etc.), so only shell-quote-breaking characters and leading
/// dashes need rejection. Kept as a separate function for distinct error
/// messages.
fn validate_ref_string(s: &str) -> Result<()> {
    if s.is_empty() {
        return Ok(());
    }
    if s.starts_with('-') {
        bail!("invalid tool ref {s:?}: must not start with '-'");
    }
    if s.contains("..") {
        bail!("invalid tool ref {s:?}: contains path-traversal sequence");
    }
    if let Some(c) = s.chars().find(|c| is_forbidden_version_char(*c)) {
        bail!("invalid tool ref {s:?}: contains forbidden character {c:?}");
    }
    Ok(())
}

/// Validate `path:` values. Filesystem paths legitimately contain `/`, spaces,
/// and many other characters, but the resolved path becomes `ctx.rootPath` /
/// `installPath` for path-mode tools and is interpolated into shell commands
/// by some plugin hooks. Reject the same shell-quote-breaking characters as
/// version strings — `$`, backtick, quotes, and `\` — so a hostile `path:`
/// entry in a project config cannot inject shell syntax. Path traversal is
/// intentionally not rejected here because `path:../tools/foo` is a normal
/// relative-path use case.
///
/// The list is written for a POSIX shell, which is why `\` is on it. On Windows `\` is a path
/// separator instead, so it is rewritten by [`windows_path_separators`] before it gets here rather

View on GitHub (pinned to 533346cc37)