VYPR
High severityNVD Advisory· Published Aug 18, 2024· Updated Apr 7, 2025

Improper Access Control in corydolphin/flask-cors

CVE-2024-6221

Description

A vulnerability in corydolphin/flask-cors version 4.0.1 allows the Access-Control-Allow-Private-Network CORS header to be set to true by default. This behavior can expose private network resources to unauthorized external access, leading to significant security risks such as data breaches, unauthorized access to sensitive information, and potential network intrusions.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
Flask-CorsPyPI
< 4.0.24.0.2

Affected products

1

Patches

3
c8514760cf03

V5: Breaking: Change default to disable private network access (#368)

https://github.com/corydolphin/flask-corsCory DolphinAug 30, 2024via ghsa
4 files changed · +17 17
  • docs/configuration.rst+14 14 modified
    @@ -54,37 +54,37 @@ CORS_INTERCEPT_EXCEPTIONS (:py:class:`bool`)
        Whether to deal with Flask exception handlers or leave them alone (with respect to CORS headers).
     
     CORS_MAX_AGE (:py:class:`~datetime.timedelta`, :py:class:`int` or :py:class:`str`)
    -   The maximum time for which this CORS request may be cached. 
    +   The maximum time for which this CORS request may be cached.
        This value is set as the :http:header:`Access-Control-Max-Age` header.
     
     CORS_METHODS (:py:class:`~typing.List` or :py:class:`str`)
        The method(s) which the allowed origins are allowed to access.
        These are included in the :http:header:`Access-Control-Allow-Methods` response headers to the preflight OPTIONS requests.
    -   
    +
     .. _cors_origins_setting:
     
     CORS_ORIGINS (:py:class:`~typing.List`, :py:class:`str` or :py:class:`re.Pattern`)
        The origin(s) to allow requests from.
        An origin configured here that matches the value of the :http:header:`Origin` header in a preflight OPTIONS request is returned as the value of the :http:header:`Access-Control-Allow-Origin` response header.
     
     CORS_RESOURCES (:py:class:`~typing.Dict`, :py:class:`~typing.List` or :py:class:`str`)
    -   The series of regular expression and (optionally) associated CORS options to be applied to the given resource path.                       
    -   
    +   The series of regular expression and (optionally) associated CORS options to be applied to the given resource path.
    +
        If the value is a dictionary, it's keys must be regular expressions matching resources, and the values must be another dictionary of configuration options, as described in this section.
    -   
    -   If the argument is a list, it is expected to be a list of regular expressions matching resources for which the app-wide configured options are applied.     
    -   
    -   If the argument is a string, it is expected to be a regular expression matching resources for which the app-wide configured options are applied.        
    +
    +   If the argument is a list, it is expected to be a list of regular expressions matching resources for which the app-wide configured options are applied.
    +
    +   If the argument is a string, it is expected to be a regular expression matching resources for which the app-wide configured options are applied.
     
     CORS_SEND_WILDCARD (:py:class:`bool`)
        If :ref:`CORS_ORIGINS <cors_origins_setting>` is ``"*"`` and this is true, then the :http:header:`Access-Control-Allow-Origin` response header's value with be ``"*"`` as well, instead of the value of the :http:header:`Origin` request header.
     
     CORS_SUPPORTS_CREDENTIALS (:py:class:`bool`)
    -   Allows users to make authenticated requests. 
    -   If true, injects the :http:header:`Access-Control-Allow-Credentials` header in responses. 
    -   This allows cookies and credentials to be submitted across domains.                 
    -   
    -   :note: This option cannot be used in conjunction with a "*" origin  
    +   Allows users to make authenticated requests.
    +   If true, injects the :http:header:`Access-Control-Allow-Credentials` header in responses.
    +   This allows cookies and credentials to be submitted across domains.
    +
    +   :note: This option cannot be used in conjunction with a "*" origin
     
     CORS_VARY_HEADER: (:py:class:`bool`)
        Enables or disables the injection of the :http:header:`Vary` response header is set to ``Origin``.
    @@ -96,7 +96,7 @@ Default values
     ~~~~~~~~~~~~~~
     
     * CORS_ALLOW_HEADERS: "*"
    -* CORS_ALLOW_PRIVATE_NETWORK: True
    +* CORS_ALLOW_PRIVATE_NETWORK: False
     * CORS_ALWAYS_SEND: True
     * CORS_AUTOMATIC_OPTIONS: True
     * CORS_EXPOSE_HEADERS: None
    
  • flask_cors/core.py+1 1 modified
    @@ -57,7 +57,7 @@
                            resources=r'/*',
                            intercept_exceptions=True,
                            always_send=True,
    -                       allow_private_network=True)
    +                       allow_private_network=False)
     
     
     def parse_resources(resources):
    
  • flask_cors/version.py+1 1 modified
    @@ -1 +1 @@
    -__version__ = '4.0.2'
    +__version__ = '5.0.0'
    
  • tests/decorator/test_private_network_headers.py+1 1 modified
    @@ -37,7 +37,7 @@ def test_default(self):
             """ The default behavior should be to allow private network access.
             """
             resp = self.get('/test_default', origin='www.example.com', headers={ACL_REQUEST_HEADER_PRIVATE_NETWORK:'true'})
    -        self.assertTrue(ACL_RESPONSE_PRIVATE_NETWORK in resp.headers)
    +        self.assertFalse(resp.headers.get('ACL_RESPONSE_PRIVATE_NETWORK'))
     
             resp = self.get('/test_default')
             self.assertFalse(ACL_RESPONSE_PRIVATE_NETWORK in resp.headers)
    
03aa3f8e2256

V5: Breaking: Change default to disable private network access

https://github.com/corydolphin/flask-corsCory DolphinAug 30, 2024via ghsa
4 files changed · +17 17
  • docs/configuration.rst+14 14 modified
    @@ -54,37 +54,37 @@ CORS_INTERCEPT_EXCEPTIONS (:py:class:`bool`)
        Whether to deal with Flask exception handlers or leave them alone (with respect to CORS headers).
     
     CORS_MAX_AGE (:py:class:`~datetime.timedelta`, :py:class:`int` or :py:class:`str`)
    -   The maximum time for which this CORS request may be cached. 
    +   The maximum time for which this CORS request may be cached.
        This value is set as the :http:header:`Access-Control-Max-Age` header.
     
     CORS_METHODS (:py:class:`~typing.List` or :py:class:`str`)
        The method(s) which the allowed origins are allowed to access.
        These are included in the :http:header:`Access-Control-Allow-Methods` response headers to the preflight OPTIONS requests.
    -   
    +
     .. _cors_origins_setting:
     
     CORS_ORIGINS (:py:class:`~typing.List`, :py:class:`str` or :py:class:`re.Pattern`)
        The origin(s) to allow requests from.
        An origin configured here that matches the value of the :http:header:`Origin` header in a preflight OPTIONS request is returned as the value of the :http:header:`Access-Control-Allow-Origin` response header.
     
     CORS_RESOURCES (:py:class:`~typing.Dict`, :py:class:`~typing.List` or :py:class:`str`)
    -   The series of regular expression and (optionally) associated CORS options to be applied to the given resource path.                       
    -   
    +   The series of regular expression and (optionally) associated CORS options to be applied to the given resource path.
    +
        If the value is a dictionary, it's keys must be regular expressions matching resources, and the values must be another dictionary of configuration options, as described in this section.
    -   
    -   If the argument is a list, it is expected to be a list of regular expressions matching resources for which the app-wide configured options are applied.     
    -   
    -   If the argument is a string, it is expected to be a regular expression matching resources for which the app-wide configured options are applied.        
    +
    +   If the argument is a list, it is expected to be a list of regular expressions matching resources for which the app-wide configured options are applied.
    +
    +   If the argument is a string, it is expected to be a regular expression matching resources for which the app-wide configured options are applied.
     
     CORS_SEND_WILDCARD (:py:class:`bool`)
        If :ref:`CORS_ORIGINS <cors_origins_setting>` is ``"*"`` and this is true, then the :http:header:`Access-Control-Allow-Origin` response header's value with be ``"*"`` as well, instead of the value of the :http:header:`Origin` request header.
     
     CORS_SUPPORTS_CREDENTIALS (:py:class:`bool`)
    -   Allows users to make authenticated requests. 
    -   If true, injects the :http:header:`Access-Control-Allow-Credentials` header in responses. 
    -   This allows cookies and credentials to be submitted across domains.                 
    -   
    -   :note: This option cannot be used in conjunction with a "*" origin  
    +   Allows users to make authenticated requests.
    +   If true, injects the :http:header:`Access-Control-Allow-Credentials` header in responses.
    +   This allows cookies and credentials to be submitted across domains.
    +
    +   :note: This option cannot be used in conjunction with a "*" origin
     
     CORS_VARY_HEADER: (:py:class:`bool`)
        Enables or disables the injection of the :http:header:`Vary` response header is set to ``Origin``.
    @@ -96,7 +96,7 @@ Default values
     ~~~~~~~~~~~~~~
     
     * CORS_ALLOW_HEADERS: "*"
    -* CORS_ALLOW_PRIVATE_NETWORK: True
    +* CORS_ALLOW_PRIVATE_NETWORK: False
     * CORS_ALWAYS_SEND: True
     * CORS_AUTOMATIC_OPTIONS: True
     * CORS_EXPOSE_HEADERS: None
    
  • flask_cors/core.py+1 1 modified
    @@ -57,7 +57,7 @@
                            resources=r'/*',
                            intercept_exceptions=True,
                            always_send=True,
    -                       allow_private_network=True)
    +                       allow_private_network=False)
     
     
     def parse_resources(resources):
    
  • flask_cors/version.py+1 1 modified
    @@ -1 +1 @@
    -__version__ = '4.0.2'
    +__version__ = '5.0.0'
    
  • tests/decorator/test_private_network_headers.py+1 1 modified
    @@ -37,7 +37,7 @@ def test_default(self):
             """ The default behavior should be to allow private network access.
             """
             resp = self.get('/test_default', origin='www.example.com', headers={ACL_REQUEST_HEADER_PRIVATE_NETWORK:'true'})
    -        self.assertTrue(ACL_RESPONSE_PRIVATE_NETWORK in resp.headers)
    +        self.assertFalse(resp.headers.get('ACL_RESPONSE_PRIVATE_NETWORK'))
     
             resp = self.get('/test_default')
             self.assertFalse(ACL_RESPONSE_PRIVATE_NETWORK in resp.headers)
    
7ae310c56ac3

Backwards Compatible Fix for CVE-2024-6221 (#363)

https://github.com/corydolphin/flask-corsAdriano Sela AvilesAug 30, 2024via ghsa
4 files changed · +36 4
  • docs/configuration.rst+14 0 modified
    @@ -23,6 +23,19 @@ CORS_ALLOW_HEADERS (:py:class:`~typing.List` or :py:class:`str`)
        Headers to accept from the client.
        Headers in the :http:header:`Access-Control-Request-Headers` request header (usually part of the preflight OPTIONS request) matching headers in this list will be included in the :http:header:`Access-Control-Allow-Headers` response header.
     
    +CORS_ALLOW_PRIVATE_NETWORK (:py:class:`bool`)
    +   If True, the response header :http:header:`Access-Control-Allow-Private-Network`
    +   will be set with the value 'true' whenever the request header
    +   :http:header:`Access-Control-Request-Private-Network` has a value 'true'.
    +
    +   If False, the reponse header :http:header:`Access-Control-Allow-Private-Network`
    +   will be set with the value 'false' whenever the request header
    +   :http:header:`Access-Control-Request-Private-Network` has a value of 'true'.
    +
    +   If the request header :http:header:`Access-Control-Request-Private-Network` is
    +   not present or has a value other than 'true', the response header
    +   :http:header:`Access-Control-Allow-Private-Network` will not be set.
    +
     CORS_ALWAYS_SEND (:py:class:`bool`)
        Usually, if a request doesn't include an :http:header:`Origin` header, the client did not request CORS.
        This means we can ignore this request.
    @@ -83,6 +96,7 @@ Default values
     ~~~~~~~~~~~~~~
     
     * CORS_ALLOW_HEADERS: "*"
    +* CORS_ALLOW_PRIVATE_NETWORK: True
     * CORS_ALWAYS_SEND: True
     * CORS_AUTOMATIC_OPTIONS: True
     * CORS_EXPOSE_HEADERS: None
    
  • flask_cors/core.py+5 3 modified
    @@ -36,7 +36,7 @@
                       'CORS_MAX_AGE', 'CORS_SEND_WILDCARD',
                       'CORS_AUTOMATIC_OPTIONS', 'CORS_VARY_HEADER',
                       'CORS_RESOURCES', 'CORS_INTERCEPT_EXCEPTIONS',
    -                  'CORS_ALWAYS_SEND']
    +                  'CORS_ALWAYS_SEND', 'CORS_ALLOW_PRIVATE_NETWORK']
     # Attribute added to request object by decorator to indicate that CORS
     # was evaluated, in case the decorator and extension are both applied
     # to a view.
    @@ -56,7 +56,8 @@
                            vary_header=True,
                            resources=r'/*',
                            intercept_exceptions=True,
    -                       always_send=True)
    +                       always_send=True,
    +                       allow_private_network=True)
     
     
     def parse_resources(resources):
    @@ -186,7 +187,8 @@ def get_cors_headers(options, request_headers, request_method):
     
         if ACL_REQUEST_HEADER_PRIVATE_NETWORK in request_headers \
                 and request_headers.get(ACL_REQUEST_HEADER_PRIVATE_NETWORK) == 'true':
    -        headers[ACL_RESPONSE_PRIVATE_NETWORK] = 'true'
    +        allow_private_network = 'true' if options.get('allow_private_network') else 'false'
    +        headers[ACL_RESPONSE_PRIVATE_NETWORK] = allow_private_network
     
         # This is a preflight request
         # http://www.w3.org/TR/cors/#resource-preflight-requests
    
  • flask_cors/extension.py+16 0 modified
    @@ -138,6 +138,22 @@ class CORS(object):
     
             Default : True
         :type vary_header: bool
    +
    +    :param allow_private_network:
    +        If True, the response header `Access-Control-Allow-Private-Network`
    +        will be set with the value 'true' whenever the request header
    +        `Access-Control-Request-Private-Network` has a value 'true'.
    +
    +        If False, the reponse header `Access-Control-Allow-Private-Network`
    +        will be set with the value 'false' whenever the request header
    +        `Access-Control-Request-Private-Network` has a value of 'true'.
    +
    +        If the request header `Access-Control-Request-Private-Network` is
    +        not present or has a value other than 'true', the response header
    +        `Access-Control-Allow-Private-Network` will not be set.
    +
    +        Default : True
    +    :type allow_private_network: bool
         """
     
         def __init__(self, app=None, **kwargs):
    
  • flask_cors/version.py+1 1 modified
    @@ -1 +1 @@
    -__version__ = '4.0.1'
    +__version__ = '4.0.2'
    

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

10

News mentions

0

No linked articles in our index yet.