CSIRTS // UNIFIED SECURITY ADVISORY FEEDSYS ● ONLINE · POWERED BY INTELFUSIONS.COM

GHSA-fxhp-mv3v-67qp: `oras-go` tar extraction: Hardlink entry with relative Linkname escapes extract dir via process CWD resolution

highCVSS 7.1CVE-2026-50163
Root cause The tar-extraction helper ensureLinkPath at content/file/utils.go:262-275 validates that a hardlink's target resolves inside the extract base, but then returns the original unresolved target string back to the caller: func ensureLinkPath(baseAbs, baseRel, link, target string) (string, error) { path := target if !filepath.IsAbs(target) { path = filepath.Join(filepath.Dir(link), target) // resolved FOR VALIDATION } if _, err := resolveRelToBase(baseAbs, baseRel, path); err != nil { return "", err } return target, nil // <-- returns the ORIGINAL target, not the validated path } The caller for TypeLink hardlinks then does: case tar.TypeLink: var target string if target, err = ensureLinkPath(dirPath, dirName, filePath, header.Linkname); err == nil { err = os.Link(target, filePath) } os.Link(oldname, newname) wraps the link(2) system call. From the link(2) man page: oldpath and newpath are interpreted relative to the current working directory of the calling process. So when target (i.e., header.Linkname) is a relative path, os.Link resolves it against the process's current working directory, not against filepath.Dir(link) as the validation assumed. Attack An attacker who controls an OCI-compliant registry (or any artifact source the victim consumes via oras pull) crafts a tarball layer with: - A regular file: payload.tar.gz/README.txt. - A hardlink entry: Typeflag=TypeLink, Name=payload.tar.gz/evil_cwd_link, Linkname="victim.secret" (relative). and marks the layer descriptor with io.deis.oras.content.unpack: "true" (a standard annotation that tells oras-go to auto-extract). When a victim runs oras pull (or any Go code using content.File), the extraction: 1. Validates payload.tar.gz/evil_cwd_link — passes. 2. Calls ensureLinkPath(dirPath, "payload.tar.gz", filePath, "victim.secret"): - path = filepath.Join(filepath.Dir(filePath), "victim.secret") = <extract_base>/payload.tar.gz/victim.secret → inside base → validation passes. - Returns target = "vic

Details

Source
GitHub Security Advisories (INTL · database · site)
Severity
high — CVSS 7.1
Published
2026-07-01
Last updated
2026-08-04
Exploitation
Not in CISA KEV at last sync

Original advisory: https://github.com/advisories/GHSA-fxhp-mv3v-67qp

Exploitation outlook

EPSS (FIRST.org) estimates each CVE’s probability of exploitation in the next 30 days — here is the CSIRTS.com read on those numbers.

Referenced CVEs

CVECSIRTS overviewExternal
CVE-2026-50163coverage & exploitation statusNVD · CVE.org

Same CVEs, other sources

How other CERTs, PSIRTs and databases cover the vulnerabilities in this advisory.

More from GitHub Security Advisories