Attack ChainAIDerived
Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain
-
AccessGain MITM position or operate malicious registry
-
DeliveryServe forged manifest with spoofed Docker-Content-Digest header
-
ExploitClient skips digest verification and accepts content
-
ExecutionPull-through proxy caches substituted manifest
-
ImpactDownstream clients pull attacker-chosen content
Vulnerability Assessment
| Weakness |
CWE
OWASP Top 10:2025
A08:2025 - Software or Data Integrity Failures
ASVS 5.0
V15 - Secure Coding and Architecture Integrity verification
|
| Exploitation Conditions | Exploitation requires the attacker to control the manifest HTTP response for a digest-pinned request - achieved either by operating a malicious or compromised registry the victim pulls from, or by holding a man-in-the-middle position on the registry connection (e.g., TLS interception). The vulnerable path is registry/client manifests.Get() when the manifest is fetched by digest (byDigest, i.e., digestOrTag empty); the attacker forges the Docker-Content-Digest header to match the requested digest while serving different bytes. Impact is amplified when the bundled pull-through proxy (registry/proxy/proxymanifeststore.go) is deployed, since it caches and re-serves the substituted manifest to downstream clients. Affected: distribution prior to 3.1.2. Limiting factors: the attacker needs a privileged network position or a malicious registry (reflected as AC:H), there is no availability or confidentiality impact, and clients that fetch by tag rather than by digest are outside this specific verification path. |
| Impact | This is a genuine but conditional supply-chain integrity flaw rather than a drop-everything emergency. The CVSS 3.1 base score of 6.8 (vector AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:H/A:N) correctly captures the shape: network-reachable and unauthenticated, but with HIGH attack complexity because exploitation requires the attacker to control the manifest response - either by operating a malicious/compromised registry or by holding a man-in-the-middle position on the registry connection. There is no confidentiality or availability impact (C:N/A:N); the entire harm is integrity (I:H), and the scope change (S:C) reflects that the bundled pull-through proxy can cache and re-serve the substituted manifest to other downstream clients. On exploitation signals: no EPSS score was provided in the input, the CVE is NOT in CISA KEV, and no public exploit code was referenced, so exploitation status is 'no public exploit identified at time of analysis.' The real-world significance is that digest pinning is a security control users explicitly rely on for content-addressed integrity, and this bug silently voids that guarantee (CWE-354) - but the AC:H prerequisite (privileged network position or malicious registry) and absence of any exploitation evidence place this below internet-facing RCE-class issues in priority. Note one inconsistency to verify: the input tag 'Information Disclosure' conflicts with the CVSS (C:N, I:H) and CWE-354, which describe an integrity/tampering issue, not disclosure. |
| Exploit ScenarioDerived | A victim client (or a pull-through proxy built on distribution < 3.1.2) requests a manifest pinned by digest, expecting content-addressed integrity. An attacker operating a malicious registry or sitting in a man-in-the-middle position returns an attacker-chosen manifest while forging the Docker-Content-Digest header to claim the requested digest; because manifests.Get() never hashes the body against the pinned digest, the forged content is accepted. No public exploit code was identified, but the flaw is trivially demonstrable given control of the response, and the bundled proxy will then cache and re-serve the poisoned manifest to other clients. |
Get an e-mail when this CVE is exploited, patched or re-scored. Free account.
Alert meAnalysisAIv1 – Oct 13, 2026
Manifest and blob digest verification bypass in the CNCF Distribution registry client (all versions prior to 3.1.2) lets an attacker who controls the registry HTTP response - by operating a malicious or compromised registry, or by holding a TLS-intercepting man-in-the-middle position - substitute attacker-chosen manifest content even when the caller pinned the request by digest, with the forged Docker-Content-Digest header presented as the requested value. The flaw is unauthenticated from the client's perspective (CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:H/A:N, 6.8) and scopes out of the client because the bundled pull-through proxy (registry/proxy/proxymanifeststore.go) can cache and re-serve the substituted manifest to downstream consumers, making this a conditional supply-chain integrity issue rather than a drop-everything emergency. No public exploit code and no confirmed active exploitation were identified at time of analysis; the vendor-released patch is version 3.1.2.
RemediationAI
Upgrade Distribution to version 3.1.2, which is the vendor-released patch and the first version that hashes digest-pinned manifest and blob responses against the requested digest, rejects unsupported digest algorithms via dgst.Validate() instead of panicking, and explicitly documents that the streaming Open() API provides no integrity guarantee; the change is captured in commit 960439b09f342cdeb8f1c0e18e8c7349bdcfbf80 with the advisory at https://github.com/distribution/distribution/security/advisories/GHSA-685w-q87j-wqw3. If an immediate upgrade is not possible, the primary compensating control is to eliminate the attacker's ability to influence the registry response: enforce TLS with strict certificate validation and pinning against registry endpoints so a MITM cannot serve forged manifests - with the trade-off that interception proxies, custom CA bundles, or TLS-terminating middleboxes that are currently in use will break, and any endpoint that cannot be pinned remains exposed. Additionally, avoid operating pull-through proxy caches against registries you do not control, or disable/limit the proxy's manifest caching, since the proxy is what re-serves substituted content to otherwise-isolated downstream clients; the trade-off is added upstream bandwidth and latency for image pulls. Where image provenance matters more than pull convenience, require signature verification (e.g. cosign/Notary) before deployment, accepting that unsigned legacy images will be blocked. Note that switching to tag-based pulls does not fix the issue - it simply sidesteps the digest-verification path while relying on a weaker mutable reference - and that pre-3.1.2 callers of the blobs streaming API receive no digest verification for streamed content.
Affected VersionsENISA
Affected Packages
Source: OSV (Open Source Vulnerabilities)
Affects your stack
Affects 3 packages in go, euvd
Checking this CVE against your own stacks and servers is part of the Basic plan and up.
Technical ContextAI · show details
Container registries are content-addressed: clients request a manifest or blob by digest and rely on the digest as the integrity guarantee. Under CWE-354 (Improper Validation of Integrity Check Value), registry/client.(*manifests).Get() in Distribution fetched a manifest for a digest-pinned request and handed the body to distribution.UnmarshalManifest without re-hashing the received bytes against the requested digest - the server-supplied Docker-Content-Digest header was treated as authoritative even though a malicious registry or MITM can forge it while returning arbitrary bytes. The vulnerable path is reached only when the manifest is requested by digest (byDigest, i.e. digestOrTag is empty); tag-based fetches are outside this verification path. The bundled pull-through proxy in registry/proxy/proxymanifeststore.go amplifies impact because it caches and re-serves the substituted manifest to downstream clients, propagating the poison without requiring an attacker position against each consumer. The upstream fix (commit 960439b09f342cdeb8f1c0e18e8c7349bdcfbf80, released in v3.1.2) adds explicit verifier-based hashing for digest-pinned manifest reads and for the blobs.Get() path, calls dgst.Validate() first so an unsupported/unavailable digest algorithm fails closed instead of panicking the verifier, and documents that the streaming blobs.Open() API is intentionally unverified since a content digest cannot be checked without reading the full body. Regression tests (TestManifestFetchByDigestVerifies, TestBlobFetchByDigestVerifies, TestBlobGetUnsupportedDigestAlgorithm) confirm that forged Docker-Content-Digest headers and mismatched bodies are now rejected.
Know when Distribution gets its next vulnerability
- Watch products and get an email when something new is published
- Check this CVE against your own stack and servers
- Exploit and PoC references, threat intelligence from 22 sources
No credit card · 7-day full trial
Severity by source
AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:H/A:N
Network-reachable and unauthenticated (AV:N/PR:N/UI:N) but requires MITM or malicious registry control (AC:H); integrity-only (I:H, C:N/A:N); proxy re-serving poisoned content to other clients justifies S:C.
Primary rating from Vendor (GitHub_M).
CVSS VectorVendor: GitHub_M
Lifecycle Timeline
2DescriptionCVE.org
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.
Threat Intelligence Overview
How this decision was reached
The engine reads each signal below and applies a fixed list of rules from top to bottom. The first rule that matches sets the recommended action – like a statement, every line is shown.
EUVD-2026-99225
GHSA-685w-q87j-wqw3
NVD
CVE.org
EPSS
Exploit-DB