jdx/mise · error
brew-cask: invalid generic artifact parent
Error message
brew-cask: invalid generic artifact parent
What it means
The brew-cask installer validates every component of an artifact's path relative to its resolved parent directory before descending into it. Only plain path components (Component::Normal) are allowed; `..`, `.`-style or root/prefix components mean the artifact would escape or address outside the intended directory. The library bails to prevent path traversal during cask staging.
Source
Thrown at src/system/packages/brew/cask/mod.rs:2073
|| current_groups.contains(&stat.st_gid);
let writable_by_untrusted = stat.st_mode & 0o002 != 0
|| (stat.st_mode & 0o020 != 0 && (!allow_current_user || !trusted_group));
if !SFlag::from_bits_truncate(stat.st_mode).contains(SFlag::S_IFDIR)
|| !trusted_owner
|| writable_by_untrusted
{
bail!(
"brew-cask: refusing operation through untrusted directory {}",
directory.display()
);
}
Ok(())
};
let mut directory = resolved_root.to_path_buf();
verify(&fd, &directory)?;
for component in relative.components() {
let Component::Normal(name) = component else {
bail!("brew-cask: invalid generic artifact parent");
};
directory.push(name);
fd = match openat(&fd, name, flags, Mode::empty()) {
Ok(fd) => fd,
Err(nix::errno::Errno::ENOENT) if create_missing => {
match nix::sys::stat::mkdirat(
&fd,
name,
Mode::S_IRWXU | Mode::S_IRGRP | Mode::S_IXGRP | Mode::S_IROTH | Mode::S_IXOTH,
) {
Ok(()) | Err(nix::errno::Errno::EEXIST) => {}
Err(err) => {
return Err(err).wrap_err_with(|| {
format!(
"brew-cask: cannot create operation directory {}",
directory.display()
)
});View on GitHub (pinned to afd2eddd3a)
Solutions
- Inspect the cask definition's artifact paths and remove any `..`, absolute-path, or `.` components so targets are relative and below the stage root
- Update/refresh the cask source (brew tap update / mise update) in case the metadata is outdated
- Report the cask as unsafe to the tap maintainer if the traversal is intentional
Example fix
// before (cask artifact declaration)
{"artifacts": [{"type": "generic", "target": "../../usr/local/bin/app"}]}
// after
{"artifacts": [{"type": "generic", "target": "bin/app"}]} Defensive patterns
Strategy: validation
Validate before calling
use std::path::{Component, Path};
fn is_safe_relative(p: &Path) -> bool {
p.is_relative()
&& p.components().all(|c| matches!(c, Component::Normal(_)))
} Type guard
fn has_only_normal_components(p: &Path) -> bool {
p.components().all(|c| matches!(c, Component::Normal(_)))
} Try / catch
match result {
Err(e) if e.to_string().contains("invalid generic artifact parent") => {
eprintln!("cask artifact path contains traversal components; fix the cask JSON");
}
Err(e) => return Err(e),
Ok(v) => v,
} Prevention
- Only use relative, forward paths in cask artifact declarations
- Never reference paths outside the staged bundle with `..`
- Validate third-party cask JSON before installing from untrusted taps
When it happens
Trigger: Installing a cask whose generic artifact relative path contains a parent-directory component (`..`), a root component, or another non-Normal component (e.g. prefix, CurDir) while iterating relative.components() to open/create each directory level.
Common situations: A cask formula (or a hand-edited / malicious cask JSON) declares an artifact target like `../../etc/foo` or an absolute path instead of a path relative to the staged root; corrupted cached cask metadata after a Homebrew format change.
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
- brew-cask: invalid {kind} '{value}'
- brew-cask: staged symlink path escaped extraction root: {}
- brew-cask: refusing generic artifact source outside the extr
- brew-cask: refusing to stage generic artifact through a path
- brew-cask: completion target '{}' must not contain '..'
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/c7f6f270130c4f3a.
Report an issue: GitHub.