jdx/mise · error

install_mise must not contain '..': {path:?}

Error message

install_mise must not contain '..': {path:?}

What it means

The remote install_mise path must not contain any '..' path component. This prevents path-traversal style tricks where the configured install location could escape the intended directory or be crafted to point outside expected locations on the remote host.

Source

Thrown at src/system/remote.rs:2220

fn validated_absolute_remote_path_output(output: &str, kind: &str) -> Result<String> {
    let path = output.strip_suffix('\n').unwrap_or(output);
    if !path.starts_with('/') || path.contains(['\0', '\n', '\r']) {
        bail!("{kind} returned an unsafe absolute path: {path:?}");
    }
    Ok(path.to_string())
}

fn validate_install_mise_path(path: &str) -> Result<()> {
    validate_value("mise install path", path)?;
    if path.contains(['\n', '\r']) {
        bail!("install_mise must not contain a newline: {path:?}");
    }
    if !path.starts_with('/') && !path.starts_with("~/") {
        bail!("install_mise must be an absolute path or start with ~/: {path:?}");
    }
    if path.split('/').any(|component| component == "..") {
        bail!("install_mise must not contain '..': {path:?}");
    }
    if matches!(
        path.rsplit('/').next(),
        None | Some("") | Some(".") | Some("~")
    ) {
        bail!("install_mise must name an executable file: {path:?}");
    }
    Ok(())
}

fn validate_remote_executable(command: &str) -> Result<()> {
    validate_value("mise command", command)?;
    let is_path = command.contains('/');
    if command.starts_with('-')
        || command.contains(['\n', '\r'])
        || (!is_path && command.chars().any(char::is_whitespace))
    {
        bail!("remote mise command must be an executable name or path: {command:?}");

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Remove '..' segments; write the canonical absolute path directly
  2. Use the resolved real path of the binary on the remote host
  3. Rebuild path construction so components are joined without traversal

Example fix

// before
install_mise = "/opt/../usr/local/bin/mise"
// after
install_mise = "/usr/local/bin/mise"
Defensive patterns

Strategy: validation

Validate before calling

const noTraversal = (p) => { if (typeof p !== 'string') return false; return !p.split('/').includes('..'); };

Type guard

const hasNoDotDotSegments = (s) => typeof s === 'string' && !s.split('/').includes('..');

Try / catch

try { setInstallMisePath(p); } catch (e) { p = path.posix.normalize(p); if (!hasNoDotDotSegments(p)) throw e; setInstallMisePath(p); }

Prevention

When it happens

Trigger: Configuring install_mise with a value containing a '..' segment, e.g. "/opt/../etc/mise" or "~/../root/mise" — often from string concatenation or resolving symlinks textually.

Common situations: Building the path by joining user input; normalizing paths by hand; copying paths with redundant '..' segments from documentation.

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@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/2b934f2204c7668c. Report an issue: GitHub.