jdx/mise · error

brew-cask: refusing installer executable outside trusted ins

Error message

brew-cask: refusing installer executable outside trusted installer roots: {}

What it means

Before executing a cask's installer artifact, mise joins the configured executable name onto the staging directory and requires staged_relative_path to still resolve inside the stage. If the executable value escapes the stage (via '..', an absolute path, or traversal components), the run is refused: only binaries that shipped inside the staged payload may be executed.

Source

Thrown at src/system/packages/brew/cask.rs:2317

    let relative = appdir.strip_prefix(Path::new("/")).map_err(|_| {
        eyre!(
            "brew-cask: app directory '{}' must be an absolute path",
            appdir.display()
        )
    })?;
    // `allow_current_user` is true because a per-user appdir such as
    // `~/Applications` is legitimately owned by the invoking user.
    open_trusted_directory(Path::new("/"), relative, true, true)
}

fn run_installer_artifact(
    stage: &Path,
    installer: &InstallerArtifact,
    copied_files: &BTreeSet<PathBuf>,
) -> Result<()> {
    let executable = stage.join(&installer.executable);
    if staged_relative_path(stage, &executable).is_none() {
        bail!(
            "brew-cask: refusing installer executable outside trusted installer roots: {}",
            executable.display()
        );
    }
    if !executable.is_file() {
        bail!(
            "brew-cask: installer executable '{}' was not found",
            installer.executable
        );
    }
    let executable = file::desymlink_path(&executable);
    if !executable.starts_with(file::desymlink_path(stage)) && !copied_files.contains(&executable) {
        bail!(
            "brew-cask: refusing installer executable outside trusted installer roots: {}",
            executable.display()
        );
    }
    file::make_executable(&executable)?;

View on GitHub (pinned to 9dcfcaa0dc)

Solutions

  1. Fix the cask's executable value to a plain path relative to the installer artifact (e.g. "Installer.app/Contents/MacOS/Installer")
  2. Verify what the staged artifact actually contains and align the stanza with it
  3. Treat persistent occurrences in a tap cask as a cask bug and report it to the tap

Example fix

# cask installer stanza -- before
executable: "../../usr/local/bin/setup"

# after
executable: "Installer.app/Contents/MacOS/Installer"
Defensive patterns

Strategy: validation

Validate before calling

use std::path::{Path, Component};

fn executable_stays_in_stage(stage: &Path, executable: &str) -> bool {
    let exe = Path::new(executable);
    !exe.is_absolute()
        && !exe.components().any(|c| matches!(c, Component::ParentDir))
        && stage.join(exe).starts_with(stage)
}

Prevention

When it happens

Trigger: An installer executable value like '../../usr/bin/open' or an absolute path; a cask whose executable stanza points above the extracted artifact root; executable names built from untrusted cask metadata.

Common situations: Hand-edited or third-party-tap casks with sloppy executable paths; casks written against a different artifact layout than what was actually downloaded.

Related errors


AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17). Data as JSON: /api/errors/c8ff27bc54aa7f19. Report an issue: GitHub.