oras.land/oras-go/v2

CVE-2026-50163

CVE-2026-50163 is a high-severity path traversal vulnerability in oras.land/oras-go/v2 (go), affecting versions <= 2.6.1. No fixed version is listed yet.

Key facts
CVSS score
7.1
High
Attack vector
Network
Issuing authority
GitHub Advisory Database
Affected package
oras.land/oras-go/v2
Fixed in
Not available
Disclosed
2026

Summary

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: The caller for TypeLink hardlinks then does: 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/evilcwdlink, 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: Validates payload.tar.gz/evilcwdlink, passes. Calls ensureLinkPath(dirPath, "payload.tar.gz", filePath, "victim.secret"): path = filepath.Join(filepath.Dir(filePath), "victim.secret") = <extractbase>/payload.tar.gz/victim.secret → inside base → validation passes. Returns target = "victim.secret" (NOT path). Calls os.Link("victim.secret", "<extractbase>/payload.tar.gz/evilcwdlink"). link(2) resolves relative oldname="victim.secret" against process CWD → creates a hardlink inside the extract tree pointing to <invokerCWD>/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 oras CLI v1.3.0 (SHA-256 040e140304b7dbdd9b40dacd798e2303cea44ad84eeb210750afdf15f1dcf8b4, downloaded from <https://github.com/oras-project/oras/releases/download/v1.3.0/oras1.3.0linuxamd64.tar.gz>). Reproduction script (standalone, ~50 lines) attached. Summary of key steps: Observed output: A library-level regression test is also provided (poctest.go) that drops into content/file/utilstest.go and runs via go 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 oras CLI or any Go program using oras-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: CI pipelines where oras pull runs 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. Container orchestration where the extract dir is bind-mounted into a lower-trust container while the pull-invoker's CWD is higher-trust. Hardlinks created in the extract tree expose invoker-CWD files across the trust boundary. Kubernetes operators / Flux source-controller using oras-go to fetch artifacts; their CWD is typically / or /root, very sensitive. Multi-tenant registry proxies that use oras-go to 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): tarDirectory in 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. Symlink extraction path (TypeSymlink): os.Symlink stores the target string verbatim and does not CWD-resolve at creation time. The current ensureLinkPath return-of-target is correct for symlinks (the existing validation correctly models the symlink-follow path). Attack-surface boundary (fs.protectedhardlinks) On Linux with fs.protectedhardlinks=1 (default on modern distros), link(2) additionally requires the linking user to have READ + WRITE permission on the source file (per maylinkat() in the kernel). Verified on Ubuntu 24.04: as non-root, ln /etc/passwd /tmp/x returns EPERM, and the same via the oras PoC path returns link passwd /tmp/.../evilpasswd: operation not permitted. So the attacker cannot use this bug to read arbitrary root-owned files (e.g., /etc/shadow) when the victim invokes oras pull as a regular user. The attack surface depends on the invocation context: | Invocation context | Reachable file classes | |---|---| | oras pull run by a regular user | Any file the user OWNS or has write access to in the process CWD: .env, .git/config, .aws/credentials, ~/.ssh/config, project-local secrets, CI workspace files. | | oras pull run as root (systemd without User=, container entrypoint default root, Kubernetes operator) | Every file on the host filesystem. /etc/shadow, /root/.ssh/idrsa, 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 ensureLinkPath to expose both the verbatim target (for symlinks) and the resolved absolute path (for hardlinks); have the TypeLink case use the resolved path. Regression test to add: Extend TestextractTarDirectory_HardLink with a third sub-test that: Creates a sentinel file in the test's t.TempDir() (or an explicitly os.Chdir-entered directory) with a known name, e.g. sentinel.txt. Builds a tarball containing a TypeLink entry with Linkname: "sentinel.txt" (relative). Extracts. Asserts either extractTarDirectory returned an error, OR the resulting hardlink's inode does NOT match the sentinel's inode.

Impact

What is path traversal?

Input manipulates file paths to reach files outside the intended directory, such as configuration or credential files. Typical impact: unauthorized file read or write outside the intended directory.

Severity and exposure

CVE-2026-50163 has a CVSS score of 7.1 (High). The vector is network-reachable, no privileges required, and user interaction required. A CVSS score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether this affects your application depends on whether the vulnerable code is present and reachable in your environment.

No fixed version is listed yet, so configuration controls and monitoring matter more in the interim.

Affected versions

go

  • oras.land/oras-go/v2 (<= 2.6.1)

Security releases

Not available
Kodem intelligence

Severity tells you how bad this could be in the worst case. It does not tell you whether you are exposed. Exploitability and impact are functions of runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A vulnerable package can sit in your dependency tree and never run.

Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter instead of chasing every advisory.

Kodem's runtime-powered SCA identifies whether CVE-2026-50163 is reachable in your applications. Explore open-source security for your team.

See if CVE-2026-50163 is reachable in your applications. Get a demo

Already deployed Kodem? See CVE-2026-50163 in your environment

Remediation advice

No fixed version is listed for CVE-2026-50163 yet.

In the interim: Resolve the canonical path after applying any user-supplied input, and verify it remains within the intended directory before accessing it.

Kodem Kai can prioritize this vulnerability in your dependency tree and generate a fix recommendation.

Frequently asked questions about CVE-2026-50163

What is CVE-2026-50163?

CVE-2026-50163 is a high-severity path traversal vulnerability in oras.land/oras-go/v2 (go), affecting versions <= 2.6.1. No fixed version is listed yet. Input manipulates file paths to reach files outside the intended directory, such as configuration or credential files.

How severe is CVE-2026-50163?

CVE-2026-50163 has a CVSS score of 7.1 (High). This score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether it represents real risk in your environment depends on whether the vulnerable code is present and reachable.

Which versions of oras.land/oras-go/v2 are affected by CVE-2026-50163?

oras.land/oras-go/v2 (go) versions <= 2.6.1 is affected.

Is there a fix for CVE-2026-50163?

No fixed version is listed for CVE-2026-50163 yet. Monitor the advisory for updates and apply mitigations in the interim.

Is CVE-2026-50163 exploitable, and should I be worried?

Whether CVE-2026-50163 is exploitable in your environment depends on whether the vulnerable code is present and reachable. A CVSS score is a worst-case rating; it does not account for your specific deployment, configuration, or usage patterns. Kodem, an Intelligent Application Security platform, uses runtime intelligence to show which vulnerabilities actually execute in production, so you can focus on the ones that represent real risk. Get a demo

What actually determines whether CVE-2026-50163 is exploitable, and how bad it is?

Exploitability and impact are not fixed properties of a CVE. They depend on runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A high CVSS score on a dependency that never runs is not the same as real risk. Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter.

How do I fix CVE-2026-50163?

No fixed version is listed yet. In the interim: Resolve the canonical path after applying any user-supplied input, and verify it remains within the intended directory before accessing it.

Stop the waste.
Protect your environment with Kodem.