KINWILDER

Rust & systems · Code anatomy

Memory safe. Boundary broken.

Three innocent lines in a Rust archive library explain why memory safety is only the beginning of a security argument.

Kinwilder research desk · · AI-assisted analysis

Code specimen

tar-rs 0.4.44 · entry.rs · verbatim excerpt

let prev = fs::metadata(dst);
if prev.map(|m| m.is_dir()).unwrap_or(false) {
    return Ok(());
}

A directory can be a destination. It can also be a promise you have not actually checked.

In March 2026, the Rust ecosystem published CVE-2026-33056 / RUSTSEC-2026-0067: tar-rs through 0.4.44 could change permissions on directories outside an archive's extraction root. Version 0.4.45 fixes this particular issue. The interesting part is the mismatch between the object the program thinks it checked and the object the operating system actually checked. RustSec advisory.

Read the three lines

The specimen below is a short, verbatim excerpt from src/entry.rs in tar-rs 0.4.44, inside the AlreadyExists branch of unpack_dir. The surrounding function tries to create a directory. If one appears to exist, it accepts that situation and continues. Upstream source.

metadata follows a symlink to its target. is_dir() then answers a question about that target. The value is a perfectly valid Rust value, yet it proves the wrong proposition: a directory exists at the end of this resolution, not this archive entry names a real directory contained within our destination. Rust's API contract.

The published advisory describes an archive with a symlink followed by a directory entry at the same name. Directory creation fails because the link already exists; the fallback follows it; subsequent permission handling can reach the external directory. The operation remains limited by the extraction process's operating-system permissions. This is not a claim of arbitrary root access. Maintainer advisory and fix.

The one-word patch and the larger lesson

The fix uses symlink_metadata for this check, so a symbolic link is inspected as a link and rejected by the directory test. That addresses this reported path. It is not a universal cure for filesystem containment: intermediate path components and changes between a check and a later operation still deserve separate analysis.

Our interpretation: the security property belongs to the entire sequence of filesystem operations. A clean pathname does not guarantee a contained operation. A check and a later mutation need to agree on object identity, resolution policy, and permissions. A useful review question is: “Can the next syscall reach something different from the object we just approved?”

A defender's review plan

Find every archive ingestion path, including package caches, backup restore jobs, document conversion workers, and container tooling. Check the actual resolved dependency versions in the deployed build. Upgrade affected tar dependencies to a maintained release containing the fix; 0.4.45 is the historical minimum for this advisory, not a recommendation to stop there.

Run extraction as a dedicated low-privilege identity in a disposable directory. Restrict the filesystem that identity can mutate. Decide whether the application needs to preserve archive ownership and permissions at all. Add a regression test that asserts both extracted output and unchanged metadata on a separate temporary sentinel directory. The latter catches the side effect a content-only assertion misses.

For an authorized pentest, record the service identity and extraction workflow first. A vulnerable library on disk does not establish reachable impact. Demonstrate effects only on disposable fixtures and retain the dependency lockfile, configuration, and before/after metadata with the finding.

What we have and have not established

This is analysis of a publicly disclosed, patched vulnerability and its published source. We have not discovered a new tar-rs flaw or reproduced exploitation against a deployed service. The broader review method above is Kinwilder commentary. The practical lesson is precise: Rust prevents many memory errors; it cannot decide which filesystem objects your application is entitled to change.

Sources

Editorial standard · root@kinwilder.com · RSS · Outpost