Skip to content
AppleGHSA-r3h2-rgqf-9hv9

Loading an OCI image layout can read host files through a symlink

MediumPublished Aug 30, 2026

## Impact An attacker who can supply an OCI image layout for a victim to load (`cctl`/`container images load`, `ImageStore.load(from:)`) — via a malicious registry, a compromised base image, or a pull request that changes which image gets fetched — can read the contents of files on the victim's host that the loading user has access to, with no privileges beyond running the load. This is most severe in CI/CD, where loading and re-pushing an image commonly runs unattended. Two defects combine to make this practical: the importer will resolve a symlinked blob entry instead of rejecting it, and a digest-mismatch error discloses the digest needed to exploit that. See Details for the mechanism. The only information an attacker needs up front is a target file's path and size, both commonly recoverable from CI logs or standard filesystem conventions. ## Details A prior fix (CVE-2026-20613 / GHSA-cq3j-qj2h-6rv3) prevented tar entries from escaping the extraction directory via relative paths such as `../`. It did not cover symlink entries with an absolute target — those were created without any check on where they pointed. The image-loading code subsequently resolved that symlink: when ...

GitHub advisory

Affected versions

PackageAffectedFixed in
github.com/apple/container
Product
< 1.3.01.3.0
github.com/apple/containerization
Product
< 0.41.00.41.0
Details and references

## Impact An attacker who can supply an OCI image layout for a victim to load (`cctl`/`container images load`, `ImageStore.load(from:)`) — via a malicious registry, a compromised base image, or a pull request that changes which image gets fetched — can read the contents of files on the victim's host that the loading user has access to, with no privileges beyond running the load. This is most severe in CI/CD, where loading and re-pushing an image commonly runs unattended. Two defects combine to make this practical: the importer will resolve a symlinked blob entry instead of rejecting it, and a digest-mismatch error discloses the digest needed to exploit that. See Details for the mechanism. The only information an attacker needs up front is a target file's path and size, both commonly recoverable from CI logs or standard filesystem conventions. ## Details A prior fix (CVE-2026-20613 / GHSA-cq3j-qj2h-6rv3) prevented tar entries from escaping the extraction directory via relative paths such as `../`. It did not cover symlink entries with an absolute target — those were created without any check on where they pointed. The image-loading code subsequently resolved that symlink: when it opened an extracted blob to read and hash it, it did not verify the path was a regular file, and so read through the symlink to its target and hashed that file's content. The attacker chooses the symlink's target but does not know that file's content or digest in advance. On a mismatch against the digest declared in the manifest, the error message included the digest it had just computed — handing the attacker the target file's digest. A deliberately incorrect first attempt surfaces the digest this way, and a second attempt using that digest completes the read. ## Affected code - Archive extraction's handling of symlink entries (`ArchiveReader`) — the symlink file itself is still created inside the extraction directory; only its target is unchecked. The fix does not change this: it closes the issue by rejecting the symlink on the read side below, not by validating the target at extraction time. - The code that reads a blob back during image-layout loading (`LocalContent`, via `ImageStore.load(from:)`) — fixed to require a regular file. - The digest-mismatch error message, raised both during import and during registry push — fixed to omit both digest values. Not affected: pulling an image from a remote registry streams and hashes each blob directly rather than extracting local tar entries, so it is not exposed to the symlink component of this issue. ## Mitigations 1. Upgrade to the version of `apple/containerization` containing the fix. 2. Do not load OCI image layouts from untrusted sources — a registry, base image, or CI step that supplies a layout tar is part of the trust boundary, not just the resulting container's contents. 3. In CI/CD, avoid loading an image reference that a pull request or other external input can influence on a runner with access to credentials or other sensitive files. 4. If an untrusted layout has already been loaded on an affected version, treat any files readable by that user as potentially exposed and rotate the corresponding credentials — restricting or sandboxing the resulting container does not mitigate this, since the read occurs on the host during `load`, before any container exists. 5. Remove any image imported from an untrusted layout and prune the local content store, since a copy of the exposed file's content can remain there even if the image was never run or pushed: ```bash container image delete <ref> container image prune --all ``` ## Verifying whether you are affected Before loading a layout, check whether any of its blobs are symlinks. If the layout is still a tar file, list its members without extracting: ```bash tar -tvf <layout.tar> | grep '^l' ``` If it has already been extracted to a directory: ```bash find <layout-directory>/blobs/sha256 -type

Severity from
GitHub (reviewed advisory)

More Apple advisories

All Apple

Critical advisories by email

Wednesdays: the week’s critical and high advisories in the AI and data stack, with the fixed versions. Only in weeks that have some.

Double opt-in. Unsubscribe any time.