{"record":{"id":"9229a7ced604c332","repo":"jdx/mise","slug":"brew-cask-invalid-structured-flight-path-9229a7","errorCode":null,"errorMessage":"brew-cask: invalid structured flight path '{}'","messagePattern":"brew-cask: invalid structured flight path '(.+?)'","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/packages/brew/cask/flight.rs","lineNumber":1134,"sourceCode":"        .replace(\"{{staged_path}}\", &staged_path.to_string_lossy())\n        .replace(\"{{appdir}}\", &appdir.to_string_lossy());\n    if let Some(version) = version {\n        value = value.replace(\"{{version}}\", version);\n    }\n    if let Some(rest) = value.strip_prefix(\"~/\") {\n        value = crate::dirs::HOME.join(rest).to_string_lossy().to_string();\n    }\n    value\n}\n\npub(super) fn validate_flight_relative_path(path: &str) -> Result<()> {\n    let path = Path::new(path);\n    if path.is_absolute()\n        || path\n            .components()\n            .any(|component| matches!(component, Component::ParentDir))\n    {\n        bail!(\n            \"brew-cask: invalid structured flight path '{}'\",\n            path.display()\n        );\n    }\n    Ok(())\n}\n\npub(super) fn expand_braces(pattern: &str) -> Vec<String> {\n    let Some(start) = pattern.find('{') else {\n        return vec![pattern.to_string()];\n    };\n    let Some(end_offset) = pattern[start + 1..].find('}') else {\n        return vec![pattern.to_string()];\n    };\n    let end = start + 1 + end_offset;\n    let prefix = &pattern[..start];\n    let suffix = &pattern[end + 1..];\n    let mut expanded = Vec::new();","sourceCodeStart":1116,"sourceCodeEnd":1152,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/packages/brew/cask/flight.rs#L1116-L1152","documentation":"A relative path used in a structured cask flight operation was rejected because it is absolute or contains a `..` (ParentDir) component. Homebrew validates every flight path to keep operations confined to the staged directory and throws this on any escape attempt or malformed path.","triggerScenarios":"parse_flight_path, resolve_flight_path, or expand_staged_glob receive a path string that is absolute (`/Applications/App.app`) or includes `..` (e.g. `../../shared`); typically from a cask stanza or generated config.","commonSituations":"Cask authors accidentally writing absolute destinations; path templates that interpolate user/version strings producing `..`; copy-paste from non-staged-context scripts.","solutions":["Remove the leading `/` and make the path relative to staged_path","Eliminate `..` components by restructuring the relative path","Validate user- or upstream-supplied names before interpolating into flight paths","Run `brew audit --strict` on the cask to catch bad paths pre-release"],"exampleFix":"// before\npath: \"/Applications/../../opt/App\"\n// after\npath: \"App.app\"  // relative to staged_path","handlingStrategy":"validation","validationCode":"fn is_safe_relative(p: &str) -> bool {\n    let path = std::path::Path::new(p);\n    !path.is_absolute()\n        && !path.components().any(|c| c == std::path::Component::ParentDir)\n}","typeGuard":"fn flight_path_ok(p: &str) -> bool {\n    !std::path::Path::new(p).is_absolute()\n        && std::path::Path::new(p).components().all(|c| c != std::path::Component::ParentDir)\n}","tryCatchPattern":"match validate_flight_relative_path(p) {\n    Err(e) => { log::warn!(\"bad flight path {p}: {e}\"); sanitize_and_retry(p); }\n    Ok(()) => proceed(),\n}","preventionTips":["Sanitize interpolated names (versions, tokens) before joining paths","Write stanzas with relative paths only","Run `brew audit --strict` to catch traversal-prone paths","Never accept user-supplied absolute destinations in generated flight config"],"tags":["brew","cask","path-validation","security"],"backgroundTag":"path-traversal-blocked","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}