GitHub Advisoryadvisory · Go

GHSA-f2g3-hh2r-cwgc Distribution: stale blob access resurrection via repo-scoped redis descriptor cache invalidation

HIGH Published 2026-04-06 Modified 2026-04-06 Official page ↗
Aliases
CVE-2026-35172
Ecosystem
Go
Packages
github.com/distribution/distribution/v3, github.com/distribution/distribution
Severity
High
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Weaknesses
CWE-284
Reviewed
2026-04-06

Affected packages

• Go github.com/distribution/distribution/v3: < 3.1.0 → fixed in 3.1.0 • Go github.com/distribution/distribution: <= 2.8.3 (no fix yet)

Description

summary: distribution can restore read access in `repo a` after an explicit delete when `storage.cache.blobdescriptor: redis` and `storage.delete.enabled: true` are both enabled. the delete path clears the shared digest descriptor but leaves stale repo-scoped membership behind, so a later `Stat` or `Get` from `repo b` repopulates the shared descriptor and makes the deleted blob readable from `repo a` again. Severity HIGH justification: this is a repo-local authorization bypass after explicit delete, with concrete confidentiality impact and no requirement for write access after the delete event. CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N (7.5). CWE-284. affected version • repository: https://github.com/distribution/distribution • commit: ab67ffa0bda3712991194841d0fde727464feeb9 • affected versions: \upstream.Clear->repositoryScopedRedisBlobDescriptorService.Stat [PROOF_MARKER]: repo_a_access_restored=true repo_a_delete_miss=true repo_b_peer_warm=true [IMPACT_MARKER]: repo_a_post_delete_read=true confidentiality_boundary_broken=true ``` control: ```bash unzip -q -o poc.zip -d poc cd poc make control ``` expected control output: ```text [CALLSITE_HIT]: repositoryScopedRedisBlobDescriptorService.Clear->repositoryScopedRedisBlobDescriptorService.Stat [NC_MARKER]: repo_a_access_restored=false repo_b_peer_warm=true ``` expected vs actual • expected: after `repo a` deletes its blob link, later reads from `repo a` should keep returning `blob unknown` even if `repo b` still references the same digest and warms cache state. • actual: `repo a` first returns `blob unknown`, then `repo b` repopulates the shared descriptor, and `repo a` serves the deleted digest again through stale repo-scoped redis membership. impact the confirmed impact is repository-local confidentiality failure after explicit delete. an operator can remove sensitive content from `repo a`, observe revocation working immediately after the delete, and still have the same content become readable from `repo a` again as soon as `repo b` refreshes the shared descriptor for that digest. this is not a claim about global blob deletion. the bounded claim is that repository-local revocation fails, which breaks the expectation that deleting a blob link from one repository prevents further reads from that repository. remediation the safest fix is to make redis invalidation revoke repo-scoped state together with the backend link deletion. in practice that means removing the digest from the repository membership set, deleting the repo-scoped descriptor hash, and keeping that cleanup atomic enough that peer-repository warming cannot restore access in the repository that already deleted its link. poc.zip PR_DESCRIPTION.md attack_scenario.md

Related

Alias · CVE (1)

  • CVE-2026-35172 Distribution is a toolkit to pack, ship, store, and deliver container content. vulnerability

Weakness · CWE (1)

  • CWE-284 Improper Access Control weakness

References