Skip to main content

Distribution Registry CVE-2026-35172

| EUVDEUVD-2026-19446 HIGH
Improper Access Control (CWE-284)
2026-04-06 https://github.com/distribution/distribution GHSA-f2g3-hh2r-cwgc
7.5
CVSS 3.1 · Vendor: https://github.com/distribution/distribution
View

Attack ChainAIDerived

Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain

  1. Access
    Configure registry with Redis cache + deletion enabled
  2. Delivery
    Share digest across repo A and repo B
  3. Exploit
    Admin deletes blob from repo A
  4. Execution
    Attacker triggers repo B access to repopulate shared descriptor
  5. Persist
    Attacker reads deleted blob from repo A via stale membership
  6. Impact
    Restored confidentiality breach

Vulnerability Assessment

Weakness
CWE
OWASP Top 10:2025
A01:2025 - Broken Access Control
ASVS 5.0
V8 - Authorization Access control enforcement
MITRE ATT&CK

1 technique across 1 tactic: Defense Evasion

The technique list with ATT&CK links and the kill-chain view is part of the Basic plan and up.

Exploitation Conditions

Requires BOTH non-default configuration settings enabled simultaneously: storage.cache.blobdescriptor: redis (enables Redis-backed blob descriptor caching instead of default in-memory or no caching) AND storage.delete.enabled: true (enables blob deletion API, often disabled in production to prevent accidental data loss). Additionally requires multi-repository blob sharing-the same content-addressable digest must exist in at least two repositories (repo A where deletion occurs and repo B that repopulates cache). Exploitation depends on specific operational timing: an administrator must delete a blob from repo A, then a user (can be unauthenticated per PR:N) must access the same digest from repo B before Redis cache entry expires, followed by a second access to the deleted digest from repo A. Default Distribution deployments using filesystem-backed caching or with blob deletion disabled are not vulnerable. The vulnerability affects only repository-scoped read access, not global blob deletion or other repository isolation boundaries.

Impact

CVSS 7.5 (HIGH) reflects maximum confidentiality impact (C:H) with network reachability (AV:N), low complexity (AC:L), and no authentication barrier (PR:N/UI:N). However, real-world risk is conditional and significantly lower than the raw score suggests. EPSS score of 0.03% (9th percentile) indicates minimal observed exploitation interest despite public POC availability since the GitHub advisory disclosure. SSVC framework confirms POC exists and the attack is automatable with partial technical impact, but exploitation status remains at POC-only-no evidence of active targeting. The critical limiting factor: deployment requires BOTH storage.cache.blobdescriptor: redis AND storage.delete.enabled: true, which is not the default Distribution configuration. Most production registries either disable blob deletion entirely or use filesystem-backed descriptor caching. The attack also requires multi-repository blob sharing (same digest in repo A and repo B), a specific operational sequence (delete from A, then access from B), and provides only read access to previously-accessible content-not privilege escalation or arbitrary data exfiltration. The confidentiality impact is real for environments that rely on repository-local deletion for compliance or secret rotation, but the narrow deployment profile explains the low EPSS score. This is a high-CVSS, low-real-world-prevalence issue: prioritize for registries using Redis caching with deletion enabled, but most deployments are not exposed. Verified patch availability in 3.1.0 reduces urgency further.

Exploit ScenarioDerived

An attacker identifies a Distribution registry running with Redis blob descriptor caching and deletion enabled. The target registry hosts both a public repository (repo B) and a private repository (repo A) that share a common base layer digest. When an administrator deletes sensitive content from repo A (e.g., a layer containing leaked credentials), the attacker observes the deletion succeed and repo A returns 404 for the blob. The attacker then triggers a pull from repo B, which legitimately contains the same digest. This pull operation causes repo B to repopulate the shared Redis descriptor cache. The attacker immediately requests the previously deleted digest from repo A again and successfully retrieves the content that was just deleted, bypassing repository-local access controls. The attack requires no authentication (PR:N), works over the network (AV:N), and is deterministic (AC:L) given the configuration prerequisites. POC code demonstrating the exact sequence is publicly available in poc.zip.

This Week Schedule remediation this week. Why: HIGH severity (CVSS 7.0-8.9).
Patch available 0.0% exploitation probability (EPSS)

Get an e-mail when this CVE is exploited, patched or re-scored. Free account.

Alert me

AnalysisAIv2 – Apr 28, 2026

Distribution container registry versions ≤3.0.x and ≤2.8.x restore read access to explicitly deleted blobs when Redis blob descriptor caching and storage deletion are both enabled. After an administrator deletes a blob from repository A, the deletion briefly succeeds, but when repository B later accesses the same digest, it repopulates the shared Redis descriptor cache. Repository A then regains unauthorized read access to the deleted blob because stale repository-scoped membership metadata was never invalidated from Redis. This authorization bypass defeats repository-local content revocation with concrete confidentiality impact. CVSS 7.5 (HIGH) with network attack vector, low complexity, and no authentication required. EPSS exploitation probability is very low (0.03%, 9th percentile), suggesting limited real-world targeting despite public POC availability. Vendor-released patch confirms the issue and provides a fix in version 3.1.0.

Earlier versions of this analysis (1)
v1 Apr 06, 2026 - 19:00 CVSS 7.5

Repository-scoped authorization bypass in distribution container registry allows restored read access to explicitly deleted blobs when Redis caching is enabled. Affects distribution/distribution v2.8.x and v3.0.x when both storage.cache.blobdescriptor: redis and storage.delete.enabled: true are configured. Unauthenticated remote attackers can retrieve sensitive content deleted from repo A after repo B repopulates the shared Redis descriptor cache, exposing confidential data that operators believed was permanently revoked. CVSS 7.5 (High). Publicly available exploit code exists with deterministic PoC demonstrating the state-machine race condition. EPSS data not provided, but the low attack complexity (AC:L) and no privilege requirement (PR:N) indicate straightforward exploitation once the vulnerable configuration is identified.

RemediationAI

Upgrade to Distribution 3.1.0 or later, which includes the vendor-released patch (commit 078b0783f239b4115d1a979e66f08832084e9d1d) that atomically removes digests from repository-scoped membership sets during blob deletion. Refer to GitHub Security Advisory GHSA-f2g3-hh2r-cwgc for upgrade guidance. If immediate upgrade is not feasible, implement these compensating controls with their trade-offs: (1) Disable storage.delete.enabled: true to prevent delete operations entirely-this eliminates the vulnerability but also removes the ability to reclaim storage, impacting compliance workflows that depend on permanent deletion. (2) Switch from storage.cache.blobdescriptor: redis to storage.cache.blobdescriptor: inmemory or disable blob descriptor caching entirely-this closes the attack vector but degrades registry performance, especially for Stat-heavy workloads, as every descriptor lookup hits backend storage. (3) Implement external cache invalidation: after deleting a blob from repository A, manually flush the corresponding Redis keys (both the shared descriptor hash and the repository membership set)-this requires custom scripting, introduces operational complexity, and risks race conditions if not executed atomically with the delete operation. None of these workarounds provide the same security guarantee as the patched code, which ensures repository-local revocation survives peer repository cache warming.

Affected VersionsENISA

distribution < 3.1.0

Affected Packages

go github.com/distribution/distribution no fix
go github.com/distribution/distribution/v3 fix: 3.1.0
euvd distribution fix: 3.1.0

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

Distribution (formerly Docker Registry) is a stateless, highly scalable container registry implementation. The vulnerability lies in the Redis-backed blob descriptor cache layer (storage.cache.blobdescriptor: redis), which implements a two-tier state model: shared digest descriptors and repository-scoped membership sets. When storage.delete.enabled: true is configured, the delete code path (linkedBlobStore.Delete → blobAccessController.Clear → cachedBlobStatter.Clear → repositoryScopedRedisBlobDescriptorService.Clear) only invalidates the shared digest descriptor via upstream.Clear but fails to remove the digest from the repository-scoped membership set in Redis. Later, when a peer repository (repo B) legitimately accesses the same digest via Stat or Get, it repopulates the shared descriptor. The original repository (repo A) then trusts the stale membership metadata and re-authorizes access to content it had already deleted. This maps to CWE-284 (Improper Access Control) because the cache layer violates the repository-link-based access model's revocation invariant: once a repository deletes its blob link, it should never regain read access to that digest regardless of peer repository state. The affected code paths are in registry/storage/cache/redis/redis.go (L212-226), cachedblobdescriptorstore.go (L66-76), and linkedblobstore.go (L218-224, L396-403).

Know when Redis 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

Vendor (https://github.com/distribution/distribution) PRIMARY 7.5 HIGH
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
SUSE HIGH
Red Hat 7.5 HIGH

Primary rating from Vendor (https://github.com/distribution/distribution).

CVSS VectorVendor: https://github.com/distribution/distribution

Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
None
Availability
None

Lifecycle Timeline

3
Analysis Updated
Apr 28, 2026 - 00:14 vuln.today
v2 - CVSS changed
Patch released
Apr 06, 2026 - 19:00 nvd
Patch available
CVE Published
Apr 06, 2026 - 17:53 nvd
HIGH 7.5

DescriptionCVE.org

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: \<= 3.0.x, \<= 2.8.x when redis blob descriptor cache and delete are both enabled
  • affected file:
  • https://github.com/distribution/distribution/blob/ab67ffa0bda3712991194841d0fde727464feeb9/registry/storage/cache/redis/redis.go#L212-L226
  • related callsites:
  • https://github.com/distribution/distribution/blob/ab67ffa0bda3712991194841d0fde727464feeb9/registry/storage/cache/cachedblobdescriptorstore.go#L66-L76
  • https://github.com/distribution/distribution/blob/ab67ffa0bda3712991194841d0fde727464feeb9/registry/storage/linkedblobstore.go#L218-L224
  • https://github.com/distribution/distribution/blob/ab67ffa0bda3712991194841d0fde727464feeb9/registry/storage/linkedblobstore.go#L396-L403

details

the backend access model is repository-link based: once repo a deletes its blob link, later reads from repo a should continue returning ErrBlobUnknown even if the same digest remains linked in repo b.

the issue is the split invalidation path in the redis cache backend:

  1. linkedBlobStore.Delete calls blobAccessController.Clear during repository delete handling.
  2. cachedBlobStatter.Clear forwards that invalidation into the cache layer.
  3. repositoryScopedRedisBlobDescriptorService.Clear checks that the digest is a member of repo a, but then only calls upstream.Clear.
  4. upstream.Clear deletes the shared digest descriptor and does not remove the digest from the repository membership set for repo a.
  5. when repo b later stats or gets the same digest, the shared descriptor is recreated.
  6. repositoryScopedRedisBlobDescriptorService.Stat for repo a accepts the stale membership and now trusts the repopulated shared descriptor, restoring access in the repository that already deleted its link.

this creates a revocation gap at the repository boundary. the blob is briefly inaccessible from repo a right after delete, which confirms the backend link was removed, and then becomes accessible again only because stale redis membership survived while a peer repository repopulated the shared descriptor.

attack scenario

  1. an operator runs distribution with storage.cache.blobdescriptor: redis and storage.delete.enabled: true.
  2. the same digest exists in both repo a and repo b.
  3. the operator deletes the blob from repo a and expects repository-local access to be revoked.
  4. repo a correctly returns blob unknown immediately after the delete.
  5. an anonymous or unprivileged user requests the same digest from repo b, which still legitimately owns it and repopulates the shared descriptor.
  6. a later request for the digest from repo a succeeds again because stale repo-a membership was never revoked from redis.

PoC

attachment: poc.zip

the attached PoC is a deterministic integration harness using miniredis and the pinned distribution source tree.

steps to reproduce

canonical:

bash
unzip -q -o poc.zip -d poc
cd poc
make canonical

expected output:

text
[CALLSITE_HIT]: repositoryScopedRedisBlobDescriptorService.Clear->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

Executive ViewAI

Why It Matters

Distribution container registry versions 3.0.x and 2.8.x contain an authorization bypass that allows unauthorized read access to deleted blobs when Redis caching is enabled, enabling attackers to recover sensitive container images or artifacts after deletion without authentication. This vulnerability undermines content revocation controls and exposes organizations to data exposure when repositories share cached blob descriptors, requiring immediate patching to restore repository isolation.

Business Impact: High
Compensating Controls

Apply vendor patch. If patching cannot be applied immediately: disable Redis blob descriptor caching (set REGISTRY_STORAGE_CACHE_BLOBDESCRIPTOR to 'none' or remove caching configuration); implement network-level access controls to restrict registry access to authorized users only; monitor registry deletion operations and validate deletion succeeded before considering content revoked; segregate repositories with sensitive content to isolated registry instances without shared Redis caches.

Threat Intelligence Overview

EPSS Score
0.0%
Top 91% exploitable
Threat Intel
1
1 source
Data Quality
8 sources
Confidence: High
EUVD NVD CVE.org EPSS Vulnrichment GHSA Vendor GitHub VulDB

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.

SignalValue
Severity HIGH
CISA KEV No
Public POC No
EPSS 0.0%
Patch available Yes
Active threat No
Deciding rule
HIGH severity (CVSS 7.0-8.9)
What every action level means
Emergency Immediate action required. Criteria: CRITICAL + in CISA KEV (actively exploited) without patch, OR CRITICAL + EPSS > 30% without patch, OR CRITICAL + active threat signals without patch.
Act Now Prioritize within 24-48h. Criteria: in KEV with patch available, OR CRITICAL + public POC, OR HIGH + EPSS > 10%, OR CRITICAL + active threat, OR any CRITICAL severity.
This Week Schedule remediation this week. Criteria: HIGH severity (CVSS 7.0-8.9). Patch within normal change window.
This Month Plan within 30 days. Criteria: MEDIUM severity (CVSS 4.0-6.9), lower exploitation probability. Include in regular patch cycle.
Monitor Track and reassess. Criteria: LOW severity (CVSS 0.1-3.9), minimal exploitation risk. No immediate action needed.

SSVC AssessmentENISA

SSVC Decision
Out-of-Cycle
Exploitation
Poc
System Exposure· derived
Open
Automatable
Yes
Human Impact
High
Technical Impact
Partial

Priority Score

38
Low Medium High Critical
KEV: 0
EPSS: 0
CVSS: +38
PoC: 0
Weaponized: 0
Threat intel: 0
Gov advisory: 0

Attack Technique

Authentication bypass attacks exploit flaws in the verification mechanisms that control access to systems and applications.

More in Redis

View all
CVE-2026-48172 CRITICAL POC
10.0 May 21

Privilege escalation to root in the LiteSpeed User-End cPanel Plugin (versions 2.3 through before 2.4.5) lets attackers

CVE-2025-49844 CRITICAL POC
9.9 Oct 03

UAF in Redis 8.2.1 via crafted Lua scripts by authenticated users. EPSS 12.4%. Patch available.

CVE-2025-46817 HIGH POC
8.8 Oct 03

Authenticated Redis users with permission to run server-side Lua can trigger an integer overflow (CWE-190) in the bundle

CVE-2022-0543 CRITICAL POC
10.0 Feb 18

It was discovered, that redis, a persistent key-value database, due to a packaging issue, is prone to a (Debian-specific

CVE-2018-11218 CRITICAL POC
9.8 Jun 17

Memory Corruption was discovered in the cmsgpack library in the Lua subsystem in Redis before 3.2.12, 4.x before 4.0.10,

CVE-2015-4335 CRITICAL POC
10.0 Jun 09

Redis before 2.8.21 and 3.x before 3.0.2 allows remote attackers to execute arbitrary Lua bytecode via the eval command.

CVE-2016-8339 CRITICAL POC
9.8 Oct 28

A buffer overflow in Redis 3.2.x prior to 3.2.4 causes arbitrary code execution when a crafted command is sent. Rated cr

CVE-2025-46819 HIGH POC
7.1 Oct 03

Authenticated Lua script execution in Redis 8.2.1 and earlier can be abused with a crafted long-string delimiter to trig

CVE-2026-77602 CRITICAL POC
9.9 Sep 23

Authenticated remote code execution in OpenC3 COSMOS (Ruby gem 'openc3' versions 5.1.0 through 7.2.1) lets any logged-in

CVE-2025-46818 HIGH POC
7.3 Oct 03

CVE-2025-46818 is a sandbox-escape flaw in Redis's embedded Lua scripting engine (all versions up to and including 8.2.1

CVE-2026-27574 CRITICAL POC
9.9 Feb 21

Code injection in OneUptime monitoring via custom JS monitor using vm module. PoC and patch available.

CVE-2026-84372 CRITICAL POC
9.8 Sep 01

RESP protocol command injection in Predis, the popular PHP client for Redis and Valkey, affects versions 3.0.0-RC1 throu

Vendor StatusVendor

SUSE

Severity: High
Product Status
SUSE Linux Enterprise High Performance Computing 15 SP7 Fixed
SUSE Linux Enterprise Micro 5.5 Fixed
SUSE Linux Enterprise Module for Containers 15 SP7 Fixed
SUSE Linux Enterprise Module for Package Hub 15 SP7 Fixed
SUSE Linux Enterprise Server 15 SP7 Fixed

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy