]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-144370: Disallow usage of control characters in status in wsgiref.handlers for...
authorBenedikt Johannes <benedikt.johannes.hofer@gmail.com>
Fri, 6 Mar 2026 12:22:21 +0000 (13:22 +0100)
committerGitHub <noreply@github.com>
Fri, 6 Mar 2026 12:22:21 +0000 (13:22 +0100)
Disallow usage of control characters in status in wsgiref.handlers
to prevent HTTP header injections.

Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>
Co-authored-by: Victor Stinner <vstinner@python.org>
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 a7a5c5ba33d493291db43ae89ab099cee505cc08..3379df37d38ca801d81f00442c8e95f4246b7b43 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)])
+
 
 class TestModule(unittest.TestCase):
     def test_deprecated__version__(self):
index 9353fb678625b3613d247e135b156228dc85af0f..b82862deea7d741884e36ce341f580a0bfb61b59 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
 
@@ -250,6 +250,8 @@ class BaseHandler:
         return self.write
 
     def _validate_status(self, status):
+        if _name_disallowed_re.search(status):
+            raise ValueError("Control characters are not allowed in status")
         if len(status) < 4:
             raise AssertionError("Status must be at least 4 characters")
         if not status[:3].isdigit():
index e38bda37bfa92d9130d7a64231d06ff1fa46ec47..88c0a68f1e6c8740e64c8437c2a89d278ffc7b72 100644 (file)
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -1086,6 +1086,7 @@ Wolfgang Langner
 Detlef Lannert
 RĂ©mi Lapeyre
 Soren Larsen
+Seth Michael Larson
 Amos Latteier
 Keenan Lau
 Piers Lauder
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.