Skip to content
AppleGHSA-f689-h8m7-3jp2

Apple: path traversal

HighPublished Aug 30, 2026

## Impact A malicious or compromised OCI registry may be able to serve a manifest or index whose descriptor `digest` field contains path-traversal (`..`) components, causing `container pull`, `run`, `create` (or any other consumer of `ContainerizationOCI`) to open a host file outside the local content store's blob directory during import. The confirmed impact is a file existence and readability oracle: an attacker may be able to observe whether a path exists and is readable on the macOS host, based on success or error behavior. Before the fix described below, the digest file read was unbounded, such that a `digest` with path traversal could refer to a very large or unreadable-to-EOF file, exhausting memory and/or denying service to the pulling process. ## Details `Descriptor.digest` (`Sources/ContainerizationOCI/Descriptor.swift`) was a plain `String` with no format validation, decoded straight from registry responses and on-disk OCI layouts via Swift's synthesized `Codable` conformance. `String.trimmingDigestPrefix` (`Sources/ContainerizationOCI/Content/String+Extension.swift`), used throughout the codebase to turn a digest into a filesystem path component, only split the stri...

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 A malicious or compromised OCI registry may be able to serve a manifest or index whose descriptor `digest` field contains path-traversal (`..`) components, causing `container pull`, `run`, `create` (or any other consumer of `ContainerizationOCI`) to open a host file outside the local content store's blob directory during import. The confirmed impact is a file existence and readability oracle: an attacker may be able to observe whether a path exists and is readable on the macOS host, based on success or error behavior. Before the fix described below, the digest file read was unbounded, such that a `digest` with path traversal could refer to a very large or unreadable-to-EOF file, exhausting memory and/or denying service to the pulling process. ## Details `Descriptor.digest` (`Sources/ContainerizationOCI/Descriptor.swift`) was a plain `String` with no format validation, decoded straight from registry responses and on-disk OCI layouts via Swift's synthesized `Codable` conformance. `String.trimmingDigestPrefix` (`Sources/ContainerizationOCI/Content/String+Extension.swift`), used throughout the codebase to turn a digest into a filesystem path component, only split the string on `:` and returned the remainder verbatim — a digest such as `sha256:../../etc/hosts` came back as `../../etc/hosts`, untouched. `LocalContentStore.get(digest:)` (`Sources/ContainerizationOCI/Content/LocalContentStore.swift`) appended that unvalidated string directly onto the store's `blobs/sha256` directory with `URL.appendingPathComponent`, which does not collapse `..`, and opened the result. Every `container pull`/`run`/`create` reaches this sink through `ImageStore+Import.swift`'s `fetch()` and `getManifestContent()`, so a single malicious manifest is enough — no separate ingestion step is required. `getManifestContent()` doesn't just check whether the traversed path exists. It tries to `.decode()` the file's contents as an OCI manifest or index. Most traversed files aren't valid JSON in that shape, so `JSONDecoder` throws. That error can include a short fragment of the file's actual bytes near the parse failure. This only reaches the local operator's own error output or logs — the registry never sees it. The fix described below closes this too: it rejects the digest before a traversed path is ever built, so `.decode()` never runs on a traversed file at all. The same unvalidated digest does not also give a write primitive. `ImageStore+Import.swift`'s `fetch()` has a cache-hit branch that copies an already-resolved blob into the ingest directory with `FileManager.copyItem`, using the same digest string for both source and destination. `_blobPath` (`blobs/sha256`) and the ingest session directory sit at the same depth under the content store root. A malicious digest's `../` prefix resolves both paths to the same file. The copy fails with `EEXIST`. It never writes attacker-controlled content anywhere new. ## Affected code - `Sources/ContainerizationOCI/Descriptor.swift` (`digest: String`) — decoded with no format validation. - `Sources/ContainerizationOCI/Content/String+Extension.swift` (`trimmingDigestPrefix`) — strips the algorithm prefix without validating what remains. - `Sources/ContainerizationOCI/Content/LocalContentStore.swift` (`get`, `delete`, `delete(digests:)`) — unvalidated digest used to build blob paths. - `Sources/ContainerizationOCI/Content/LocalContent.swift` (`data()`, `decode()`) — read the entire target file into memory with no size bound, independent of the traversal (this is what makes the memory-exhaustion variant possible). - `Sources/Containerization/Image/ImageStore/ImageStore+Import.swift` (`fetch`, `getManifestContent`) — reachable from `container pull`/`run`/`create` on every image reference, not just a special import mode. **Not affected:** the `copyItem` cache-hit branch in `fetch()` cannot be used as a write primitive, for the reason described in Details above. ## Mitigations 1. U

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.

GHSA-f689-h8m7-3jp2: Apple high vulnerability | Advisories
Skip to content
AppleGHSA-f689-h8m7-3jp2

Apple: path traversal

HighPublished Aug 30, 2026

## Impact A malicious or compromised OCI registry may be able to serve a manifest or index whose descriptor `digest` field contains path-traversal (`..`) components, causing `container pull`, `run`, `create` (or any other consumer of `ContainerizationOCI`) to open a host file outside the local content store's blob directory during import. The confirmed impact is a file existence and readability oracle: an attacker may be able to observe whether a path exists and is readable on the macOS host, based on success or error behavior. Before the fix described below, the digest file read was unbounded, such that a `digest` with path traversal could refer to a very large or unreadable-to-EOF file, exhausting memory and/or denying service to the pulling process. ## Details `Descriptor.digest` (`Sources/ContainerizationOCI/Descriptor.swift`) was a plain `String` with no format validation, decoded straight from registry responses and on-disk OCI layouts via Swift's synthesized `Codable` conformance. `String.trimmingDigestPrefix` (`Sources/ContainerizationOCI/Content/String+Extension.swift`), used throughout the codebase to turn a digest into a filesystem path component, only split the stri...

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 A malicious or compromised OCI registry may be able to serve a manifest or index whose descriptor `digest` field contains path-traversal (`..`) components, causing `container pull`, `run`, `create` (or any other consumer of `ContainerizationOCI`) to open a host file outside the local content store's blob directory during import. The confirmed impact is a file existence and readability oracle: an attacker may be able to observe whether a path exists and is readable on the macOS host, based on success or error behavior. Before the fix described below, the digest file read was unbounded, such that a `digest` with path traversal could refer to a very large or unreadable-to-EOF file, exhausting memory and/or denying service to the pulling process. ## Details `Descriptor.digest` (`Sources/ContainerizationOCI/Descriptor.swift`) was a plain `String` with no format validation, decoded straight from registry responses and on-disk OCI layouts via Swift's synthesized `Codable` conformance. `String.trimmingDigestPrefix` (`Sources/ContainerizationOCI/Content/String+Extension.swift`), used throughout the codebase to turn a digest into a filesystem path component, only split the string on `:` and returned the remainder verbatim — a digest such as `sha256:../../etc/hosts` came back as `../../etc/hosts`, untouched. `LocalContentStore.get(digest:)` (`Sources/ContainerizationOCI/Content/LocalContentStore.swift`) appended that unvalidated string directly onto the store's `blobs/sha256` directory with `URL.appendingPathComponent`, which does not collapse `..`, and opened the result. Every `container pull`/`run`/`create` reaches this sink through `ImageStore+Import.swift`'s `fetch()` and `getManifestContent()`, so a single malicious manifest is enough — no separate ingestion step is required. `getManifestContent()` doesn't just check whether the traversed path exists. It tries to `.decode()` the file's contents as an OCI manifest or index. Most traversed files aren't valid JSON in that shape, so `JSONDecoder` throws. That error can include a short fragment of the file's actual bytes near the parse failure. This only reaches the local operator's own error output or logs — the registry never sees it. The fix described below closes this too: it rejects the digest before a traversed path is ever built, so `.decode()` never runs on a traversed file at all. The same unvalidated digest does not also give a write primitive. `ImageStore+Import.swift`'s `fetch()` has a cache-hit branch that copies an already-resolved blob into the ingest directory with `FileManager.copyItem`, using the same digest string for both source and destination. `_blobPath` (`blobs/sha256`) and the ingest session directory sit at the same depth under the content store root. A malicious digest's `../` prefix resolves both paths to the same file. The copy fails with `EEXIST`. It never writes attacker-controlled content anywhere new. ## Affected code - `Sources/ContainerizationOCI/Descriptor.swift` (`digest: String`) — decoded with no format validation. - `Sources/ContainerizationOCI/Content/String+Extension.swift` (`trimmingDigestPrefix`) — strips the algorithm prefix without validating what remains. - `Sources/ContainerizationOCI/Content/LocalContentStore.swift` (`get`, `delete`, `delete(digests:)`) — unvalidated digest used to build blob paths. - `Sources/ContainerizationOCI/Content/LocalContent.swift` (`data()`, `decode()`) — read the entire target file into memory with no size bound, independent of the traversal (this is what makes the memory-exhaustion variant possible). - `Sources/Containerization/Image/ImageStore/ImageStore+Import.swift` (`fetch`, `getManifestContent`) — reachable from `container pull`/`run`/`create` on every image reference, not just a special import mode. **Not affected:** the `copyItem` cache-hit branch in `fetch()` cannot be used as a write primitive, for the reason described in Details above. ## Mitigations 1. U

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.

yourself before any code path that could use it as a filesystem path component.\r\n5. Redact digest-decode errors that reference a path outside the content store before sharing logs externally (bug reports, support tickets, CI artifacts). They can contain fragments of local file content.\r\n\r\n## Verifying whether you are affected\r\n\r\nSearch your `container pull`/`run`/`create` (or other `ContainerizationOCI`-consumer) logs for a decode or fetch error whose message contains a digest with a `..` sequence in it. Any such line reflects a prior traversal attempt via this defect, whether or not it happened to succeed:\r\n\r\n```\r\ngrep -rE 'digest.*\\.\\./' \u003cyour application's log files>\r\n```\r\n\r\n## References\r\n\r\n- Fix: apple/containerization#898, commit [5b5fbae7f0be5572484166fb8f4f2826a89bd922](https://github.com/apple/containerization/pull/898/commits/5b5fbae7f0be5572484166fb8f4f2826a89bd922)","vector":"","cvssVersion":"","severitySource":"github","cwes":[],"refs":["https://github.com/apple/containerization/security/advisories/GHSA-f689-h8m7-3jp2","https://github.com/apple/containerization"],"affected":[{"product":"apple","ecosystem":"Vendor","package":"github.com/apple/container","introduced":"","fixed":"1.3.0","lastAffected":""},{"product":"apple","ecosystem":"Vendor","package":"github.com/apple/containerization","introduced":"","fixed":"0.41.0","lastAffected":""}],"changes":[]},"related":[{"id":"GHSA-g3rx-2m58-rr63","cve":"","aliases":[],"summary":"Unpacking a crafted image layer with an invalid length extended-attribute name crashes the unpacking process","title":"Unpacking a crafted image layer with an invalid length extended-attribute name crashes the unpacking process","severity":"medium","score":null,"product":"apple","productLabel":"","products":["apple"],"fixed":"0.41.0, 1.3.0","fixFirst":"0.41.0","fixedN":2,"published":"2026-08-30","modified":"2026-08-30","withdrawn":"","url":"https://github.com/apple/containerization/security/advisories/GHSA-g3rx-2m58-rr63","foundAt":"2026-09-26 01:32:50"},{"id":"GHSA-697p-8837-37h3","cve":"","aliases":[],"summary":"Unpacking a crafted image layer with a long(invalid) file name crashes the unpacking process","title":"Unpacking a crafted image layer with a long(invalid) file name crashes the unpacking process","severity":"medium","score":null,"product":"apple","productLabel":"","products":["apple"],"fixed":"0.41.0, 1.3.0","fixFirst":"0.41.0","fixedN":2,"published":"2026-08-30","modified":"2026-08-30","withdrawn":"","url":"https://github.com/apple/containerization/security/advisories/GHSA-697p-8837-37h3","foundAt":"2026-09-26 01:32:50"},{"id":"GHSA-r3h2-rgqf-9hv9","cve":"","aliases":[],"summary":"Loading an OCI image layout can read host files through a symlink","title":"Loading an OCI image layout can read host files through a symlink","severity":"medium","score":null,"product":"apple","productLabel":"","products":["apple"],"fixed":"0.41.0, 1.3.0","fixFirst":"0.41.0","fixedN":2,"published":"2026-08-30","modified":"2026-08-30","withdrawn":"","url":"https://github.com/apple/containerization/security/advisories/GHSA-r3h2-rgqf-9hv9","foundAt":"2026-09-26 01:32:50"},{"id":"GHSA-mx96-5vvg-x2mg","cve":"CVE-2026-65388","aliases":[],"summary":"`RegistryClient` follows the `WWW-Authenticate` realm without validating its host or scheme","title":"`RegistryClient` follows the `WWW-Authenticate` realm without validating its host or scheme","severity":"medium","score":null,"product":"apple","productLabel":"","products":["apple"],"fixed":"0.41.0","fixFirst":"0.41.0","fixedN":1,"published":"2026-08-30","modified":"2026-08-30","withdrawn":"","url":"https://github.com/apple/containerization/security/advisories/GHSA-mx96-5vvg-x2mg","foundAt":"2026-09-26 01:32:50"},{"id":"GHSA-x7pf-2jmj-pgcq","cve":"","aliases":[],"summary":"Creating a container or executing a container process can delete files outside its bundle through an unchecked id","title":"## Impact An attacker who can choose a container or exec id may be able to...","severity":"high","score":null,"product":"apple","productLabel":"","products":["apple"],"fixed":"0.41.0","fixFirst":"0.41.0","fixedN":1,"published":"2026-08-30","modified":"2026-08-30","withdrawn":"","url":"https://github.com/apple/containerization/security/advisories/GHSA-x7pf-2jmj-pgcq","foundAt":"2026-09-26 01:32:50"},{"id":"CVE-2026-64705","cve":"CVE-2026-64705","aliases":[],"summary":"A buffer overflow was addressed with improved bounds checking. This issue is fixed in iOS 26.6 and iPadOS 26.6, macOS Sequoia 15.7.7, macOS Sonoma 14.8.7, macOS Tahoe 26.6.","title":"Apple iOS and iPadOS: buffer overflow","severity":"medium","score":5.5,"product":"apple","productLabel":"iOS and iPadOS","products":["apple"],"fixed":"iOS and iPadOS 26.6, macOS 14.8.7, macOS 15.7.7","fixFirst":"26.6","fixedN":3,"published":"2026-08-25","modified":"2026-09-14","withdrawn":"","url":"https://support.apple.com/en-us/127116","foundAt":"2026-09-26 01:52:08"}]}}