{"record":{"id":"5042d879d22451d6","repo":"jdx/mise","slug":"invalid-oci-layer-path","errorCode":null,"errorMessage":"invalid OCI layer path {}","messagePattern":"invalid OCI layer path (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/oci/packages.rs","lineNumber":291,"sourceCode":"\n    let magic = reader.fill_buf()?;\n    if magic.starts_with(&[0x1f, 0x8b]) {\n        Ok(LayerCompression::Gzip)\n    } else if magic.starts_with(&[0x28, 0xb5, 0x2f, 0xfd]) {\n        Ok(LayerCompression::Zstd)\n    } else {\n        Ok(LayerCompression::Tar)\n    }\n}\n\nfn clean_layer_path(path: &Path) -> Result<PathBuf> {\n    let mut out = PathBuf::new();\n    for component in path.components() {\n        match component {\n            Component::CurDir | Component::RootDir => {}\n            Component::Normal(part) => out.push(part),\n            Component::ParentDir | Component::Prefix(_) => {\n                bail!(\"invalid OCI layer path {}\", path.display())\n            }\n        }\n    }\n    Ok(out)\n}\n\nfn apply_oci_whiteout(rootfs: &Path, rel: &Path) -> Result<bool> {\n    let Some(name) = rel.file_name().and_then(|n| n.to_str()) else {\n        return Ok(false);\n    };\n    let parent = rel.parent().unwrap_or_else(|| Path::new(\"\"));\n    if name == \".wh..wh..opq\" {\n        let dir = rootfs.join(parent);\n        if dir.is_dir() {\n            for entry in fs::read_dir(&dir)? {\n                remove_path(&entry?.path())?;\n            }\n        }","sourceCodeStart":273,"sourceCodeEnd":309,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/oci/packages.rs#L273-L309","documentation":"While unpacking base-image layers, clean_layer_path sanitizes each tar entry path, rejecting components that could escape the rootfs. ParentDir ('..') and Prefix (e.g. Windows drive) components are treated as invalid and bail with the full offending path. This is a path-traversal safety guard on layer contents.","triggerScenarios":"A layer tarball contains an entry whose normalized path includes '..' or a Windows prefix component, and unpack_base_layers processes it.","commonSituations":"Malicious or corrupted OCI base images; hand-built layer tarballs with absolute or ../ paths; third-party registries with non-conforming layer archives.","solutions":["Use a trusted base image from a reputable registry","Inspect the layer tarball (`tar -tf`) for '..' or absolute entries and rebuild it with relative paths","Re-pull the base image in case of corruption (verify digest)"],"exampleFix":"null","handlingStrategy":"validation","validationCode":"# check a layer tarball before use\ntar -tf layer.tar | grep -E '(^|/)\\.\\.(/|$)' && echo 'UNSAFE: parent-dir entries' || echo 'ok'","typeGuard":"function isSafeLayerPath(p) {\n  const parts = p.split(\"/\").filter(x => x && x !== \".\");\n  return !parts.includes(\"..\") && !p.startsWith(\"/\") && !/^[A-Za-z]:/.test(p);\n}","tryCatchPattern":null,"preventionTips":["Pull base images only from trusted registries","Pin base images by digest","Inspect third-party layer tarballs for ../ entries before use"],"tags":["oci","security","path-traversal"],"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-14T00:17:10.932Z"}