Bug 2522941 (CVE-2026-101295)
| Summary: | CVE-2026-101295 oc-mirror: oc-mirror: Path traversal / arbitrary file write in operator catalog image extraction | ||
|---|---|---|---|
| Product: | [Other] Security Response | Reporter: | OSIDB Bzimport <bzimport> |
| Component: | vulnerability | Assignee: | Product Security <prodsec-ir-bot> |
| Status: | NEW --- | QA Contact: | |
| Severity: | medium | Docs Contact: | |
| Priority: | medium | ||
| Version: | unspecified | CC: | akhatavk, aos-team-art-private, asdas, dpaolell, jdelft, jupierce, lgamliel, lgarciaa, mbiarnes, ppalepu, ppostler, prdhamdh, sbratsla, security-response-team, sghai, sidsharm, suppawar, vlaad |
| Target Milestone: | --- | Keywords: | Security |
| Target Release: | --- | ||
| Hardware: | All | ||
| OS: | Linux | ||
| Whiteboard: | |||
| Fixed In Version: | Doc Type: | --- | |
| Doc Text: |
Path traversal / arbitrary file write in oc-mirror's operator catalog image extraction. When mirroring operator catalogs using either the legacy v1 path (--v1) or the OCI feature path (--use-oci-feature), oc-mirror extracts tar entries from catalog image layers without validating that file paths resolve within the intended destination directory.
|
Story Points: | --- |
| Clone Of: | Environment: | ||
| Last Closed: | Type: | --- | |
| Regression: | --- | Mount Type: | --- |
| Documentation: | --- | CRM: | |
| Verified Versions: | Category: | --- | |
| oVirt Team: | --- | RHEL 7.3 requirements from Atomic Host: | |
| Cloudforms Team: | --- | Target Upstream Version: | |
| Embargoed: | |||
## Zip-slip and symlink traversal in v1 catalog-image extractors **CWEs:** CWE-22, CWE-59 **CVSS:** 7.3 (CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:L) **Component:** openshift-4.18-payload/oc-mirror__release-4.18 ### Description The legacy v1 engine extracts the full operator-catalog image filesystem (catalog_images.go writeToFs) and the FBC configs directory (fbc_operators.go) by iterating tar entries from mutate.Extract(img). In catalog_images.go the destination is computed as descriptor := filepath.Join(destFolder, header.Name) for TypeDir and TypeReg with no traversal guard, and for TypeSymlink it stores symLinks[descriptor] = filepath.Join(destFolder, header.Linkname), letting both the link path and target escape destFolder. fbc_operators.go gates on strings.HasPrefix(header.Name, configsPrefix) but a name such as 'configs/../../etc/x' still has that prefix after which targetFileName := filepath.Join(extractedImageDir, header.Name) escapes. As with FIND-001 the tar stream is the layer content of a catalog image the user asked to mirror. ### Affected Locations - `:` - `:` ### Evidence **pkg/cli/mirror/catalog_images.go:680-716 — unsanitised Name and Linkname** ```go // catalog_images.go descriptor := filepath.Join(destFolder, header.Name) ... f, err := os.OpenFile(descriptor, os.O_CREATE|os.O_RDWR, os.FileMode(header.Mode)|0755) ... } else if header.Typeflag == tar.TypeSymlink { symLinks[descriptor] = filepath.Join(destFolder, header.Linkname) } ``` **pkg/cli/mirror/fbc_operators.go:359-378 — HasPrefix does not block 'configs/../..'** ```go if !strings.HasPrefix(header.Name, configsPrefix) || header.FileInfo().IsDir() { continue } ... targetFileName := filepath.Join(extractedImageDir, header.Name) ... f, err := os.Create(targetFileName) ``` ### Attack Pattern Compromised or malicious catalog image mirrored with v1 oc-mirror yields arbitrary file create/overwrite (and arbitrary symlink placement) under the privileges of the mirror operator. --- *Source: Ex-Wing security assessment, finding FIND-002*