jdx/mise · error
brew-cask: refusing to stage generic artifact through a path
Error message
brew-cask: refusing to stage generic artifact through a path outside the caskroom: {} What it means
Generic artifacts are also copied into a temporary Caskroom so Homebrew-style layouts stay intact. After joining the source's stage-relative path onto the temporary caskroom, mise re-verifies that the joined path is still inside that caskroot after resolution. If the relative path escapes (via symlinks or '..'), staging is refused — otherwise the trusted caskroom copy could write outside the caskroom it was scoped to.
Source
Thrown at src/system/packages/brew/cask.rs:1720
fn install_generic_artifact(
stage: &Path,
temporary_caskroom: &Path,
artifact: &GenericArtifact,
targets: &mut FlightTargetTransaction,
) -> Result<()> {
let source = find_artifact_matching(stage, &artifact.source, |_| true)
.ok_or_else(|| eyre!("brew-cask: artifact '{}' was not found", artifact.source))?;
if !path_starts_with_resolved_root(&source, stage) {
bail!(
"brew-cask: refusing generic artifact source outside the extraction root: {}",
source.display()
);
}
let target = generic_artifact_target_path(&artifact.target)?;
let relative_source = source.strip_prefix(stage)?;
let caskroom_source = temporary_caskroom.join(relative_source);
if !path_starts_with_resolved_root(&caskroom_source, temporary_caskroom) {
bail!(
"brew-cask: refusing to stage generic artifact through a path outside the caskroom: {}",
caskroom_source.display()
);
}
#[cfg(not(unix))]
if let Some(parent) = target.parent() {
file::create_dir_all(parent)?;
}
let elevated_target = targets.protect_generic(&target)?;
copy_generic_artifact(&source, &target, elevated_target.as_deref())?;
if let Some(parent) = caskroom_source.parent() {
file::create_dir_all(parent)?;
}
file::make_symlink(&target, &caskroom_source)?;
targets.record_installed(target);
Ok(())
}
View on GitHub (pinned to 9dcfcaa0dc)
Solutions
- Audit the cask's archive for symlinks in generic artifact paths and report the cask if any escape
- If you maintain the tap, ship real files (dereference symlinks when packaging)
- Do not bypass the guard by pre-creating caskroom paths — the check is scoped exactly to what the cask may write
Defensive patterns
Strategy: try-catch
Try / catch
Catch 'refusing to stage generic artifact through a path outside the caskroom' as a terminal security failure for that cask; log token and artifact and report. Do not pre-create or relax caskroom directories to work around it.
Prevention
- Keep generic artifact targets/targets relative within the cask layout
- Package artifacts without symlink chains crossing the extraction root
When it happens
Trigger: An artifact whose relative_source, once symlinks under the temporary caskroom resolve, points outside the temporary caskroom — e.g. a staged symlink chained to ../../../, or a directory swapped during staging.
Common situations: Maliciously crafted cask archives; taps that package symlink trees; races where staged content is replaced between extraction and staging.
Related errors
- brew-cask: refusing generic artifact source outside the extr
- brew-cask: staged symlink path escaped extraction root: {}
- brew-cask: invalid {kind} '{value}'
- brew-cask: temporary artifact directory is not private
- brew-cask: refusing elevated operation through mutable direc
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/7e18ad336e898bff.
Report an issue: GitHub.