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
- Fix the cask's executable value to a plain path relative to the installer artifact (e.g. "Installer.app/Contents/MacOS/Installer")
- Verify what the staged artifact actually contains and align the stanza with it
- 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
- Write installer executable values as plain paths relative to the artifact root
- Never let cask metadata reference binaries outside the staged payload
- Lint third-party casks for '..' or absolute executable paths before use
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
- mise upgrade --monorepo is not implemented yet
- brew-cask: temporary artifact directory was replaced
- brew-cask: refusing generic artifact copy outside Homebrew p
- brew-cask: refusing operation through untrusted directory {}
- brew-cask: invalid generic artifact parent
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/c8ff27bc54aa7f19.
Report an issue: GitHub.