VYPR
Moderate severityNVD Advisory· Published Jun 2, 2014· Updated May 6, 2026

CVE-2013-2014

CVE-2013-2014

Description

OpenStack Identity (Keystone) before 2013.1 allows remote attackers to cause a denial of service (memory consumption and crash) via multiple long requests.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
keystonePyPI
< 8.0.0a08.0.0a0

Affected products

2

Patches

1
7691276b869a

Limit the size of HTTP requests.

https://github.com/openstack/keystoneDan PrinceJan 13, 2013via ghsa
6 files changed · +127 5
  • etc/keystone.conf.sample+8 5 modified
    @@ -186,6 +186,9 @@ paste.filter_factory = keystone.contrib.s3:S3Extension.factory
     [filter:url_normalize]
     paste.filter_factory = keystone.middleware:NormalizingFilter.factory
     
    +[filter:sizelimit]
    +paste.filter_factory = keystone.middleware:RequestBodySizeLimiter.factory
    +
     [filter:stats_monitoring]
     paste.filter_factory = keystone.contrib.stats:StatsMiddleware.factory
     
    @@ -202,13 +205,13 @@ paste.app_factory = keystone.service:v3_app_factory
     paste.app_factory = keystone.service:admin_app_factory
     
     [pipeline:public_api]
    -pipeline = stats_monitoring url_normalize token_auth admin_token_auth xml_body json_body debug ec2_extension user_crud_extension public_service
    +pipeline = sizelimit stats_monitoring url_normalize token_auth admin_token_auth xml_body json_body debug ec2_extension user_crud_extension public_service
     
     [pipeline:admin_api]
    -pipeline = stats_monitoring url_normalize token_auth admin_token_auth xml_body json_body debug stats_reporting ec2_extension s3_extension crud_extension admin_service
    +pipeline = sizelimit stats_monitoring url_normalize token_auth admin_token_auth xml_body json_body debug stats_reporting ec2_extension s3_extension crud_extension admin_service
     
     [pipeline:api_v3]
    -pipeline = stats_monitoring url_normalize token_auth admin_token_auth xml_body json_body debug stats_reporting ec2_extension s3_extension service_v3
    +pipeline = sizelimit stats_monitoring url_normalize token_auth admin_token_auth xml_body json_body debug stats_reporting ec2_extension s3_extension service_v3
     
     [app:public_version_service]
     paste.app_factory = keystone.service:public_version_app_factory
    @@ -217,10 +220,10 @@ paste.app_factory = keystone.service:public_version_app_factory
     paste.app_factory = keystone.service:admin_version_app_factory
     
     [pipeline:public_version_api]
    -pipeline = stats_monitoring url_normalize xml_body public_version_service
    +pipeline = sizelimit stats_monitoring url_normalize xml_body public_version_service
     
     [pipeline:admin_version_api]
    -pipeline = stats_monitoring url_normalize xml_body admin_version_service
    +pipeline = sizelimit stats_monitoring url_normalize xml_body admin_version_service
     
     [composite:main]
     use = egg:Paste#urlmap
    
  • keystone/common/utils.py+34 0 modified
    @@ -311,3 +311,37 @@ def setup_remote_pydev_debug():
             except:
                 LOG.exception(_(error_msg))
                 raise
    +
    +
    +class LimitingReader(object):
    +    """Reader to limit the size of an incoming request."""
    +    def __init__(self, data, limit):
    +        """
    +        :param data: Underlying data object
    +        :param limit: maximum number of bytes the reader should allow
    +        """
    +        self.data = data
    +        self.limit = limit
    +        self.bytes_read = 0
    +
    +    def __iter__(self):
    +        for chunk in self.data:
    +            self.bytes_read += len(chunk)
    +            if self.bytes_read > self.limit:
    +                raise exception.RequestTooLarge()
    +            else:
    +                yield chunk
    +
    +    def read(self, i):
    +        result = self.data.read(i)
    +        self.bytes_read += len(result)
    +        if self.bytes_read > self.limit:
    +            raise exception.RequestTooLarge()
    +        return result
    +
    +    def read(self):
    +        result = self.data.read()
    +        self.bytes_read += len(result)
    +        if self.bytes_read > self.limit:
    +            raise exception.RequestTooLarge()
    +        return result
    
  • keystone/config.py+2 0 modified
    @@ -137,6 +137,8 @@ def register_cli_int(*args, **kw):
     register_str('auth_admin_prefix', default='')
     register_str('policy_file', default='policy.json')
     register_str('policy_default_rule', default=None)
    +#default max request size is 112k
    +register_int('max_request_body_size', default=114688)
     
     #ssl options
     register_bool('enable', group='ssl', default=False)
    
  • keystone/exception.py+6 0 modified
    @@ -173,6 +173,12 @@ class Conflict(Error):
         title = 'Conflict'
     
     
    +class RequestTooLarge(Error):
    +    """Request is too large."""
    +    code = 413
    +    title = 'Request is too large.'
    +
    +
     class UnexpectedError(Error):
         """An unexpected error prevented the server from fulfilling your request.
     
    
  • keystone/middleware/core.py+21 0 modified
    @@ -14,7 +14,10 @@
     # License for the specific language governing permissions and limitations
     # under the License.
     
    +import webob.dec
    +
     from keystone.common import serializer
    +from keystone.common import utils
     from keystone.common import wsgi
     from keystone import config
     from keystone import exception
    @@ -164,3 +167,21 @@ def process_request(self, request):
             # Rewrites path to root if no path is given.
             elif not request.environ['PATH_INFO']:
                 request.environ['PATH_INFO'] = '/'
    +
    +
    +class RequestBodySizeLimiter(wsgi.Middleware):
    +    """Limit the size of an incoming request."""
    +
    +    def __init__(self, *args, **kwargs):
    +        super(RequestBodySizeLimiter, self).__init__(*args, **kwargs)
    +
    +    @webob.dec.wsgify(RequestClass=wsgi.Request)
    +    def __call__(self, req):
    +
    +        if req.content_length > CONF.max_request_body_size:
    +            raise exception.RequestTooLarge()
    +        if req.content_length is None and req.is_body_readable:
    +            limiter = utils.LimitingReader(req.body_file,
    +                                           CONF.max_request_body_size)
    +            req.body_file = limiter
    +        return self.application
    
  • tests/test_sizelimit.py+56 0 added
    @@ -0,0 +1,56 @@
    +# Copyright (c) 2013 OpenStack, LLC
    +#
    +#    Licensed under the Apache License, Version 2.0 (the "License"); you may
    +#    not use this file except in compliance with the License. You may obtain
    +#    a copy of the License at
    +#
    +#         http://www.apache.org/licenses/LICENSE-2.0
    +#
    +#    Unless required by applicable law or agreed to in writing, software
    +#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    +#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    +#    License for the specific language governing permissions and limitations
    +#    under the License.
    +
    +import webob
    +
    +from keystone import config
    +from keystone import exception
    +from keystone import middleware
    +from keystone import test
    +
    +CONF = config.CONF
    +MAX_REQUEST_BODY_SIZE = CONF.max_request_body_size
    +
    +
    +class TestRequestBodySizeLimiter(test.TestCase):
    +
    +    def setUp(self):
    +        super(TestRequestBodySizeLimiter, self).setUp()
    +
    +        @webob.dec.wsgify()
    +        def fake_app(req):
    +            return webob.Response(req.body)
    +
    +        self.middleware = middleware.RequestBodySizeLimiter(fake_app)
    +        self.request = webob.Request.blank('/', method='POST')
    +
    +    def test_content_length_acceptable(self):
    +        self.request.headers['Content-Length'] = MAX_REQUEST_BODY_SIZE
    +        self.request.body = "0" * MAX_REQUEST_BODY_SIZE
    +        response = self.request.get_response(self.middleware)
    +        self.assertEqual(response.status_int, 200)
    +
    +    def test_content_length_too_large(self):
    +        self.request.headers['Content-Length'] = MAX_REQUEST_BODY_SIZE + 1
    +        self.request.body = "0" * (MAX_REQUEST_BODY_SIZE + 1)
    +        self.assertRaises(exception.RequestTooLarge,
    +                          self.request.get_response,
    +                          self.middleware)
    +
    +    def test_request_too_large_no_content_length(self):
    +        self.request.body = "0" * (MAX_REQUEST_BODY_SIZE + 1)
    +        self.request.headers['Content-Length'] = None
    +        self.assertRaises(exception.RequestTooLarge,
    +                          self.request.get_response,
    +                          self.middleware)
    

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

9

News mentions

0

No linked articles in our index yet.