Skip to content
OpenAdvisories
High · 7.1 RUSTSEC-2026-0450

`ocipkg`: unpacking an OCI archive can write and delete files outside the local image store (path traversal)

Published Oct 30, 2026 · Updated Nov 6, 2026 · Assigned by RUSTSEC

Description

When `ocipkg` unpacks an OCI archive, the destination directory is derived from the
image name, which `ocipkg` reads from the archive's **own** `index.json`
(`org.opencontainers.image.ref.name`). That name is attacker-controlled, and
`ImageName::parse` accepts a hostname of `..`, so the computed destination escapes the
local image store. A "zip-slip"-style path traversal (CWE-22 / CWE-23). This is esclatable to code execution.

In `Artifact::unpack` (`src/image/artifact.rs`), the destination is
`image_dir(name) = data_dir().join(name.as_path())` (`src/local/mod.rs:31`), where the
name comes from `get_name_from_index` (`src/image/layout.rs:114-124`):

```rust
let image_name = self.base.get_name()?; // from the archive's index.json ref.name
let dest = image_dir(&image_name)?; // data_dir().join(name.as_path()); hostname ".." escapes
if dest.exists() {
if overwrite {
fs::remove_dir_all(&dest)?; // deletes a directory OUTSIDE the store
}
}
fs::create_dir_all(&dest)?;
// ... each tar layer is then unpacked under `dest` (also outside the store)
```

## The fix

Fixed in `ocipkg` 0.4.1 by [PR #223](https://github.com/termoshtt/ocipkg/pull/223). The leading
reference component is validated against the `org.opencontainers.image.ref.name` grammar from OCI
Image Specification 1.1.1 on parse and deserialization, and `local::image_dir` revalidates the name
and rejects any non-normal path component (e.g. `..`) before any filesystem mutation, so a crafted
archive can no longer escape the local image store.

Affected packages

EcosystemPackageAffectedFixedRecord
crates.io ocipkg >= 0.0.0-0, < 0.4.1 0.4.1 RUSTSEC-2026-0450

References