chore(deps): update module oras.land/oras-go/v2 to v2.6.2 [security] - abandoned - #525
chore(deps): update module oras.land/oras-go/v2 to v2.6.2 [security] - abandoned#525renovate[bot] wants to merge 1 commit into
Conversation
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
|
Hi @renovate[bot]. Thanks for your PR. I'm waiting for a cert-manager member to verify that this patch is reasonable to test. If it is, they should reply with Regular contributors should join the org to skip this step. Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. DetailsInstructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. |
Signed-off-by: Renovate Bot <renovate-bot@users.noreply.github.com>
5187986 to
134bc36
Compare
Autoclosing SkippedThis PR has been flagged for autoclosing. However, it is being skipped due to the branch being already modified. Please close/delete it manually or report a bug if you think this is in error. |
Edited/Blocked NotificationRenovate will not automatically rebase this PR, because it does not recognize the last commit author and assumes somebody else may have edited the PR. You can manually request rebase by checking the rebase/retry box above. |
This PR contains the following updates:
v2.6.1→v2.6.2oras-gotar extraction: Hardlink entry with relative Linkname escapes extract dir via process CWD resolutionCVE-2026-50163 / GHSA-fxhp-mv3v-67qp
More information
Details
Root cause
The tar-extraction helper
ensureLinkPathatcontent/file/utils.go:262-275validates that a hardlink's target resolves inside the extract base, but then returns the original unresolvedtargetstring back to the caller:The caller for
TypeLinkhardlinks then does:os.Link(oldname, newname)wraps thelink(2)system call. From thelink(2)man page:So when
target(i.e.,header.Linkname) is a relative path,os.Linkresolves it against the process's current working directory, not againstfilepath.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:payload.tar.gz/README.txt.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 tellsoras-goto auto-extract).When a victim runs
oras pull(or any Go code usingcontent.File), the extraction:payload.tar.gz/evil_cwd_link— passes.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.target = "victim.secret"(NOTpath).os.Link("victim.secret", "<extract_base>/payload.tar.gz/evil_cwd_link").link(2)resolves relativeoldname="victim.secret"against process CWD → creates a hardlink inside the extract tree pointing to<invoker_CWD>/victim.secret.The resulting hardlink and the CWD file share an inode — reading one reads the other; writing to one writes to the other.
Proof of Concept
Tested on Ubuntu 24.04.4 LTS with
orasCLI v1.3.0 (SHA-256040e140304b7dbdd9b40dacd798e2303cea44ad84eeb210750afdf15f1dcf8b4, downloaded from https://github.com/oras-project/oras/releases/download/v1.3.0/oras_1.3.0_linux_amd64.tar.gz).Reproduction script (standalone, ~50 lines) attached. Summary of key steps:
Observed output:
A library-level regression test is also provided (
poc_test.go) that drops intocontent/file/utils_test.goand runs viago test ./content/file/... -run TestPoC— output shows identical inode match for consumers of the library API.Impact
Primary: arbitrary-CWD-file read primitive. An attacker-controlled OCI artifact, when pulled by a victim using the
orasCLI or any Go program usingoras-go/v2/content/file, can create a hardlink inside the victim's extract tree pointing to an arbitrary file in the victim's process CWD (that the invoker UID is permitted to read). Reading the extract-tree hardlink yields that file's contents verbatim.Secondary: inode-sharing tampering primitive. Any tool that later modifies the extract-tree hardlink (write, chmod, truncate, etc.) modifies the CWD file through the shared inode. This violates the "writes inside the extract dir are confined" invariant that downstream tooling (CI systems, container-image builders, artifact scanners) typically depends on.
High-severity chains:
oras pullruns from a project workspace containing secrets/credentials (.env,.git/config, service-account tokens). The pulled artifact can hardlink those secrets into a location later archived/mounted/published.oras-goto fetch artifacts; their CWD is typically/or/root— very sensitive.oras-goto fetch and re-serve artifacts; each proxy process has a CWD with configuration, keys, or per-tenant state.Not affected:
oras push(tarball creation side):tarDirectoryin the same file explicitly skips hardlink generation (line 65 comment:"We don't support hard links and treat it as regular files"), so pushed content cannot trigger this on the server.TypeSymlink):os.Symlinkstores the target string verbatim and does not CWD-resolve at creation time. The currentensureLinkPathreturn-of-targetis correct for symlinks (the existing validation correctly models the symlink-follow path).Attack-surface boundary (
fs.protected_hardlinks)On Linux with
fs.protected_hardlinks=1(default on modern distros),link(2)additionally requires the linking user to have READ + WRITE permission on the source file (permay_linkat()in the kernel). Verified on Ubuntu 24.04: as non-root,ln /etc/passwd /tmp/xreturnsEPERM, and the same via the oras PoC path returnslink passwd /tmp/.../evil_passwd: operation not permitted.So the attacker cannot use this bug to read arbitrary root-owned files (e.g.,
/etc/shadow) when the victim invokesoras pullas a regular user. The attack surface depends on the invocation context:oras pullrun by a regular user.env,.git/config,.aws/credentials,~/.ssh/config, project-local secrets, CI workspace files.oras pullrun as root (systemd withoutUser=, container entrypoint default root, Kubernetes operator)/etc/shadow,/root/.ssh/id_rsa, bind-mounted host paths, service private keys.The user-context attack surface alone is sufficient for supply-chain-grade impact: CI pipelines and developer machines routinely hold API keys, signing keys, and cloud credentials in user-owned files in the working directory. The root-context escalation makes the bug Critical in mainstream Kubernetes/GitOps tooling where oras-go is adopted for artifact distribution.
Proposed fix
Change
ensureLinkPathto expose both the verbatim target (for symlinks) and the resolved absolute path (for hardlinks); have theTypeLinkcase use the resolved path.Regression test to add:
Extend
Test_extractTarDirectory_HardLinkwith a third sub-test that:t.TempDir()(or an explicitlyos.Chdir-entered directory) with a known name, e.g.sentinel.txt.TypeLinkentry withLinkname: "sentinel.txt"(relative).extractTarDirectoryreturned an error, OR the resulting hardlink's inode does NOT match the sentinel's inode.Severity
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:L/A:NReferences
This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).
Configuration
📅 Schedule: (in timezone Europe/London)
🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR was generated by Mend Renovate. View the repository job log.