Skip to content

[Aikido] Fix 33 security issues in jinja2, flask, werkzeug and 2 more#19

Open
aikido-autofix[bot] wants to merge 1 commit intomasterfrom
fix/aikido-security-update-packages-17197158-3tFd
Open

[Aikido] Fix 33 security issues in jinja2, flask, werkzeug and 2 more#19
aikido-autofix[bot] wants to merge 1 commit intomasterfrom
fix/aikido-security-update-packages-17197158-3tFd

Conversation

@aikido-autofix
Copy link
Copy Markdown

@aikido-autofix aikido-autofix bot commented Feb 23, 2026

Upgrade Jinja2, Flask, Werkzeug, and Flask-CORS to fix multiple sandbox escape RCE vulnerabilities and privilege escalation issues. This update includes breaking changes that require manual migration.

⚠️ Code affected by breaking changes.

⚠️ This codebase has several breaking changes that will cause failures:

1. Python 2 to Python 3 incompatibility

  • Where affected:

    • requestbin/__init__.py:3 - Uses from cStringIO import StringIO (Python 2 only)

    • requestbin/filters.py:9,73,78,85,115 - Uses long type which doesn't exist in Python 3

    • requestbin/filters.py:115 - Uses unicode type which doesn't exist in Python 3

    • requestbin/models.py:58 - Uses xrange() which doesn't exist in Python 3

  • Impact: Code will fail with ImportError and NameError as these Python 2 constructs don't exist in Python 3. Flask 3.1.3, Werkzeug 3.1.6, and Jinja2 3.1.6 all require Python 3.8+.

  • Remediation: Replace cStringIO.StringIO with io.BytesIO, replace long with int, replace unicode with str, and replace xrange with range.

2. Werkzeug contrib.fixers.ProxyFix removed

  • Where affected: requestbin/__init__.py:42 - Imports from werkzeug.contrib.fixers import ProxyFix

  • Impact: werkzeug.contrib module was removed in Werkzeug 1.0+. This will cause an ImportError.

  • Remediation: Change import to from werkzeug.middleware.proxy_fix import ProxyFix.

3. Werkzeug request.values behavior change with GET requests

  • Where affected: requestbin/models.py:77 - Uses input.values[k] where input is a Flask/Werkzeug request object

  • Impact: In Werkzeug 2.0+, request.values does not include form data for GET requests. Since the code iterates over input.form and then accesses input.values[k], this may cause unexpected behavior or KeyError if the request method is GET.

  • Remediation: Use input.form[k] directly instead of input.values[k] since the code is already iterating over input.form.

4. Flask escape import location

  • Where affected: requestbin/views.py:2 - Imports escape from flask

  • Impact: In Flask 2.2+, escape should be imported from markuplib (MarkupSafe), not from Flask directly. While Flask may still provide it for backwards compatibility in 3.x, it's deprecated.

  • Remediation: Change import to from markupsafe import escape.

All breaking changes by upgrading jinja2 from version 2.7 to 3.1.6 (CHANGELOG)

Version Description
2.8.0
Added a check for default arguments followed by non-default arguments. This change makes {% macro m(x, y=1, z) %} a syntax error. The previous behavior for this code was broken anyway (resulting in the default value being applied to y).
2.9.0
Corrected a long standing issue with operator precedence of math operations not being what was expected.
2.9.0
Change the logic for macro autoescaping to be based on the runtime autoescaping information at call time instead of macro define time.
2.9.0
Tests now no longer accept an arbitrary expression as first argument but a restricted one.
2.9.0
Greatly changed the scoping system to be more consistent with what template designers and developers expect. There is now no more magic difference between the different include and import constructs.
2.10.0
import statement cannot end with a trailing comma.
2.10.0
indent filter will not indent blank lines by default.
2.11.0
Drop support for Python 2.6, 3.3, and 3.4.
2.11.0
The environment's finalize function is only applied to the output of expressions (constant or not), not static template data.
2.11.0
Always return Undefined when omitting the else clause in a {{ 'foo' if bar }} expression, regardless of the environment's undefined class.
2.11.0
Compiling templates always writes UTF-8 instead of defaulting to the system encoding.
3.0.0
Drop support for Python 2.7 and 3.5.
3.0.0
Bump MarkupSafe dependency to >=1.1.
3.0.0
Remove code that was marked deprecated.
3.0.0
The urlize filter recognizes mailto: links and takes extra_schemes to recognize other schemes. URLs without a scheme are linked as https:// instead of http://.
3.0.0
Undefined.__contains__ (in) raises an UndefinedError instead of a TypeError.
3.0.0
Template rendering only treats \n, \r\n and \r as line breaks. Other characters are left unchanged.
3.0.0
Async support no longer requires Jinja to patch itself. It must still be enabled with Environment(enable_async=True).
3.1.0
Drop support for Python 3.6.
3.1.0
Remove previously deprecated code including WithExtension and AutoEscapeExtension now built-in, contextfilter/contextfunction replaced by pass_context, evalcontextfilter/evalcontextfunction replaced by pass_eval_context, environmentfilter/environmentfunction replaced by pass_environment.
3.1.0
Markup and escape should be imported from MarkupSafe.
3.1.0
Compiled templates from very old Jinja versions may need to be recompiled.
3.1.0
Legacy resolve mode for Context subclasses is no longer supported. Override resolve_or_missing instead of resolve.
3.1.0
unicode_urlencode is renamed to url_quote.
3.1.0
The groupby filter is case-insensitive by default, matching other comparison filters.

All breaking changes by upgrading flask from version 0.10.1 to 3.1.3 (CHANGELOG)

Version Description
0.11.0
Templates are no longer automatically reloaded outside of debug mode. This can be configured with the new TEMPLATES_AUTO_RELOAD config key.
0.11.0
Removed deprecated module functionality.
0.11.0
Turn on autoescape for flask.templating.render_template_string by default.
0.12.0
Mimetype guessing and ETag generation for file-like objects in send_file has been removed.
0.12.0
Mimetype guessing in send_file now fails loudly and doesn't fall back to application/octet-stream.
1.0.0
Python 2.6 and 3.3 are no longer supported.
1.0.0
Bump minimum dependency versions to the latest stable versions: Werkzeug >= 0.14, Jinja >= 2.10, itsdangerous >= 0.24, Click >= 5.1.
1.0.0
Change the default for JSONIFY_PRETTYPRINT_REGULAR to False. jsonify returns a compact format by default, and an indented format in debug mode.
1.0.0
Flask.make_response raises TypeError instead of ValueError for bad response types.
1.0.0
TRAP_BAD_REQUEST_ERRORS is enabled by default in debug mode.
1.0.0
Removed error handler caching because it caused unexpected results for some exception inheritance hierarchies.
1.0.0
The following old deprecated code was removed: flask.ext, Flask.init_jinja_globals, Flask.error_handlers, Flask.request_globals_class, Flask.static_path, Request.module.
1.0.0
Flask.logger has been simplified. LOGGER_NAME and LOGGER_HANDLER_POLICY config was removed. The logger is always named flask.app.
1.0.0
Blueprint view function names may not contain dots.
1.0.0
Request.get_json no longer accepts arbitrary encodings. Incoming JSON should be encoded using UTF-8 per RFC 8259, but Flask will autodetect UTF-8, -16, or -32.
1.0.0
Subdomain matching is disabled by default and setting SERVER_NAME does not implicitly enable it. It can be enabled by passing subdomain_matching=True to the Flask constructor.
1.1.0
Bump minimum Werkzeug version to >= 0.15.
1.1.0
Drop support for Python 3.4.
1.1.0
Error handlers for InternalServerError or 500 will always be passed an instance of InternalServerError. If they are invoked due to an unhandled exception, that original exception is now available as e.original_exception rather than being passed directly to the handler.
1.1.0
Flask.logger takes the same name as Flask.name (the value passed as Flask(import_name)). This reverts 1.0's behavior of always logging to "flask.app".
2.1.0
Drop support for Python 3.6.
2.1.0
Update Click dependency to >= 8.0.
2.1.0
Remove previously deprecated code: The CLI does not pass script_info to app factory functions; config.from_json is replaced by config.from_file(name, load=json.load); json functions no longer take an encoding parameter; safe_join is removed; total_seconds is removed; The same blueprint cannot be registered with the same name; The test client's as_tuple parameter is removed.
2.2.0
Remove previously deprecated code: Old names for some send_file parameters have been removed (download_name replaces attachment_filename, max_age replaces cache_timeout, etag replaces add_etags); path replaces filename in send_from_directory; The RequestContext.g property returning AppContext.g is removed.
2.2.0
Update Werkzeug dependency to >= 2.2.
2.2.0
The app and request contexts are managed using Python context vars directly rather than Werkzeug's LocalStack.
2.2.0
before_first_request is deprecated.
2.2.0
Use Blueprint decorators and functions intended for setup after registering the blueprint will show a warning. In the next version, this will become an error.
2.3.0
Drop support for Python 3.7.
2.3.0
Update minimum requirements to the latest versions: Werkzeug>=2.3.0, Jinja2>3.1.2, itsdangerous>=2.1.2, click>=8.1.3.
2.3.0
Remove previously deprecated code: The push and pop methods of _app_ctx_stack and _request_ctx_stack are removed; FLASK_ENV environment variable, ENV config key, and app.env property are removed; session_cookie_name, send_file_max_age_default, use_x_sendfile, propagate_exceptions, and templates_auto_reload properties on app are removed; JSON_AS_ASCII, JSON_SORT_KEYS, JSONIFY_MIMETYPE, and JSONIFY_PRETTYPRINT_REGULAR config keys are removed; app.before_first_request and bp.before_app_first_request decorators are removed; json_encoder and json_decoder attributes on app and blueprint are removed; json.htmlsafe_dumps and htmlsafe_dump functions are removed.
2.3.0
Calling setup methods on blueprints after registration is an error instead of a warning.
2.3.0
blinker>=1.6.2 is a required dependency.
2.3.0
SESSION_COOKIE_DOMAIN does not fall back to SERVER_NAME. The default is not to set the domain.
3.0.0
Remove previously deprecated code.
3.0.0
Require Werkzeug >= 3.0.0.
3.1.0
Drop support for Python 3.8.
3.1.0
Update minimum dependency versions to latest feature releases: Werkzeug >= 3.1, ItsDangerous >= 2.2, Blinker >= 1.9.
3.1.0
Fix how setting host_matching=True or subdomain_matching=False interacts with SERVER_NAME. Setting SERVER_NAME no longer restricts requests to only that domain.
3.1.0
Request.trusted_hosts is checked during routing.

All breaking changes by upgrading werkzeug from version 0.9.3 to 3.1.6 (CHANGELOG)

Version Description
0.10.0
Use stdlib ssl module instead of OpenSSL for the builtin server. OpenSSL contexts are not supported anymore, but instead ssl.SSLContext from the stdlib.
0.10.0
wrappers.Request.method is now always uppercase, eliminating inconsistencies of the WSGI environment.
0.11.0
mimetype parameters on request and response classes are now always converted to lowercase.
0.11.0
Changed cache so that cache never expires if timeout is 0. This also fixes an issue with redis setex.
0.12.0
The defaults of generate_password_hash have been changed to more secure ones.
0.12.0
Change Accept datastructure to sort by specificity first, allowing for more accurate results when using best_match for mime types.
0.13.0
response.age is parsed as a timedelta. Previously, it was incorrectly treated as a datetime.
0.13.0
Authorization.qop is a string instead of a set, to comply with RFC 2617.
0.13.0
An exception is raised when an encoded cookie is larger than, by default, 4093 bytes.
0.14.0
HTTP exceptions are now automatically caught by Request.application.
0.14.0
get_multi on cache clients now returns lists all the time.
0.14.0
The built-in HTTP server will no longer close a connection in cases where no HTTP body is expected (204, 204, HEAD requests etc.)
0.14.0
Werkzeug will no longer send the content-length header on 1xx or 204/304 responses.
0.16.0
Request cookies are parsed into a MultiDict to capture all values for cookies with the same key. cookies[key] returns the first value rather than the last.
0.16.0
Map and Rule have a merge_slashes option to collapse multiple slashes into one, similar to how many HTTP servers behave. This is enabled by default.
0.16.0
Range requests that span an entire file respond with 206 instead of 200, to be more compliant with RFC 7233.
0.16.0
The SharedDataMiddleware default fallback_mimetype is application/octet-stream. If a filename looks like a text mimetype, the utf-8 charset is added to it.
1.0.0
Drop support for Python 3.4.
2.0.0
Drop support for Python 2 and 3.5.
2.0.0
All datetime values are timezone-aware with tzinfo=timezone.utc.
2.0.0
Merge all request and response wrapper mixin code into single Request and Response classes. Using the mixin classes is no longer necessary and will show a deprecation warning.
2.0.0
Response.get_json() no longer caches the result, and the cache parameter is removed.
2.0.0
Response.freeze() generates an ETag header if one is not set. The no_etag parameter is no longer used.
2.0.0
The response generated by Unauthorized produces one WWW-Authenticate header per value in www_authenticate, rather than joining them into a single value.
2.0.0
Switch the parameter order of default_stream_factory to match the order used when calling it.
2.0.0
send_file sets conditional=True and max_age=None by default. Cache-Control is set to no-cache if max_age is not set, otherwise public.
2.0.0
Update the defaults used by generate_password_hash. Increase PBKDF2 iterations to 260000 from 150000. Increase salt length to 16 from 8.
2.0.0
The test Client request methods always return an instance of TestResponse. In addition to the normal behavior of Response, this class provides request with the request that produced the response, and history to track intermediate responses when follow_redirects is used.
2.0.0
Cookie names are no longer unquoted. This was against RFC 6265 and potentially allowed setting __Secure prefixed cookies.
2.0.0
Use SHA-1 instead of MD5 for generating ETags and the debugger pin, and in some tests.
2.0.0
LocalProxy matches the current Python data model special methods, including all r-ops, in-place ops, and async. __class__ is proxied, so the proxy will look like the object in more cases, including isinstance. Use issubclass(type(obj), LocalProxy) to check if an object is actually a proxy.
2.0.0
Local uses ContextVar on Python 3.7+ instead of threading.local.
2.0.0
request.values does not include form for GET requests.
2.1.0
Drop support for Python 3.6.
2.1.0
Using gevent or eventlet requires greenlet>=1.0 or PyPy>=7.3.7.
2.1.0
When passing a dict of URL values to Map.build, list values do not filter out None or collapse to a single value. Passing a MultiDict does collapse single items.
2.1.0
The development server uses HTTP/1.1, which enables keep-alive connections and chunked streaming responses, when threaded or processes is enabled.
2.1.0
The default status code for append_slash_redirect is 308 instead of 301.
2.1.0
Response.autocorrect_location_header is disabled by default. The Location header URL will remain relative, and exclude the scheme and domain, by default.
2.1.0
Request.get_json() will raise a 400 BadRequest error if the Content-Type header is not application/json.
2.2.0
If a custom converter needs to match a / it must set the class variable part_isolating = False.
2.3.0
Drop support for Python 3.7.
2.3.0
Request.get_json() will raise a 415 Unsupported Media Type error if the Content-Type header is not application/json, instead of a generic 400.
2.3.0
A URL converter's part_isolating defaults to False if its regex contains a /.
2.3.0
Increase default work factor for PBKDF2 to 600,000 iterations.
...

All breaking changes by upgrading flask-cors from version 3.0.2 to 6.0.0 (CHANGELOG)

Version Description
4.0.0
Remove support for Python versions older than 3.8
5.0.0
Change default to disable private network access
6.0.0
Path specificity ordering has changed to improve specificity, which may break users who expected the previous incorrect ordering
6.0.0
Replace use of (urllib) unquote_plus with unquote, changing URL decoding behavior
6.0.0
Request path matching is now case sensitive

All breaking changes by upgrading Flask-Cors from version 3.0.2 to 4.0.1 (CHANGELOG)

Version Description
4.0.0
Remove support for Python versions older than 3.8
✅ 33 CVEs resolved by this upgrade

This PR will resolve the following CVEs:

Issue Severity           Description
CVE-2025-27516
HIGH
[jinja2] Sandbox bypass in the
CVE-2016-10745
HIGH
[jinja2] In Pallets Jinja before 2.8.1, str.format allows a sandbox escape.
CVE-2019-10906
HIGH
[jinja2] In Pallets Jinja before 2.10.1, str.format_map allows a sandbox escape.
CVE-2014-1402
HIGH
[jinja2] The default configuration for bccache.FileSystemBytecodeCache in Jinja2 before 2.7.2 does not properly create temporary files, which allows local users to gain privileges via a crafted .cache file with a name starting with _jinja2 in /tmp.
CVE-2024-56326
HIGH
[jinja2] Sandbox bypass in template processing allows arbitrary Python code execution through indirect calls to str.format via custom filters when an attacker controls template content.
CVE-2014-0012
MEDIUM
[jinja2] FileSystemBytecodeCache in Jinja2 2.7.2 does not properly create temporary directories, which allows local users to gain privileges by pre-creating a temporary directory with a user's uid. NOTE: this vulnerability exists because of an incomplete fix for CVE-2014-1402.
CVE-2024-22195
MEDIUM
[jinja2] The xmlattr filter can be abused to inject arbitrary HTML attributes, bypassing auto-escaping and enabling Cross-Site Scripting (XSS) attacks and potential attribute validation bypass.
CVE-2024-34064
MEDIUM
[jinja2] The xmlattr filter fails to properly sanitize attribute keys, allowing injection of special characters (/, >, =) that enable XSS attacks when user-controlled keys are rendered in XML/HTML attributes.
CVE-2020-28493
LOW
[jinja2] A ReDoS vulnerability in the urlize filter's _punctuation_re regex allows attackers to cause denial of service through specially crafted input with multiple wildcards. Mitigation includes using Markdown for user content formatting or implementing request timeouts and memory limits.
CVE-2023-30861
HIGH
[flask] A caching proxy vulnerability allows session cookies to be cached and sent to unintended clients when specific conditions align, including permanent sessions, no session access during requests, and missing cache-control headers. This can lead to information disclosure or session hijacking depending on application behavior and proxy configuration.
CVE-2018-1000656
HIGH
[flask] Improper input validation in JSON parsing allows attackers to provide malformed JSON data in incorrect encoding, causing excessive memory consumption and leading to denial of service attacks.
CVE-2019-1010083
HIGH
[flask] The Pallets Project Flask before 1.0 is affected by: unexpected memory usage. The impact is: denial of service. The attack vector is: crafted encoded JSON data. The fixed version is: 1. NOTE: this may overlap CVE-2018-1000656.
CVE-2026-27205
MEDIUM
[flask] A vulnerability in session object access fails to set the Vary: Cookie header in certain cases, allowing sensitive user-specific information to be cached by proxies. This can lead to information disclosure when applications access sessions through specific methods like the Python in operator without proper cache control headers.
CVE-2019-14322
HIGH
[werkzeug] In Pallets Werkzeug before 0.15.5, SharedDataMiddleware mishandles drive names (such as C:) in Windows pathnames.
CVE-2023-46136
HIGH
[werkzeug] A denial of service vulnerability exists in multipart data parsing where crafted uploads with CR/LF followed by large data cause inefficient buffer operations, consuming excessive CPU and blocking worker processes from handling legitimate requests.
CVE-2019-14806
HIGH
[werkzeug] Pallets Werkzeug before 0.15.3, when used with Docker, has insufficient debugger PIN randomness because Docker containers share the same machine id.
CVE-2023-25577
HIGH
[werkzeug] The multipart form data parser accepts unlimited parts without restriction, allowing attackers to cause denial of service through excessive CPU and memory consumption. Sending crafted multipart requests to endpoints accessing form/file data can exhaust worker processes and trigger out-of-memory conditions.
CVE-2024-34069
HIGH
[werkzeug] The debugger can be exploited for remote code execution if an attacker tricks a developer into visiting a controlled domain and entering the debugger PIN, then guesses a URL that triggers the debugger. This bypasses localhost-only protections.
CVE-2024-49767
HIGH
[werkzeug] The MultiPartParser is vulnerable to a resource exhaustion denial of service attack where specially crafted multipart form submissions cause excessive memory allocation, consuming 3-8x the upload size in RAM with no upper limit.
CVE-2016-10516
MEDIUM
[werkzeug] A cross-site scripting (XSS) vulnerability in the debugger's render_full function allows remote attackers to inject arbitrary web script or HTML through exception messages. This enables attackers to execute malicious code in users' browsers when viewing debug information.
CVE-2020-28724
MEDIUM
[werkzeug] Open redirect vulnerability in werkzeug before 0.11.6 via a double slash in the URL.
CVE-2026-27199
MEDIUM
[werkzeug] A path traversal vulnerability in the safe_join function allows Windows device names (like NUL) as filenames when preceded by path segments, causing file read operations to hang indefinitely when serving files through send_from_directory on Windows systems. This bypasses previous security filtering that didn't account for multi-segment paths.
CVE-2024-49766
MEDIUM
[werkzeug] safe_join() fails to properly validate UNC paths on Windows with Python < 3.11, allowing directory traversal and unintended file access. This vulnerability enables attackers to bypass path security checks and access sensitive data outside intended directories.
CVE-2025-66221
MEDIUM
[werkzeug] The safe_join function fails to block Windows device names (CON, AUX, etc.), allowing attackers to request these special paths through send_from_directory, causing indefinite hangs when reading files on Windows systems (Denial of Service).
CVE-2026-21860
MEDIUM
[werkzeug] The safe_join function fails to properly validate Windows device names with file extensions or trailing spaces (e.g., CON.txt, AUX ), allowing attackers to bypass path restrictions and access special device files on Windows systems.
CVE-2023-23934
LOW
[werkzeug] A cookie parsing vulnerability allows adjacent subdomains to set malicious cookies with valid-looking names by exploiting nameless cookie handling, potentially bypassing cookie security protections. An attacker on a compromised subdomain could inject cookies into a Werkzeug application, leading to authentication bypass or session hijacking.
CVE-2020-25032
HIGH
[flask-cors] An issue was discovered in Flask-CORS (aka CORS Middleware for Flask) before 3.0.9. It allows ../ directory traversal to access private resources because resource matching does not ensure that pathnames are in a canonical format.
CVE-2024-6221
HIGH
[flask-cors] A default configuration vulnerability allows the Access-Control-Allow-Private-Network CORS header to be set to true without explicit configuration, potentially exposing private network resources to unauthorized external access and enabling data breaches or network intrusions.
CVE-2024-6866
HIGH
[flask-cors] Case-insensitive path matching in CORS request validation allows unauthorized origins to bypass path-based access restrictions, enabling unauthorized access to protected resources and potential data exposure.
CVE-2024-1681
MEDIUM
[flask-cors] A log injection vulnerability allows attackers to inject fake log entries by sending requests with CRLF sequences in the path, enabling log file corruption and potential obfuscation of attack traces when debug logging is enabled.
CVE-2024-6839
MEDIUM
[flask-cors] Improper regex path matching allows less restrictive CORS policies to be applied to sensitive endpoints, enabling unauthorized cross-origin access to sensitive data and functionality.
CVE-2024-6844
MEDIUM
[flask-cors] CORS policy bypass vulnerability due to improper URL path normalization where '+' characters are converted to spaces, causing endpoints to be matched incorrectly against CORS configurations and potentially allowing unauthorized cross-origin access.
AIKIDO-2024-10084
MEDIUM
[Flask-Cors] A log injection vulnerability allows attackers to inject fake log entries by sending requests with CRLF sequences in the path, enabling log file corruption and covering attack tracks when debug logging is enabled.

@aikido-autofix aikido-autofix bot added the security Label created by Aikido AutoFix label Feb 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

security Label created by Aikido AutoFix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants