Unpacking a crafted image layer with an invalid length extended-attribute name crashes the unpacking process
MediumPublished Aug 30, 2026
## Impact An attacker who can supply a container image layer for a victim to unpack — via a malicious or compromised registry, a poisoned base image, or a pull request that changes which image gets fetched — can crash the process performing the unpack with no privileges beyond getting the victim to pull or run the crafted image reference. The trigger is a single tar entry carrying an extended-attribute (xattr) name longer than 255 bytes. When `ContainerizationEXT4` writes that entry into the ext4 rootfs it is building, an unchecked `UInt8` conversion of the name length traps and aborts the process. ## Details `EXT4.FileXattrsState.write()` writes each xattr entry's name length into a single on-disk byte via an unchecked `UInt8` conversion: ```swift // Sources/ContainerizationEXT4/EXT4+Xattrs.swift out.append(UInt8(attribute.name.count)) // traps if attribute.name.count > 255 ``` Swift's plain `UInt8.init(_:)` traps at runtime (aborting the process) when the source value does not fit in 8 bits. `attribute.name` is the xattr name taken from a tar entry's PAX extended header (`SCHILY.xattr.*`) with no length limit, after `ExtendedAttribute.compressName()` strips a known names...
Affected versions
| Package | Affected | Fixed in |
|---|---|---|
| apple/container Product | < 1.3.0 | 1.3.0 |
| apple/containerization Product | < 0.41.0 | 0.41.0 |
Details and references
## Impact An attacker who can supply a container image layer for a victim to unpack — via a malicious or compromised registry, a poisoned base image, or a pull request that changes which image gets fetched — can crash the process performing the unpack with no privileges beyond getting the victim to pull or run the crafted image reference. The trigger is a single tar entry carrying an extended-attribute (xattr) name longer than 255 bytes. When `ContainerizationEXT4` writes that entry into the ext4 rootfs it is building, an unchecked `UInt8` conversion of the name length traps and aborts the process. ## Details `EXT4.FileXattrsState.write()` writes each xattr entry's name length into a single on-disk byte via an unchecked `UInt8` conversion: ```swift // Sources/ContainerizationEXT4/EXT4+Xattrs.swift out.append(UInt8(attribute.name.count)) // traps if attribute.name.count > 255 ``` Swift's plain `UInt8.init(_:)` traps at runtime (aborting the process) when the source value does not fit in 8 bits. `attribute.name` is the xattr name taken from a tar entry's PAX extended header (`SCHILY.xattr.*`) with no length limit, after `ExtendedAttribute.compressName()` strips a known namespace prefix, it flows into `EXT4.Formatter.create(...)`, which calls `state.writeInlineAttributes(...)` / `state.writeBlockAttributes(...)`, both reaching the conversion above with no length validation along the path. 255 bytes is the maximum length of a single xattr name on a real Linux filesystem, so a layer produced by tarring an actual directory tree can never contain a name this long. The tar format itself imposes no such limit, so a deliberately crafted archive (one that was never the tar of a real filesystem) can contain one. ## Affected code - `EXT4.FileXattrsState.write()` in `Sources/ContainerizationEXT4/EXT4+Xattrs.swift` — fixed to reject a name whose length is `0` or exceeds `UInt8.max` (255), throwing `EXT4.FileXattrsState.Error.invalidXAttr` instead of trapping. - The reachable callers `writeInlineAttributes(...)` / `writeBlockAttributes(...)`, invoked from `EXT4.Formatter.create(...)`. Any consumer of `ContainerizationEXT4` that formats an ext4 filesystem from untrusted tar/OCI layer input reaches the same conversion. ## Mitigations 1. Upgrade to the version of `apple/containerization` containing the fix. 2. Do not unpack, pull, or run container images from untrusted sources — the registry, base image, or CI step that supplies a layer is part of the trust boundary, not just the resulting container's contents. 3. In CI/CD, avoid pulling or running an image reference that a pull request or other external input can influence on a runner shared with other jobs, since the crash disrupts every concurrent image operation on that host. ## Verifying whether you are affected Inspect a layer tar for any xattr name that would overflow the single length byte before unpacking it. The only reliable check enumerates xattrs through the same library the unpacker uses (`ContainerizationArchive`, a libarchive wrapper) and applies the same prefix compression (`EXT4.ExtendedAttribute.compressName`) that feeds the conversion. This catches both PAX xattr encodings libarchive recognizes (`SCHILY.xattr.` and `LIBARCHIVE.xattr.`, the latter with URL-encoded names) and measures the exact post-compression length that the vulnerable `UInt8(...)` sees. A plain `tarfile`/`tar` scan for long `SCHILY.xattr.` keys is only an approximation — it misses `LIBARCHIVE.xattr.`-encoded names and measures the raw, pre-compression length. Create a Swift project directory and populate it with the following files: ```swift // Sources/main.swift import Foundation import ContainerizationArchive import ContainerizationEXT4 for path in CommandLine.arguments.dropFirst() { let reader = try ArchiveReader(file: URL(fileURLWithPath: path)) // auto-detects gzip/zstd/etc. for (entry, _) in reader { for (rawName, _) in
- Severity from
- GitHub (reviewed advisory)
More Apple advisories
All Apple| Date | Advisory | Severity | Fixed in |
|---|---|---|---|
| Aug 30 | Unpacking a crafted image layer with a long(invalid) file name crashes the unpacking process | Medium | 0.41.0+1 more |
| Aug 30 | Loading an OCI image layout can read host files through a symlink | Medium | 0.41.0+1 more |
| Aug 30 | `RegistryClient` follows the `WWW-Authenticate` realm without validating its host or scheme | Medium | 0.41.0 |
| Aug 30 | Apple: path traversal | High | 0.41.0+1 more |
| Aug 30 | ## Impact An attacker who can choose a container or exec id may be able to... | High | 0.41.0 |
| Aug 25 | Apple iOS and iPadOS: buffer overflow | Medium5.5 | 26.6+2 more |