diff --git a/Lib/wsgiref/handlers.py b/Lib/wsgiref/handlers.py index 9353fb678625b3..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', @@ -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)) 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.