]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.11] gh-144370: Disallow usage of control characters in status in wsgiref.handlers... 3.11 98846/head
authorVictor Stinner <vstinner@python.org>
Sun, 17 May 2026 18:33:30 +0000 (20:33 +0200)
committerGitHub <noreply@github.com>
Sun, 17 May 2026 18:33:30 +0000 (11:33 -0700)
Lib/test/test_wsgiref.py
Lib/wsgiref/handlers.py
Misc/ACKS
Misc/NEWS.d/next/Security/2026-01-31-21-56-54.gh-issue-144370.fp9m8t.rst [new file with mode: 0644]

index bb575bdaef62a2e7001c674663d5cc823b0d82e3..a8b03d15130791c40ac2fa1b772ee52c3ec41d50 100644 (file)
@@ -855,6 +855,25 @@ class HandlerTests(TestCase):
         self.assertIsNotNone(h.status)
         self.assertIsNotNone(h.environ)
 
+    def testRaisesControlCharacters(self):
+        for c0 in control_characters_c0():
+            with self.subTest(c0):
+                base = BaseHandler()
+                with self.assertRaises(ValueError):
+                    base.start_response(c0, [('x', 'y')])
+
+                base = BaseHandler()
+                with self.assertRaises(ValueError):
+                    base.start_response('200 OK', [(c0, 'y')])
+
+                # HTAB (\x09) is allowed in header values, but not in names.
+                base = BaseHandler()
+                if c0 != "\t":
+                    with self.assertRaises(ValueError):
+                        base.start_response('200 OK', [('x', c0)])
+                else:
+                    base.start_response('200 OK', [('x', c0)])
+
 
 if __name__ == "__main__":
     unittest.main()
index 6623b700537cf930397ec4d43fff149dec0014e4..49ffd7bdd55f67ad75e5a266fe6daeec52857ae7 100644 (file)
@@ -1,7 +1,7 @@
 """Base classes for server/gateway implementations"""
 
 from .util import FileWrapper, guess_scheme, is_hop_by_hop
-from .headers import Headers
+from .headers import Headers, _name_disallowed_re
 
 import sys, os, time
 
@@ -237,6 +237,8 @@ class BaseHandler:
         self.status = status
         self.headers = self.headers_class(headers)
         status = self._convert_string_type(status, "Status")
+        if _name_disallowed_re.search(status):
+            raise ValueError("Control characters are not allowed in status")
         assert len(status)>=4,"Status must be at least 4 characters"
         assert status[:3].isdigit(), "Status message must begin w/3-digit code"
         assert status[3]==" ", "Status message must have a space after code"
index 1c0f5d7f782fd3db54732c73441d70ca16879364..1ed09dc3c8858e0c232ec027559fbad2a4b3a755 100644 (file)
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -1021,6 +1021,7 @@ Wolfgang Langner
 Detlef Lannert
 RĂ©mi Lapeyre
 Soren Larsen
+Seth Michael Larson
 Amos Latteier
 Piers Lauder
 Ben Laurie
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 (file)
index 0000000..2d13a06
--- /dev/null
@@ -0,0 +1,2 @@
+Disallow usage of control characters in status in :mod:`wsgiref.handlers` to prevent HTTP header injections.
+Patch by Benedikt Johannes.