Renovate: Update module github.com/distribution/distribution/v3 to v3.1.0 [SECURITY]#12
Open
renovate[bot] wants to merge 1 commit intomasterfrom
Conversation
Author
ℹ️ Artifact update noticeFile name: go.modIn order to perform the update(s) described in the table above, Renovate ran the
Details:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR contains the following updates:
v3.0.0→v3.1.0GitHub Vulnerability Alerts
CVE-2026-33540
hi guys,
commit: 40594bd98e6d6ed993b5c6021c93fdf96d2e5851 (as-of 2026-01-31)
contact: GitHub Security Advisory (https://github.com/distribution/distribution/security/advisories/new)
summary
in pull-through cache mode, distribution discovers token auth endpoints by parsing
WWW-Authenticatechallenges returned by the configured upstream registry. therealmURL from a bearer challenge is used without validating that it matches the upstream registry host. as a result, an attacker-controlled upstream (or an attacker with MitM position to the upstream) can cause distribution to send the configured upstream credentials via basic auth to an attacker-controlledrealmURL.this is the same vulnerability class as CVE-2020-15157 (containerd), but in distribution’s pull-through cache proxy auth flow.
severity
HIGH
note: the baseline impact is credential disclosure of the configured upstream credentials. if a deployment uses broader credentials for upstream auth (for example cloud iam credentials), the downstream impact can be higher; i am not claiming this as default for all deployments.
impact
credential exfiltration of the upstream authentication material configured for the pull-through cache.
attacker starting positions that make this realistic:
affected components
registry/proxy/proxyauth.go:66-81(getAuthURLs): extracts bearerrealmfrom upstreamWWW-Authenticatewithout validating destinationinternal/client/auth/session.go:485-510(fetchToken): uses the realm URL directly for token fetchinternal/client/auth/session.go:429-434(fetchTokenWithBasicAuth): sends credentials via basic auth to the realm URLreproduction
attachment:
poc.zip(local harness) with canonical and control runs.the harness is local and does not contact a real registry: it uses two local HTTP servers (upstream + attacker token service) to demonstrate whether basic auth is sent to an attacker-chosen realm.
unzip -q -o poc.zip -d poc cd poc make canonical make controlexpected output (excerpt):
control output (excerpt):
suggested remediation
validate that the token
realmdestination is within the intended trust boundary before associating credentials with it or sending any authentication to it. one conservative option is strict same-host binding: only accept a realm whose host matches the configured upstream host.fix accepted when
addendum.md
poc.zip
PR_DESCRIPTION.md
RUNNABLE_POC.md
best,
oleh
CVE-2026-35172
summary:
distribution can restore read access in
repo aafter an explicit delete whenstorage.cache.blobdescriptor: redisandstorage.delete.enabled: trueare both enabled. the delete path clears the shared digest descriptor but leaves stale repo-scoped membership behind, so a laterStatorGetfromrepo brepopulates the shared descriptor and makes the deleted blob readable fromrepo aagain.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
details
the backend access model is repository-link based: once
repo adeletes its blob link, later reads fromrepo ashould continue returningErrBlobUnknowneven if the same digest remains linked inrepo b.the issue is the split invalidation path in the redis cache backend:
linkedBlobStore.DeletecallsblobAccessController.Clearduring repository delete handling.cachedBlobStatter.Clearforwards that invalidation into the cache layer.repositoryScopedRedisBlobDescriptorService.Clearchecks that the digest is a member ofrepo a, but then only callsupstream.Clear.upstream.Cleardeletes the shared digest descriptor and does not remove the digest from the repository membership set forrepo a.repo blater stats or gets the same digest, the shared descriptor is recreated.repositoryScopedRedisBlobDescriptorService.Statforrepo aaccepts 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 aright 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
storage.cache.blobdescriptor: redisandstorage.delete.enabled: true.repo aandrepo b.repo aand expects repository-local access to be revoked.repo acorrectly returnsblob unknownimmediately after the delete.repo b, which still legitimately owns it and repopulates the shared descriptor.repo asucceeds again because stale repo-a membership was never revoked from redis.PoC
attachment:
poc.zipthe attached PoC is a deterministic integration harness using
miniredisand the pinned distribution source tree.steps to reproduce
canonical:
unzip -q -o poc.zip -d poc cd poc make canonicalexpected output:
control:
unzip -q -o poc.zip -d poc cd poc make controlexpected control output:
expected vs actual
repo adeletes its blob link, later reads fromrepo ashould keep returningblob unknowneven ifrepo bstill references the same digest and warms cache state.repo afirst returnsblob unknown, thenrepo brepopulates the shared descriptor, andrepo aserves 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 fromrepo aagain as soon asrepo brefreshes 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
Distribution affected by pull-through cache credential exfiltration via www-authenticate bearer realm
CVE-2026-33540 / GHSA-3p65-76g6-3w7r
More information
Details
hi guys,
commit: 40594bd98e6d6ed993b5c6021c93fdf96d2e5851 (as-of 2026-01-31)
contact: GitHub Security Advisory (https://github.com/distribution/distribution/security/advisories/new)
summary
in pull-through cache mode, distribution discovers token auth endpoints by parsing
WWW-Authenticatechallenges returned by the configured upstream registry. therealmURL from a bearer challenge is used without validating that it matches the upstream registry host. as a result, an attacker-controlled upstream (or an attacker with MitM position to the upstream) can cause distribution to send the configured upstream credentials via basic auth to an attacker-controlledrealmURL.this is the same vulnerability class as CVE-2020-15157 (containerd), but in distribution’s pull-through cache proxy auth flow.
severity
HIGH
note: the baseline impact is credential disclosure of the configured upstream credentials. if a deployment uses broader credentials for upstream auth (for example cloud iam credentials), the downstream impact can be higher; i am not claiming this as default for all deployments.
impact
credential exfiltration of the upstream authentication material configured for the pull-through cache.
attacker starting positions that make this realistic:
affected components
registry/proxy/proxyauth.go:66-81(getAuthURLs): extracts bearerrealmfrom upstreamWWW-Authenticatewithout validating destinationinternal/client/auth/session.go:485-510(fetchToken): uses the realm URL directly for token fetchinternal/client/auth/session.go:429-434(fetchTokenWithBasicAuth): sends credentials via basic auth to the realm URLreproduction
attachment:
poc.zip(local harness) with canonical and control runs.the harness is local and does not contact a real registry: it uses two local HTTP servers (upstream + attacker token service) to demonstrate whether basic auth is sent to an attacker-chosen realm.
unzip -q -o poc.zip -d poc cd poc make canonical make controlexpected output (excerpt):
control output (excerpt):
suggested remediation
validate that the token
realmdestination is within the intended trust boundary before associating credentials with it or sending any authentication to it. one conservative option is strict same-host binding: only accept a realm whose host matches the configured upstream host.fix accepted when
addendum.md
poc.zip
PR_DESCRIPTION.md
RUNNABLE_POC.md
best,
oleh
Severity
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:NReferences
This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).
Distribution: stale blob access resurrection via repo-scoped redis descriptor cache invalidation
CVE-2026-35172 / GHSA-f2g3-hh2r-cwgc
More information
Details
summary:
distribution can restore read access in
repo aafter an explicit delete whenstorage.cache.blobdescriptor: redisandstorage.delete.enabled: trueare both enabled. the delete path clears the shared digest descriptor but leaves stale repo-scoped membership behind, so a laterStatorGetfromrepo brepopulates the shared descriptor and makes the deleted blob readable fromrepo aagain.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
details
the backend access model is repository-link based: once
repo adeletes its blob link, later reads fromrepo ashould continue returningErrBlobUnknowneven if the same digest remains linked inrepo b.the issue is the split invalidation path in the redis cache backend:
linkedBlobStore.DeletecallsblobAccessController.Clearduring repository delete handling.cachedBlobStatter.Clearforwards that invalidation into the cache layer.repositoryScopedRedisBlobDescriptorService.Clearchecks that the digest is a member ofrepo a, but then only callsupstream.Clear.upstream.Cleardeletes the shared digest descriptor and does not remove the digest from the repository membership set forrepo a.repo blater stats or gets the same digest, the shared descriptor is recreated.repositoryScopedRedisBlobDescriptorService.Statforrepo aaccepts 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 aright 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
storage.cache.blobdescriptor: redisandstorage.delete.enabled: true.repo aandrepo b.repo aand expects repository-local access to be revoked.repo acorrectly returnsblob unknownimmediately after the delete.repo b, which still legitimately owns it and repopulates the shared descriptor.repo asucceeds again because stale repo-a membership was never revoked from redis.PoC
attachment:
poc.zipthe attached PoC is a deterministic integration harness using
miniredisand the pinned distribution source tree.steps to reproduce
canonical:
unzip -q -o poc.zip -d poc cd poc make canonicalexpected output:
control:
unzip -q -o poc.zip -d poc cd poc make controlexpected control output:
expected vs actual
repo adeletes its blob link, later reads fromrepo ashould keep returningblob unknowneven ifrepo bstill references the same digest and warms cache state.repo afirst returnsblob unknown, thenrepo brepopulates the shared descriptor, andrepo aserves 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 fromrepo aagain as soon asrepo brefreshes 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
Severity
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:NReferences
This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).
Release Notes
distribution/distribution (github.com/distribution/distribution/v3)
v3.1.0Compare Source
Welcome to the
v3.1.0release of registry!This is a stable release
Please try out the release binaries and report any issues at
https://github.com/distribution/distribution/issues.
Notable Changes
See the full changelog below for the full list of changes.
What's Changed
Ed25519public keys by @zhangyoufu in #4626OTEL_TRACES_EXPORTERby @jcpunk in #4669useFIPSEndpointfor S3 by @1raghavmahajan in #47646053543by @thaJeztah in #4791proxyingRegistry.Close()by @joonas in #4805Writecall inputContentby @joonas in #4803Ed25519JWK thumbprintktyfrom"OTP"to"OKP"by @joonas in #4801New Contributors
Full Changelog: distribution/distribution@v3.0.0...v3.1.0
Configuration
📅 Schedule: (UTC)
🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR was generated by Mend Renovate. View the repository job log.