VYPR
Moderate severityNVD Advisory· Published Nov 11, 2012· Updated Apr 29, 2026

CVE-2012-4573

CVE-2012-4573

Description

The v1 API in OpenStack Glance Grizzly, Folsom (2012.2), and Essex (2012.1) allows remote authenticated users to delete arbitrary non-protected images via an image deletion request, a different vulnerability than CVE-2012-5482.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
glancePyPI
< 11.0.0a011.0.0a0

Affected products

3

Patches

3
efd7e75b1f41

Ensure image owned by user before delayed_deletion

https://github.com/openstack/glanceBrian WaldonNov 7, 2012via ghsa
1 file changed · +9 0
  • glance/api/v1/images.py+9 0 modified
    @@ -727,6 +727,15 @@ def delete(self, req, id):
                                     content_type="text/plain")
     
             image = self.get_image_meta_or_404(req, id)
    +
    +        if not (req.context.is_admin
    +                or image['owner'] == None
    +                or image['owner'] == req.context.owner):
    +            msg = _("Unable to delete image you do not own")
    +            logger.debug(msg)
    +            raise HTTPForbidden(msg, request=req,
    +                                content_type="text/plain")
    +
             if image['protected']:
                 msg = _("Image is protected")
                 logger.debug(msg)
    
90bcdc5a89e3

Delete from store after registry delete.

https://github.com/openstack/glanceMark WashenbergerNov 7, 2012via ghsa
4 files changed · +39 6
  • glance/api/v1/images.py+11 5 modified
    @@ -821,22 +821,28 @@ def delete(self, req, id):
                                     request=req,
                                     content_type="text/plain")
     
    -        status = 'deleted'
    +        if image['location'] and CONF.delayed_delete:
    +            status = 'pending_delete'
    +        else:
    +            status = 'deleted'
    +
             try:
    +            # Delete the image from the registry first, since we rely on it
    +            # for authorization checks.
    +            # See https://bugs.launchpad.net/glance/+bug/1065187
    +            registry.update_image_metadata(req.context, id, {'status': status})
    +            registry.delete_image_metadata(req.context, id)
    +
                 # The image's location field may be None in the case
                 # of a saving or queued image, therefore don't ask a backend
                 # to delete the image if the backend doesn't yet store it.
                 # See https://bugs.launchpad.net/glance/+bug/747799
                 if image['location']:
                     if CONF.delayed_delete:
    -                    status = 'pending_delete'
                         schedule_delayed_delete_from_backend(image['location'], id)
                     else:
                         safe_delete_from_backend(image['location'],
                                                  req.context, id)
    -
    -            registry.update_image_metadata(req.context, id, {'status': status})
    -            registry.delete_image_metadata(req.context, id)
             except exception.NotFound, e:
                 msg = ("Failed to find image to delete: %(e)s" % locals())
                 for line in msg.split('\n'):
    
  • glance/tests/stubs.py+7 1 modified
    @@ -60,7 +60,13 @@ def request(self, method, url, body=None, headers=None):
     
         def getresponse(self):
             mapper = routes.Mapper()
    -        api = context.UnauthenticatedContextMiddleware(rserver.API(mapper))
    +        server = rserver.API(mapper)
    +        # NOTE(markwash): we need to pass through context auth information if
    +        # we have it.
    +        if 'X-Auth-Token' in self.req.headers:
    +            api = utils.FakeAuthMiddleware(server)
    +        else:
    +            api = context.UnauthenticatedContextMiddleware(server)
             webob_res = self.req.get_response(api)
     
             return utils.FakeHTTPResponse(status=webob_res.status_int,
    
  • glance/tests/unit/v1/test_api.py+20 0 modified
    @@ -2930,6 +2930,26 @@ def test_delete_non_exists_image(self):
             res = req.get_response(self.api)
             self.assertEquals(res.status_int, webob.exc.HTTPNotFound.code)
     
    +    def test_delete_not_allowed(self):
    +        # Verify we can get the image data
    +        req = webob.Request.blank("/images/%s" % UUID2)
    +        req.method = 'GET'
    +        req.headers['X-Auth-Token'] = 'user:tenant:'
    +        res = req.get_response(self.api)
    +        self.assertEqual(res.status_int, 200)
    +        self.assertEqual(len(res.body), 19)
    +
    +        # Verify we cannot delete the image
    +        req.method = 'DELETE'
    +        res = req.get_response(self.api)
    +        self.assertEqual(res.status_int, 403)
    +
    +        # Verify the image data is still there
    +        req.method = 'GET'
    +        res = req.get_response(self.api)
    +        self.assertEqual(res.status_int, 200)
    +        self.assertEqual(len(res.body), 19)
    +
         def test_delete_queued_image(self):
             """Delete an image in a queued state
     
    
  • glance/tests/utils.py+1 0 modified
    @@ -368,6 +368,7 @@ def process_request(self, req):
                 'tenant': tenant,
                 'roles': roles,
                 'is_admin': self.is_admin,
    +            'auth_tok': auth_tok,
             }
     
             req.context = context.RequestContext(**kwargs)
    
6ab0992e5472

Delete from store after registry delete.

https://github.com/openstack/glanceMark WashenbergerNov 7, 2012via ghsa
4 files changed · +39 6
  • glance/api/v1/images.py+11 5 modified
    @@ -827,22 +827,28 @@ def delete(self, req, id):
                 raise HTTPForbidden(explanation=msg, request=req,
                                     content_type="text/plain")
     
    -        status = 'deleted'
    +        if image['location'] and CONF.delayed_delete:
    +            status = 'pending_delete'
    +        else:
    +            status = 'deleted'
    +
             try:
    +            # Delete the image from the registry first, since we rely on it
    +            # for authorization checks.
    +            # See https://bugs.launchpad.net/glance/+bug/1065187
    +            registry.update_image_metadata(req.context, id, {'status': status})
    +            registry.delete_image_metadata(req.context, id)
    +
                 # The image's location field may be None in the case
                 # of a saving or queued image, therefore don't ask a backend
                 # to delete the image if the backend doesn't yet store it.
                 # See https://bugs.launchpad.net/glance/+bug/747799
                 if image['location']:
                     if CONF.delayed_delete:
    -                    status = 'pending_delete'
                         schedule_delayed_delete_from_backend(image['location'], id)
                     else:
                         safe_delete_from_backend(image['location'],
                                                  req.context, id)
    -
    -            registry.update_image_metadata(req.context, id, {'status': status})
    -            registry.delete_image_metadata(req.context, id)
             except exception.NotFound, e:
                 msg = ("Failed to find image to delete: %(e)s" % locals())
                 for line in msg.split('\n'):
    
  • glance/tests/stubs.py+7 1 modified
    @@ -60,7 +60,13 @@ def request(self, method, url, body=None, headers=None):
     
         def getresponse(self):
             mapper = routes.Mapper()
    -        api = context.UnauthenticatedContextMiddleware(rserver.API(mapper))
    +        server = rserver.API(mapper)
    +        # NOTE(markwash): we need to pass through context auth information if
    +        # we have it.
    +        if 'X-Auth-Token' in self.req.headers:
    +            api = utils.FakeAuthMiddleware(server)
    +        else:
    +            api = context.UnauthenticatedContextMiddleware(server)
             webob_res = self.req.get_response(api)
     
             return utils.FakeHTTPResponse(status=webob_res.status_int,
    
  • glance/tests/unit/v1/test_api.py+20 0 modified
    @@ -3015,6 +3015,26 @@ def test_delete_non_exists_image(self):
             res = req.get_response(self.api)
             self.assertEquals(res.status_int, webob.exc.HTTPNotFound.code)
     
    +    def test_delete_not_allowed(self):
    +        # Verify we can get the image data
    +        req = webob.Request.blank("/images/%s" % UUID2)
    +        req.method = 'GET'
    +        req.headers['X-Auth-Token'] = 'user:tenant:'
    +        res = req.get_response(self.api)
    +        self.assertEqual(res.status_int, 200)
    +        self.assertEqual(len(res.body), 19)
    +
    +        # Verify we cannot delete the image
    +        req.method = 'DELETE'
    +        res = req.get_response(self.api)
    +        self.assertEqual(res.status_int, 403)
    +
    +        # Verify the image data is still there
    +        req.method = 'GET'
    +        res = req.get_response(self.api)
    +        self.assertEqual(res.status_int, 200)
    +        self.assertEqual(len(res.body), 19)
    +
         def test_delete_queued_image(self):
             """Delete an image in a queued state
     
    
  • glance/tests/utils.py+1 0 modified
    @@ -372,6 +372,7 @@ def process_request(self, req):
                 'tenant': tenant,
                 'roles': roles,
                 'is_admin': self.is_admin,
    +            'auth_tok': auth_tok,
             }
     
             req.context = context.RequestContext(**kwargs)
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

20

News mentions

0

No linked articles in our index yet.