jdx/mise · error
brew-cask: refusing elevated operation through mutable direc
Error message
brew-cask: refusing elevated operation through mutable directory {} What it means
Certain cask operations may run with elevated (sudo) privileges while touching user-owned paths. Before doing so, mise checks each directory on the path with strict_elevated_directory_is_trusted (ownership, mode, and position under a stable prefix). If any directory on the path is mutable — owned by someone other than root or the current user, or group/other-writable — the elevated operation is refused, because a local attacker could swap the directory to redirect privileged writes.
Source
Thrown at src/system/packages/brew/cask/mod.rs:1730
target
.file_name()
.ok_or_else(|| eyre!("brew-cask: generic artifact target has no filename"))?,
))
}
#[cfg(unix)]
fn validate_strict_elevated_ancestors(path: &Path) -> Result<()> {
use std::os::unix::fs::MetadataExt;
let stable_prefix = file::desymlink_path(&prefix::prefix());
for directory in path.ancestors() {
let metadata = directory.symlink_metadata()?;
if !strict_elevated_directory_is_trusted(
directory,
&stable_prefix,
metadata.uid(),
metadata.mode(),
) {
bail!(
"brew-cask: refusing elevated operation through mutable directory {}",
directory.display()
);
}
}
Ok(())
}
#[cfg(unix)]
fn strict_elevated_directory_is_trusted(
directory: &Path,
stable_prefix: &Path,
uid: u32,
mode: u32,
) -> bool {
uid == 0
&& mode & 0o002 == 0
// Intel Homebrew conventionally uses root:admin 0775 for /usr/local.View on GitHub (pinned to afd2eddd3a)
Solutions
- Fix the flagged directory: sudo chown root:admin <dir> (or your user) and sudo chmod o-w,g-w <dir> so it is not writable by others
- Check for ACLs with ls -le on macOS and strip permissive ones (chmod -N)
- Audit every path component to the target directory, not just the leaf
- Avoid running installs as different users against the same caskroom/target paths
Example fix
# before drwxrwxrwx admin /Applications/MyApp # after sudo chown root:admin /Applications/MyApp && sudo chmod 755 /Applications/MyApp
Defensive patterns
Strategy: validation
Validate before calling
// verify the whole path to a system target is root/current-user owned and not group/other writable
let mut dir = target.parent().unwrap().to_path_buf();
loop {
let md = std::fs::metadata(&dir)?;
if md.uid() != 0 && md.uid() != nix::unistd::geteuid().as_raw() { return Err(format!("untrusted owner: {}", dir.display())); }
if md.mode() & 0o022 != 0 { return Err(format!("group/other-writable: {}", dir.display())); }
if !dir.pop() { break; }
} Prevention
- Keep system target directories (e.g. /Applications subdirs) owned by root:admin with mode 755
- Check for permissive ACLs (ls -le on macOS) and strip them with chmod -N
- Do not run installs as different users against shared target paths
- Audit writable-by-others directories: find /Applications -perm -o+w
When it happens
Trigger: An elevated cask operation (e.g. installing to /Applications or another system path via FlightSudo) walks the target's parent directories; one of them fails strict_elevated_directory_is_trusted because its uid differs from root/current user or its mode is group/other-writable.
Common situations: A /Applications or /opt subdirectory chowned to another user or made world-writable; a shared machine where an admin relaxed permissions; macOS with a directory having an ACL granting write to others; running mise under a different user than the one that created intermediate directories.
Understand the failure class
Background: "You do not have permission" / 403 Forbidden errors: authenticated but not allowed — causes and fixes across open-source libraries — this error's family across 31 libraries.
Related errors
- brew-cask: temporary artifact directory is not private
- brew-cask: refusing elevated operation through mutable direc
- brew-cask: refusing operation through untrusted directory {}
- brew-cask: staging directory is not owned by the current use
- brew-cask: invalid {kind} '{value}'
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/d42f00e492013309.
Report an issue: GitHub.