From 3b0169bcc20ce29483e9349cad378450857f3f76 Mon Sep 17 00:00:00 2001 From: Benedikt Johannes Date: Sat, 31 Jan 2026 22:26:50 +0100 Subject: [PATCH 1/3] Disallow usage of control characters in status, headers and values for security --- Lib/wsgiref/handlers.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Lib/wsgiref/handlers.py b/Lib/wsgiref/handlers.py index 9353fb678625b3..ab8eca177dd477 100644 --- a/Lib/wsgiref/handlers.py +++ b/Lib/wsgiref/handlers.py @@ -16,6 +16,9 @@ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] +_name_disallowed = re.compile(r'[\x00-\x1F\x7F]') +_value_disallowed = re.compile(r'[\x00-\x08\x0A-\x1F\x7F]') + def format_date_time(timestamp): year, month, day, hh, mm, ss, wd, y, z = time.gmtime(timestamp) return "%s, %02d %3s %4d %02d:%02d:%02d GMT" % ( @@ -237,13 +240,13 @@ def start_response(self, status, headers,exc_info=None): self.status = status self.headers = self.headers_class(headers) - status = self._convert_string_type(status, "Status") + status = self._convert_string_type(status, "Status", name=False) self._validate_status(status) if __debug__: for name, val in headers: - name = self._convert_string_type(name, "Header name") - val = self._convert_string_type(val, "Header value") + name = self._convert_string_type(name, "Header name", name=True) + val = self._convert_string_type(val, "Header value", name=False) assert not is_hop_by_hop(name),\ f"Hop-by-hop header, '{name}: {val}', not allowed" @@ -257,9 +260,11 @@ def _validate_status(self, status): if status[3] != " ": raise AssertionError("Status message must have a space after code") - def _convert_string_type(self, value, title): + def _convert_string_type(self, value, title, *, name=True): """Convert/check value type.""" if type(value) is str: + if (_name_disallowed if name else _value_disallowed).search(value): + raise ValueError("Control characters not allowed in headers and values") return value raise AssertionError( "{0} must be of type str (got {1})".format(title, repr(value)) From 9414df2b3f8709457f7501ca9e1b4e5c6a194d53 Mon Sep 17 00:00:00 2001 From: Benedikt Johannes Date: Sat, 31 Jan 2026 22:48:56 +0100 Subject: [PATCH 2/3] Add missing import of "re" --- Lib/wsgiref/handlers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/wsgiref/handlers.py b/Lib/wsgiref/handlers.py index ab8eca177dd477..80957b816f6ba9 100644 --- a/Lib/wsgiref/handlers.py +++ b/Lib/wsgiref/handlers.py @@ -3,7 +3,7 @@ from .util import FileWrapper, guess_scheme, is_hop_by_hop from .headers import Headers -import sys, os, time +import sys, os, time, re __all__ = [ 'BaseHandler', 'SimpleHandler', 'BaseCGIHandler', 'CGIHandler', From 49ddbca5fcdab3348b1c8a8b4776121b42cacb70 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Sat, 31 Jan 2026 21:56:55 +0000 Subject: [PATCH 3/3] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Security/2026-01-31-21-56-54.gh-issue-144370.fp9m8t.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Security/2026-01-31-21-56-54.gh-issue-144370.fp9m8t.rst diff --git a/Misc/NEWS.d/next/Security/2026-01-31-21-56-54.gh-issue-144370.fp9m8t.rst b/Misc/NEWS.d/next/Security/2026-01-31-21-56-54.gh-issue-144370.fp9m8t.rst new file mode 100644 index 00000000000000..3f62efabdff5fd --- /dev/null +++ b/Misc/NEWS.d/next/Security/2026-01-31-21-56-54.gh-issue-144370.fp9m8t.rst @@ -0,0 +1 @@ +Disallow usage of control characters in status, headers and values in ``Lib/wsgiref/handlers.py`` for security. Patch by Benedikt Johannes.