From 0776bf0428c3cfeca3528c3bb03941034c83f34c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 3 Feb 2024 05:24:02 -0700 Subject: [PATCH 1/5] Bump jinja2 from 2.11.3 to 3.1.3 (#76) Bumps [jinja2](https://github.com/pallets/jinja) from 2.11.3 to 3.1.3. - [Release notes](https://github.com/pallets/jinja/releases) - [Changelog](https://github.com/pallets/jinja/blob/main/CHANGES.rst) - [Commits](https://github.com/pallets/jinja/compare/2.11.3...3.1.3) --- updated-dependencies: - dependency-name: jinja2 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs_requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs_requirements.txt b/docs_requirements.txt index 44993e5..fccc00d 100644 --- a/docs_requirements.txt +++ b/docs_requirements.txt @@ -1,4 +1,4 @@ -Jinja2==2.11.3 +Jinja2==3.1.3 PyYAML==5.4 Pygments==2.15.0 Sphinx==1.2b1 From c2eea36cc8fc3fc4b53e3b4f60dbc433601c4e08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 9 Feb 2024 17:25:22 +0100 Subject: [PATCH 2/5] =?UTF-8?q?=E2=9C=85=20Add=20ReDos=20check=20test=20(#?= =?UTF-8?q?81)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_multipart.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/test_multipart.py b/tests/test_multipart.py index 031515b..2ceecab 100644 --- a/tests/test_multipart.py +++ b/tests/test_multipart.py @@ -270,6 +270,11 @@ def test_handles_ie6_bug(self): t, p = parse_options_header(b'text/plain; filename="C:\\this\\is\\a\\path\\file.txt"') self.assertEqual(p[b'filename'], b'file.txt') + + def test_redos_attack_header(self): + t, p = parse_options_header(b'application/x-www-form-urlencoded; !="\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\') + # If vulnerable, this test wouldn't finish, the line above would hang + self.assertIn(b'"\\', p[b'!']) class TestBaseParser(unittest.TestCase): From cb0b7cf60e3e3c9f5854686d7725960ff77b7301 Mon Sep 17 00:00:00 2001 From: Konstantinos Tselepakis Date: Fri, 9 Feb 2024 23:44:31 +0200 Subject: [PATCH 3/5] Cleanup unused regex patterns (#82) --- multipart/multipart.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/multipart/multipart.py b/multipart/multipart.py index e1d10fc..6ec1364 100644 --- a/multipart/multipart.py +++ b/multipart/multipart.py @@ -2,7 +2,6 @@ from .exceptions import * import os -import re import sys import shutil import logging @@ -67,16 +66,6 @@ ord_char = lambda c: c join_bytes = lambda b: bytes(list(b)) -# These are regexes for parsing header values. -SPECIAL_CHARS = re.escape(b'()<>@,;:\\"/[]?={} \t') -QUOTED_STR = br'"(?:\\.|[^"])*"' -VALUE_STR = br'(?:[^' + SPECIAL_CHARS + br']+|' + QUOTED_STR + br')' -OPTION_RE_STR = ( - br'(?:;|^)\s*([^' + SPECIAL_CHARS + br']+)\s*=\s*(' + VALUE_STR + br')' -) -OPTION_RE = re.compile(OPTION_RE_STR) -QUOTE = b'"'[0] - def parse_options_header(value: Union[str, bytes]) -> Tuple[bytes, Dict[bytes, bytes]]: """ From 26d664f277a330bb63ee03820d8c2f6f1bbf951a Mon Sep 17 00:00:00 2001 From: lorenpike <55057781+lorenpike@users.noreply.github.com> Date: Fri, 9 Feb 2024 16:45:33 -0500 Subject: [PATCH 4/5] Check if `Message.get_params` return 3-`tuple` instead of `str` on `parse_options_header` (#79) * Fixing issue #78 * Added test for parse_options_header * Added a comment clarifying a condition in parse_options_header * Fixed a typo --------- Co-authored-by: lorenpike --- multipart/multipart.py | 5 +++++ tests/test_multipart.py | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/multipart/multipart.py b/multipart/multipart.py index 6ec1364..73910da 100644 --- a/multipart/multipart.py +++ b/multipart/multipart.py @@ -99,6 +99,11 @@ def parse_options_header(value: Union[str, bytes]) -> Tuple[bytes, Dict[bytes, b options = {} for param in params: key, value = param + # If the value returned from get_params() is a 3-tuple, the last + # element corresponds to the value. + # See: https://docs.python.org/3/library/email.compat32-message.html + if isinstance(value, tuple): + value = value[-1] # If the value is a filename, we need to fix a bug on IE6 that sends # the full file path instead of the filename. if key == 'filename': diff --git a/tests/test_multipart.py b/tests/test_multipart.py index 2ceecab..5cfacf4 100644 --- a/tests/test_multipart.py +++ b/tests/test_multipart.py @@ -276,6 +276,11 @@ def test_redos_attack_header(self): # If vulnerable, this test wouldn't finish, the line above would hang self.assertIn(b'"\\', p[b'!']) + def test_handles_rfc_2231(self): + t, p = parse_options_header(b'text/plain; param*=us-ascii\'en-us\'encoded%20message') + + self.assertEqual(p[b'param'], b'encoded message') + class TestBaseParser(unittest.TestCase): def setUp(self): From 8ce342cd9ac03fe238c24d68cffaf25a7ea0371a Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Fri, 9 Feb 2024 22:52:41 +0100 Subject: [PATCH 5/5] Version 0.0.8 (#83) --- CHANGELOG.md | 5 +++++ multipart/__init__.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c77841..3d6f080 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## 0.0.8 (2024-02-09) + +* Check if Message.get_params return 3-tuple instead of str on parse_options_header [#79](https://github.com/Kludex/python-multipart/pull/79). +* Cleanup unused regex patterns [#82](https://github.com/Kludex/python-multipart/pull/82). + ## 0.0.7 (2024-02-03) * Refactor header option parser to use the standard library instead of a custom RegEx [#75](https://github.com/andrew-d/python-multipart/pull/75). diff --git a/multipart/__init__.py b/multipart/__init__.py index e8b163a..28c7ad6 100644 --- a/multipart/__init__.py +++ b/multipart/__init__.py @@ -2,7 +2,7 @@ __author__ = "Andrew Dunham" __license__ = "Apache" __copyright__ = "Copyright (c) 2012-2013, Andrew Dunham" -__version__ = "0.0.7" +__version__ = "0.0.8" from .multipart import (