VYPR
Moderate severityNVD Advisory· Published Jan 21, 2015· Updated May 6, 2026

CVE-2015-1195

CVE-2015-1195

Description

The V2 API in OpenStack Image Registry and Delivery Service (Glance) before 2014.1.4 and 2014.2.x before 2014.2.2 allows remote authenticated users to read or delete arbitrary files via a full pathname in a filesystem: URL in the image location property. NOTE: this vulnerability exists because of an incomplete fix for CVE-2014-9493.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
glancePyPI
< 11.0.0a011.0.0a0

Affected products

1

Patches

3
7d3a1db33ccb

Prevent file, swift+config and filesystem schemes

https://github.com/openstack/glanceGrant MurphyJan 8, 2015via ghsa
3 files changed · +22 24
  • glance/store/__init__.py+7 4 modified
    @@ -76,6 +76,8 @@
         'glance.store.vmware_datastore.Store'
     ]
     
    +RESTRICTED_URI_SCHEMAS = frozenset(['file', 'filesystem', 'swift+config'])
    +
     
     class BackendException(Exception):
         pass
    @@ -434,10 +436,11 @@ def validate_external_location(uri):
         :param uri: The URI of external image location.
         :return: Whether given URI of external image location are OK.
         """
    -    pieces = urlparse.urlparse(uri)
    -    valid_schemes = [scheme for scheme in get_known_schemes()
    -                     if scheme != 'file' and scheme != 'swift+config']
    -    return pieces.scheme in valid_schemes
    +
    +    # TODO(gm): Use a whitelist of allowed schemes
    +    scheme = urlparse.urlparse(uri).scheme
    +    return (scheme in get_known_schemes() and
    +            scheme not in RESTRICTED_URI_SCHEMAS)
     
     
     class ImageRepoProxy(glance.domain.proxy.Repo):
    
  • glance/tests/unit/test_store_location.py+3 0 modified
    @@ -524,12 +524,15 @@ def test_add_location_with_restricted_sources(self):
     
             loc1 = {'url': 'file:///fake1.img.tar.gz', 'metadata': {}}
             loc2 = {'url': 'swift+config:///xxx', 'metadata': {}}
    +        loc3 = {'url': 'filesystem:///foo.img.tar.gz', 'metadata': {}}
     
             # Test for insert location
             image1 = TestStoreLocation.FakeImageProxy(utils.FakeStoreAPI())
             locations = glance.store.StoreLocations(image1, [])
             self.assertRaises(exception.BadStoreUri, locations.insert, 0, loc1)
    +        self.assertRaises(exception.BadStoreUri, locations.insert, 0, loc3)
             self.assertNotIn(loc1, locations)
    +        self.assertNotIn(loc3, locations)
     
             # Test for set_attr of _locations_proxy
             image2 = TestStoreLocation.FakeImageProxy(utils.FakeStoreAPI())
    
  • glance/tests/unit/v1/test_api.py+12 20 modified
    @@ -1010,31 +1010,23 @@ def test_add_copy_from_with_location(self):
     
         def test_add_copy_from_with_restricted_sources(self):
             """Tests creates an image from copy-from with restricted sources"""
    -        fixture_headers = {'x-image-meta-store': 'file',
    +        header_template = {'x-image-meta-store': 'file',
                                'x-image-meta-disk-format': 'vhd',
    -                           'x-glance-api-copy-from': 'file:///etc/passwd',
                                'x-image-meta-container-format': 'ovf',
                                'x-image-meta-name': 'fake image #F'}
     
    -        req = webob.Request.blank("/images")
    -        req.method = 'POST'
    -        for k, v in six.iteritems(fixture_headers):
    -            req.headers[k] = v
    -        res = req.get_response(self.api)
    -        self.assertEqual(400, res.status_int)
    -
    -        fixture_headers = {'x-image-meta-store': 'file',
    -                           'x-image-meta-disk-format': 'vhd',
    -                           'x-glance-api-copy-from': 'swift+config://xxx',
    -                           'x-image-meta-container-format': 'ovf',
    -                           'x-image-meta-name': 'fake image #F'}
    +        schemas = ["file:///etc/passwd",
    +                   "swift+config:///xxx",
    +                   "filesystem:///etc/passwd"]
     
    -        req = webob.Request.blank("/images")
    -        req.method = 'POST'
    -        for k, v in six.iteritems(fixture_headers):
    -            req.headers[k] = v
    -        res = req.get_response(self.api)
    -        self.assertEqual(400, res.status_int)
    +        for schema in schemas:
    +            req = webob.Request.blank("/images")
    +            req.method = 'POST'
    +            for k, v in six.iteritems(header_template):
    +                req.headers[k] = v
    +            req.headers['x-glance-api-copy-from'] = schema
    +            res = req.get_response(self.api)
    +            self.assertEqual(400, res.status_int)
     
         def test_add_copy_from_upload_image_unauthorized_with_body(self):
             rules = {"upload_image": '!', "modify_image": '@',
    
a2d986b976e9

Prevent file, swift+config and filesystem schemes

https://github.com/openstack/glanceGrant MurphyJan 8, 2015via ghsa
3 files changed · +21 25
  • glance/common/store_utils.py+6 5 modified
    @@ -38,6 +38,8 @@
     CONF = cfg.CONF
     CONF.register_opts(store_utils_opts)
     
    +RESTRICTED_URI_SCHEMAS = frozenset(['file', 'filesystem', 'swift+config'])
    +
     
     def safe_delete_from_backend(context, image_id, location):
         """
    @@ -136,8 +138,7 @@ def validate_external_location(uri):
         """
     
         # TODO(zhiyan): This function could be moved to glance_store.
    -
    -    pieces = urlparse.urlparse(uri)
    -    valid_schemes = [scheme for scheme in store_api.get_known_schemes()
    -                     if scheme != 'file' and scheme != 'swift+config']
    -    return pieces.scheme in valid_schemes
    +    # TODO(gm): Use a whitelist of allowed schemes
    +    scheme = urlparse.urlparse(uri).scheme
    +    return (scheme in store_api.get_known_schemes() and
    +            scheme not in RESTRICTED_URI_SCHEMAS)
    
  • glance/tests/unit/test_store_location.py+3 0 modified
    @@ -67,12 +67,15 @@ def test_add_location_with_restricted_sources(self):
     
             loc1 = {'url': 'file:///fake1.img.tar.gz', 'metadata': {}}
             loc2 = {'url': 'swift+config:///xxx', 'metadata': {}}
    +        loc3 = {'url': 'filesystem:///foo.img.tar.gz', 'metadata': {}}
     
             # Test for insert location
             image1 = TestStoreLocation.FakeImageProxy()
             locations = glance.location.StoreLocations(image1, [])
             self.assertRaises(exception.BadStoreUri, locations.insert, 0, loc1)
    +        self.assertRaises(exception.BadStoreUri, locations.insert, 0, loc3)
             self.assertNotIn(loc1, locations)
    +        self.assertNotIn(loc3, locations)
     
             # Test for set_attr of _locations_proxy
             image2 = TestStoreLocation.FakeImageProxy()
    
  • glance/tests/unit/v1/test_api.py+12 20 modified
    @@ -1070,31 +1070,23 @@ def test_add_copy_from_with_location(self):
     
         def test_add_copy_from_with_restricted_sources(self):
             """Tests creates an image from copy-from with restricted sources"""
    -        fixture_headers = {'x-image-meta-store': 'file',
    +        header_template = {'x-image-meta-store': 'file',
                                'x-image-meta-disk-format': 'vhd',
    -                           'x-glance-api-copy-from': 'file:///etc/passwd',
                                'x-image-meta-container-format': 'ovf',
                                'x-image-meta-name': 'fake image #F'}
     
    -        req = webob.Request.blank("/images")
    -        req.method = 'POST'
    -        for k, v in six.iteritems(fixture_headers):
    -            req.headers[k] = v
    -        res = req.get_response(self.api)
    -        self.assertEqual(400, res.status_int)
    +        schemas = ["file:///etc/passwd",
    +                   "swift+config:///xxx",
    +                   "filesystem:///etc/passwd"]
     
    -        fixture_headers = {'x-image-meta-store': 'file',
    -                           'x-image-meta-disk-format': 'vhd',
    -                           'x-glance-api-copy-from': 'swift+config://xxx',
    -                           'x-image-meta-container-format': 'ovf',
    -                           'x-image-meta-name': 'fake image #F'}
    -
    -        req = webob.Request.blank("/images")
    -        req.method = 'POST'
    -        for k, v in six.iteritems(fixture_headers):
    -            req.headers[k] = v
    -        res = req.get_response(self.api)
    -        self.assertEqual(400, res.status_int)
    +        for schema in schemas:
    +            req = webob.Request.blank("/images")
    +            req.method = 'POST'
    +            for k, v in six.iteritems(header_template):
    +                req.headers[k] = v
    +            req.headers['x-glance-api-copy-from'] = schema
    +            res = req.get_response(self.api)
    +            self.assertEqual(400, res.status_int)
     
         def test_add_copy_from_upload_image_unauthorized_with_body(self):
             rules = {"upload_image": '!', "modify_image": '@',
    
5191ed1879c5

Prevent file, swift+config and filesystem schemes

https://github.com/openstack/glanceGrant MurphyJan 8, 2015via ghsa
3 files changed · +21 25
  • glance/common/store_utils.py+6 5 modified
    @@ -38,6 +38,8 @@
     CONF = cfg.CONF
     CONF.register_opts(store_utils_opts)
     
    +RESTRICTED_URI_SCHEMAS = frozenset(['file', 'filesystem', 'swift+config'])
    +
     
     def safe_delete_from_backend(context, image_id, location):
         """
    @@ -136,8 +138,7 @@ def validate_external_location(uri):
         """
     
         # TODO(zhiyan): This function could be moved to glance_store.
    -
    -    pieces = urlparse.urlparse(uri)
    -    valid_schemes = [scheme for scheme in store_api.get_known_schemes()
    -                     if scheme != 'file' and scheme != 'swift+config']
    -    return pieces.scheme in valid_schemes
    +    # TODO(gm): Use a whitelist of allowed schemes
    +    scheme = urlparse.urlparse(uri).scheme
    +    return (scheme in store_api.get_known_schemes() and
    +            scheme not in RESTRICTED_URI_SCHEMAS)
    
  • glance/tests/unit/test_store_location.py+3 0 modified
    @@ -69,12 +69,15 @@ def test_add_location_with_restricted_sources(self):
     
             loc1 = {'url': 'file:///fake1.img.tar.gz', 'metadata': {}}
             loc2 = {'url': 'swift+config:///xxx', 'metadata': {}}
    +        loc3 = {'url': 'filesystem:///foo.img.tar.gz', 'metadata': {}}
     
             # Test for insert location
             image1 = TestStoreLocation.FakeImageProxy()
             locations = glance.location.StoreLocations(image1, [])
             self.assertRaises(exception.BadStoreUri, locations.insert, 0, loc1)
    +        self.assertRaises(exception.BadStoreUri, locations.insert, 0, loc3)
             self.assertNotIn(loc1, locations)
    +        self.assertNotIn(loc3, locations)
     
             # Test for set_attr of _locations_proxy
             image2 = TestStoreLocation.FakeImageProxy()
    
  • glance/tests/unit/v1/test_api.py+12 20 modified
    @@ -1071,31 +1071,23 @@ def test_add_copy_from_with_location(self):
     
         def test_add_copy_from_with_restricted_sources(self):
             """Tests creates an image from copy-from with restricted sources"""
    -        fixture_headers = {'x-image-meta-store': 'file',
    +        header_template = {'x-image-meta-store': 'file',
                                'x-image-meta-disk-format': 'vhd',
    -                           'x-glance-api-copy-from': 'file:///etc/passwd',
                                'x-image-meta-container-format': 'ovf',
                                'x-image-meta-name': 'fake image #F'}
     
    -        req = webob.Request.blank("/images")
    -        req.method = 'POST'
    -        for k, v in six.iteritems(fixture_headers):
    -            req.headers[k] = v
    -        res = req.get_response(self.api)
    -        self.assertEqual(400, res.status_int)
    +        schemas = ["file:///etc/passwd",
    +                   "swift+config:///xxx",
    +                   "filesystem:///etc/passwd"]
     
    -        fixture_headers = {'x-image-meta-store': 'file',
    -                           'x-image-meta-disk-format': 'vhd',
    -                           'x-glance-api-copy-from': 'swift+config://xxx',
    -                           'x-image-meta-container-format': 'ovf',
    -                           'x-image-meta-name': 'fake image #F'}
    -
    -        req = webob.Request.blank("/images")
    -        req.method = 'POST'
    -        for k, v in six.iteritems(fixture_headers):
    -            req.headers[k] = v
    -        res = req.get_response(self.api)
    -        self.assertEqual(400, res.status_int)
    +        for schema in schemas:
    +            req = webob.Request.blank("/images")
    +            req.method = 'POST'
    +            for k, v in six.iteritems(header_template):
    +                req.headers[k] = v
    +            req.headers['x-glance-api-copy-from'] = schema
    +            res = req.get_response(self.api)
    +            self.assertEqual(400, res.status_int)
     
         def test_add_copy_from_upload_image_unauthorized_with_body(self):
             rules = {"upload_image": '!', "modify_image": '@',
    

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

12

News mentions

0

No linked articles in our index yet.