Hello community, here is the log from the commit of package python-waitress for openSUSE:Factory checked in at 2020-02-15 22:23:08 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-waitress (Old) and /work/SRC/openSUSE:Factory/.python-waitress.new.26092 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-waitress" Sat Feb 15 22:23:08 2020 rev:18 rq:770684 version:1.4.3 Changes: -------- --- /work/SRC/openSUSE:Factory/python-waitress/python-waitress.changes 2020-01-01 14:58:13.077928582 +0100 +++ /work/SRC/openSUSE:Factory/.python-waitress.new.26092/python-waitress.changes 2020-02-15 22:23:11.379237361 +0100 @@ -1,0 +2,11 @@ +Thu Feb 6 17:29:20 UTC 2020 - Marketa Calabkova <mcalabk...@suse.com> + +- update to 1.4.3 + * Waitress did not properly validate that the HTTP headers it received + were properly formed, thereby potentially allowing a front-end server + to treat a request different from Waitress. This could lead to HTTP + request smuggling/splitting. +- drop patch local-intersphinx-inventories.patch + * it was commented out, anyway + +------------------------------------------------------------------- Old: ---- local-intersphinx-inventories.patch waitress-1.4.0.tar.gz New: ---- waitress-1.4.3.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-waitress.spec ++++++ --- /var/tmp/diff_new_pack.WDhuiv/_old 2020-02-15 22:23:11.939237664 +0100 +++ /var/tmp/diff_new_pack.WDhuiv/_new 2020-02-15 22:23:11.951237670 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-waitress # -# Copyright (c) 2019 SUSE LLC +# Copyright (c) 2020 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,7 +18,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-waitress -Version: 1.4.0 +Version: 1.4.3 Release: 0 Summary: Waitress WSGI server License: ZPL-2.1 @@ -29,16 +29,15 @@ # https://docs.python.org/3/objects.inv -> python3.inv Source1: python3.inv Source2: fetch-intersphinx-inventories.sh -Patch: local-intersphinx-inventories.patch BuildRequires: %{python_module setuptools} BuildRequires: fdupes BuildRequires: python-rpm-macros +BuildArch: noarch # SECTION documentation requirements BuildRequires: python3-Sphinx BuildRequires: python3-docutils BuildRequires: python3-pylons-sphinx-themes # /SECTION -BuildArch: noarch %python_subpackages %description @@ -59,8 +58,7 @@ %prep %setup -q -n waitress-%{version} -#%patch -p1 -cp %{S:1} docs/ +cp %{SOURCE1} docs/ %build %python_build ++++++ waitress-1.4.0.tar.gz -> waitress-1.4.3.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/waitress-1.4.0/CHANGES.txt new/waitress-1.4.3/CHANGES.txt --- old/waitress-1.4.0/CHANGES.txt 2019-12-20 11:31:09.000000000 +0100 +++ new/waitress-1.4.3/CHANGES.txt 2020-02-03 06:49:29.000000000 +0100 @@ -1,3 +1,62 @@ +1.4.3 (2020-02-02) +------------------ + +Security Fixes +~~~~~~~~~~~~~~ + +- In Waitress version 1.4.2 a new regular expression was added to validate the + headers that Waitress receives to make sure that it matches RFC7230. + Unfortunately the regular expression was written in a way that with invalid + input it leads to catastrophic backtracking which allows for a Denial of + Service and CPU usage going to a 100%. + + This was reported by Fil Zembowicz to the Pylons Project. Please see + https://github.com/Pylons/waitress/security/advisories/GHSA-73m2-3pwg-5fgc + for more information. + +1.4.2 (2020-01-02) +------------------ + +Security Fixes +~~~~~~~~~~~~~~ + +- This is a follow-up to the fix introduced in 1.4.1 to tighten up the way + Waitress strips whitespace from header values. This makes sure Waitress won't + accidentally treat non-printable characters as whitespace and lead to a + potental HTTP request smuggling/splitting security issue. + + Thanks to ZeddYu Lu for the extra test cases. + + Please see the security advisory for more information: + https://github.com/Pylons/waitress/security/advisories/GHSA-m5ff-3wj3-8ph4 + + CVE-ID: CVE-2019-16789 + +Bugfixes +~~~~~~~~ + +- Updated the regex used to validate header-field content to match the errata + that was published for RFC7230. + + See: https://www.rfc-editor.org/errata_search.php?rfc=7230&eid=4189 + + +1.4.1 (2019-12-24) +------------------ + +Security Fixes +~~~~~~~~~~~~~~ + +- Waitress did not properly validate that the HTTP headers it received were + properly formed, thereby potentially allowing a front-end server to treat a + request different from Waitress. This could lead to HTTP request + smuggling/splitting. + + Please see the security advisory for more information: + https://github.com/Pylons/waitress/security/advisories/GHSA-m5ff-3wj3-8ph4 + + CVE-ID: CVE-2019-16789 + 1.4.0 (2019-12-20) ------------------ @@ -36,6 +95,11 @@ For more information I can highly recommend the blog post by ZeddYu Lu https://blog.zeddyu.info/2019/12/08/HTTP-Smuggling-en/ + Please see the security advisory for more information: + https://github.com/Pylons/waitress/security/advisories/GHSA-pg36-wpm5-g57p + + CVE-ID: CVE-2019-16785 + - Waitress used to treat LF the same as CRLF in ``Transfer-Encoding: chunked`` requests, while the maintainer doesn't believe this could lead to a security issue, this is no longer supported and all chunks are now validated to be @@ -61,6 +125,11 @@ ``Transfer-Encoding: chunked`` instead of ``Transfer-Encoding: identity, chunked``. + Please see the security advisory for more information: + https://github.com/Pylons/waitress/security/advisories/GHSA-g2xc-35jw-c63p + + CVE-ID: CVE-2019-16786 + - While validating the ``Transfer-Encoding`` header, Waitress now properly handles line-folded ``Transfer-Encoding`` headers or those that contain multiple comma seperated values. This closes a potential issue where a @@ -75,3 +144,6 @@ for a potential request to be split and treated as two requests by HTTP pipelining support in Waitress. If Waitress is now unable to parse the Content-Length header, a 400 Bad Request is sent back to the client. + + Please see the security advisory for more information: + https://github.com/Pylons/waitress/security/advisories/GHSA-4ppp-gpcr-7qf6 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/waitress-1.4.0/PKG-INFO new/waitress-1.4.3/PKG-INFO --- old/waitress-1.4.0/PKG-INFO 2019-12-20 11:32:00.000000000 +0100 +++ new/waitress-1.4.3/PKG-INFO 2020-02-03 06:51:30.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: waitress -Version: 1.4.0 +Version: 1.4.3 Summary: Waitress WSGI server Home-page: https://github.com/Pylons/waitress Author: Zope Foundation and Contributors @@ -36,6 +36,65 @@ For more information, see the "docs" directory of the Waitress package or visit https://docs.pylonsproject.org/projects/waitress/en/latest/ + 1.4.3 (2020-02-02) + ------------------ + + Security Fixes + ~~~~~~~~~~~~~~ + + - In Waitress version 1.4.2 a new regular expression was added to validate the + headers that Waitress receives to make sure that it matches RFC7230. + Unfortunately the regular expression was written in a way that with invalid + input it leads to catastrophic backtracking which allows for a Denial of + Service and CPU usage going to a 100%. + + This was reported by Fil Zembowicz to the Pylons Project. Please see + https://github.com/Pylons/waitress/security/advisories/GHSA-73m2-3pwg-5fgc + for more information. + + 1.4.2 (2020-01-02) + ------------------ + + Security Fixes + ~~~~~~~~~~~~~~ + + - This is a follow-up to the fix introduced in 1.4.1 to tighten up the way + Waitress strips whitespace from header values. This makes sure Waitress won't + accidentally treat non-printable characters as whitespace and lead to a + potental HTTP request smuggling/splitting security issue. + + Thanks to ZeddYu Lu for the extra test cases. + + Please see the security advisory for more information: + https://github.com/Pylons/waitress/security/advisories/GHSA-m5ff-3wj3-8ph4 + + CVE-ID: CVE-2019-16789 + + Bugfixes + ~~~~~~~~ + + - Updated the regex used to validate header-field content to match the errata + that was published for RFC7230. + + See: https://www.rfc-editor.org/errata_search.php?rfc=7230&eid=4189 + + + 1.4.1 (2019-12-24) + ------------------ + + Security Fixes + ~~~~~~~~~~~~~~ + + - Waitress did not properly validate that the HTTP headers it received were + properly formed, thereby potentially allowing a front-end server to treat a + request different from Waitress. This could lead to HTTP request + smuggling/splitting. + + Please see the security advisory for more information: + https://github.com/Pylons/waitress/security/advisories/GHSA-m5ff-3wj3-8ph4 + + CVE-ID: CVE-2019-16789 + 1.4.0 (2019-12-20) ------------------ @@ -74,6 +133,11 @@ For more information I can highly recommend the blog post by ZeddYu Lu https://blog.zeddyu.info/2019/12/08/HTTP-Smuggling-en/ + Please see the security advisory for more information: + https://github.com/Pylons/waitress/security/advisories/GHSA-pg36-wpm5-g57p + + CVE-ID: CVE-2019-16785 + - Waitress used to treat LF the same as CRLF in ``Transfer-Encoding: chunked`` requests, while the maintainer doesn't believe this could lead to a security issue, this is no longer supported and all chunks are now validated to be @@ -99,6 +163,11 @@ ``Transfer-Encoding: chunked`` instead of ``Transfer-Encoding: identity, chunked``. + Please see the security advisory for more information: + https://github.com/Pylons/waitress/security/advisories/GHSA-g2xc-35jw-c63p + + CVE-ID: CVE-2019-16786 + - While validating the ``Transfer-Encoding`` header, Waitress now properly handles line-folded ``Transfer-Encoding`` headers or those that contain multiple comma seperated values. This closes a potential issue where a @@ -114,6 +183,9 @@ pipelining support in Waitress. If Waitress is now unable to parse the Content-Length header, a 400 Bad Request is sent back to the client. + Please see the security advisory for more information: + https://github.com/Pylons/waitress/security/advisories/GHSA-4ppp-gpcr-7qf6 + Keywords: waitress wsgi server http Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/waitress-1.4.0/setup.py new/waitress-1.4.3/setup.py --- old/waitress-1.4.0/setup.py 2019-12-20 11:31:09.000000000 +0100 +++ new/waitress-1.4.3/setup.py 2020-02-03 06:46:28.000000000 +0100 @@ -34,7 +34,7 @@ setup( name="waitress", - version="1.4.0", + version="1.4.3", author="Zope Foundation and Contributors", author_email="zope-...@zope.org", maintainer="Pylons Project", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/waitress-1.4.0/waitress/parser.py new/waitress-1.4.3/waitress/parser.py --- old/waitress-1.4.0/waitress/parser.py 2019-12-20 11:31:09.000000000 +0100 +++ new/waitress-1.4.3/waitress/parser.py 2020-01-03 00:00:37.000000000 +0100 @@ -29,6 +29,7 @@ ServerNotImplemented, find_double_newline, ) +from .rfc7230 import HEADER_FIELD class ParsingError(Exception): @@ -38,7 +39,6 @@ class TransferEncodingNotImplemented(Exception): pass - class HTTPRequestParser(object): """A structure that collects the HTTP request. @@ -208,26 +208,29 @@ headers = self.headers for line in lines: - index = line.find(b":") - if index > 0: - key = line[:index] - - if key != key.strip(): - raise ParsingError("Invalid whitespace after field-name") - - if b"_" in key: - continue - value = line[index + 1 :].strip() - key1 = tostr(key.upper().replace(b"-", b"_")) - # If a header already exists, we append subsequent values - # seperated by a comma. Applications already need to handle - # the comma seperated values, as HTTP front ends might do - # the concatenation for you (behavior specified in RFC2616). - try: - headers[key1] += tostr(b", " + value) - except KeyError: - headers[key1] = tostr(value) - # else there's garbage in the headers? + header = HEADER_FIELD.match(line) + + if not header: + raise ParsingError("Invalid header") + + key, value = header.group("name", "value") + + if b"_" in key: + # TODO(xistence): Should we drop this request instead? + continue + + # Only strip off whitespace that is considered valid whitespace by + # RFC7230, don't strip the rest + value = value.strip(b" \t") + key1 = tostr(key.upper().replace(b"-", b"_")) + # If a header already exists, we append subsequent values + # seperated by a comma. Applications already need to handle + # the comma seperated values, as HTTP front ends might do + # the concatenation for you (behavior specified in RFC2616). + try: + headers[key1] += tostr(b", " + value) + except KeyError: + headers[key1] = tostr(value) # command, uri, version will be bytes command, uri, version = crack_first_line(first_line) @@ -256,7 +259,16 @@ # here te = headers.pop("TRANSFER_ENCODING", "") - encodings = [encoding.strip().lower() for encoding in te.split(",") if encoding] + # NB: We can not just call bare strip() here because it will also + # remove other non-printable characters that we explicitly do not + # want removed so that if someone attempts to smuggle a request + # with these characters we don't fall prey to it. + # + # For example \x85 is stripped by default, but it is not considered + # valid whitespace to be stripped by RFC7230. + encodings = [ + encoding.strip(" \t").lower() for encoding in te.split(",") if encoding + ] for encoding in encodings: # Out of the transfer-codings listed in @@ -352,6 +364,9 @@ r = [] lines = header.split(b"\r\n") for line in lines: + if not line: + continue + if b"\r" in line or b"\n" in line: raise ParsingError('Bare CR or LF found in header line "%s"' % tostr(line)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/waitress-1.4.0/waitress/rfc7230.py new/waitress-1.4.3/waitress/rfc7230.py --- old/waitress-1.4.0/waitress/rfc7230.py 1970-01-01 01:00:00.000000000 +0100 +++ new/waitress-1.4.3/waitress/rfc7230.py 2020-02-03 06:46:10.000000000 +0100 @@ -0,0 +1,52 @@ +""" +This contains a bunch of RFC7230 definitions and regular expressions that are +needed to properly parse HTTP messages. +""" + +import re + +from .compat import tobytes + +WS = "[ \t]" +OWS = WS + "{0,}?" +RWS = WS + "{1,}?" +BWS = OWS + +# RFC 7230 Section 3.2.6 "Field Value Components": +# tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" +# / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" +# / DIGIT / ALPHA +# obs-text = %x80-FF +TCHAR = r"[!#$%&'*+\-.^_`|~0-9A-Za-z]" +OBS_TEXT = r"\x80-\xff" + +TOKEN = TCHAR + "{1,}" + +# RFC 5234 Appendix B.1 "Core Rules": +# VCHAR = %x21-7E +# ; visible (printing) characters +VCHAR = r"\x21-\x7e" + +# header-field = field-name ":" OWS field-value OWS +# field-name = token +# field-value = *( field-content / obs-fold ) +# field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] +# field-vchar = VCHAR / obs-text + +# Errata from: https://www.rfc-editor.org/errata_search.php?rfc=7230&eid=4189 +# changes field-content to: +# +# field-content = field-vchar [ 1*( SP / HTAB / field-vchar ) +# field-vchar ] + +FIELD_VCHAR = "[" + VCHAR + OBS_TEXT + "]" +# Field content is more greedy than the ABNF, in that it will match the whole value +FIELD_CONTENT = FIELD_VCHAR + "+(?:[ \t]+" + FIELD_VCHAR + "+)*" +# Which allows the field value here to just see if there is even a value in the first place +FIELD_VALUE = "(?:" + FIELD_CONTENT + ")?" + +HEADER_FIELD = re.compile( + tobytes( + "^(?P<name>" + TOKEN + "):" + OWS + "(?P<value>" + FIELD_VALUE + ")" + OWS + "$" + ) +) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/waitress-1.4.0/waitress/tests/test_parser.py new/waitress-1.4.3/waitress/tests/test_parser.py --- old/waitress-1.4.0/waitress/tests/test_parser.py 2019-12-20 11:31:09.000000000 +0100 +++ new/waitress-1.4.3/waitress/tests/test_parser.py 2020-02-03 06:46:10.000000000 +0100 @@ -55,6 +55,7 @@ def test_received_bad_transfer_encoding(self): from waitress.utilities import ServerNotImplemented + data = ( b"GET /foobar HTTP/1.1\r\n" b"Transfer-Encoding: foo\r\n" @@ -211,7 +212,6 @@ self.parser.parse_header(data) self.assertEqual(self.parser.body_rcv.__class__.__name__, "ChunkedReceiver") - def test_parse_header_transfer_encoding_invalid(self): from waitress.parser import TransferEncodingNotImplemented @@ -236,6 +236,35 @@ else: # pragma: nocover self.assertTrue(False) + def test_parse_header_transfer_encoding_invalid_whitespace(self): + from waitress.parser import TransferEncodingNotImplemented + + data = b"GET /foobar HTTP/1.1\r\nTransfer-Encoding:\x85chunked\r\n" + + try: + self.parser.parse_header(data) + except TransferEncodingNotImplemented as e: + self.assertIn("Transfer-Encoding requested is not supported.", e.args[0]) + else: # pragma: nocover + self.assertTrue(False) + + def test_parse_header_transfer_encoding_invalid_unicode(self): + from waitress.parser import TransferEncodingNotImplemented + + # This is the binary encoding for the UTF-8 character + # https://www.compart.com/en/unicode/U+212A "unicode character "K"" + # which if waitress were to accidentally do the wrong thing get + # lowercased to just the ascii "k" due to unicode collisions during + # transformation + data = b"GET /foobar HTTP/1.1\r\nTransfer-Encoding: chun\xe2\x84\xaaed\r\n" + + try: + self.parser.parse_header(data) + except TransferEncodingNotImplemented as e: + self.assertIn("Transfer-Encoding requested is not supported.", e.args[0]) + else: # pragma: nocover + self.assertTrue(False) + def test_parse_header_11_expect_continue(self): data = b"GET /foobar HTTP/1.1\r\nexpect: 100-continue\r\n" self.parser.parse_header(data) @@ -308,10 +337,124 @@ try: self.parser.parse_header(data) except ParsingError as e: - self.assertIn("Invalid whitespace after field-name", e.args[0]) + self.assertIn("Invalid header", e.args[0]) else: # pragma: nocover self.assertTrue(False) + def test_parse_header_invalid_whitespace_vtab(self): + from waitress.parser import ParsingError + + data = b"GET /foobar HTTP/1.1\r\nfoo:\x0bbar\r\n" + try: + self.parser.parse_header(data) + except ParsingError as e: + self.assertIn("Invalid header", e.args[0]) + else: # pragma: nocover + self.assertTrue(False) + + def test_parse_header_invalid_no_colon(self): + from waitress.parser import ParsingError + + data = b"GET /foobar HTTP/1.1\r\nfoo: bar\r\nnotvalid\r\n" + try: + self.parser.parse_header(data) + except ParsingError as e: + self.assertIn("Invalid header", e.args[0]) + else: # pragma: nocover + self.assertTrue(False) + + def test_parse_header_invalid_folding_spacing(self): + from waitress.parser import ParsingError + + data = b"GET /foobar HTTP/1.1\r\nfoo: bar\r\n\t\x0bbaz\r\n" + try: + self.parser.parse_header(data) + except ParsingError as e: + self.assertIn("Invalid header", e.args[0]) + else: # pragma: nocover + self.assertTrue(False) + + def test_parse_header_invalid_chars(self): + from waitress.parser import ParsingError + + data = b"GET /foobar HTTP/1.1\r\nfoo: bar\r\nfoo: \x0bbaz\r\n" + try: + self.parser.parse_header(data) + except ParsingError as e: + self.assertIn("Invalid header", e.args[0]) + else: # pragma: nocover + self.assertTrue(False) + + def test_parse_header_empty(self): + from waitress.parser import ParsingError + + data = b"GET /foobar HTTP/1.1\r\nfoo: bar\r\nempty:\r\n" + self.parser.parse_header(data) + + self.assertIn("EMPTY", self.parser.headers) + self.assertIn("FOO", self.parser.headers) + self.assertEqual(self.parser.headers["EMPTY"], "") + self.assertEqual(self.parser.headers["FOO"], "bar") + + def test_parse_header_multiple_values(self): + from waitress.parser import ParsingError + + data = b"GET /foobar HTTP/1.1\r\nfoo: bar, whatever, more, please, yes\r\n" + self.parser.parse_header(data) + + self.assertIn("FOO", self.parser.headers) + self.assertEqual(self.parser.headers["FOO"], "bar, whatever, more, please, yes") + + def test_parse_header_multiple_values_header_folded(self): + from waitress.parser import ParsingError + + data = b"GET /foobar HTTP/1.1\r\nfoo: bar, whatever,\r\n more, please, yes\r\n" + self.parser.parse_header(data) + + self.assertIn("FOO", self.parser.headers) + self.assertEqual(self.parser.headers["FOO"], "bar, whatever, more, please, yes") + + def test_parse_header_multiple_values_header_folded_multiple(self): + from waitress.parser import ParsingError + + data = b"GET /foobar HTTP/1.1\r\nfoo: bar, whatever,\r\n more\r\nfoo: please, yes\r\n" + self.parser.parse_header(data) + + self.assertIn("FOO", self.parser.headers) + self.assertEqual(self.parser.headers["FOO"], "bar, whatever, more, please, yes") + + def test_parse_header_multiple_values_extra_space(self): + # Tests errata from: https://www.rfc-editor.org/errata_search.php?rfc=7230&eid=4189 + from waitress.parser import ParsingError + + data = b"GET /foobar HTTP/1.1\r\nfoo: abrowser/0.001 (C O M M E N T)\r\n" + self.parser.parse_header(data) + + self.assertIn("FOO", self.parser.headers) + self.assertEqual(self.parser.headers["FOO"], "abrowser/0.001 (C O M M E N T)") + + def test_parse_header_invalid_backtrack_bad(self): + from waitress.parser import ParsingError + + data = b"GET /foobar HTTP/1.1\r\nfoo: bar\r\nfoo: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\x10\r\n" + try: + self.parser.parse_header(data) + except ParsingError as e: + self.assertIn("Invalid header", e.args[0]) + else: # pragma: nocover + self.assertTrue(False) + + def test_parse_header_short_values(self): + from waitress.parser import ParsingError + + data = b"GET /foobar HTTP/1.1\r\none: 1\r\ntwo: 22\r\n" + self.parser.parse_header(data) + + self.assertIn("ONE", self.parser.headers) + self.assertIn("TWO", self.parser.headers) + self.assertEqual(self.parser.headers["ONE"], "1") + self.assertEqual(self.parser.headers["TWO"], "22") + class Test_split_uri(unittest.TestCase): def _callFUT(self, uri): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/waitress-1.4.0/waitress/utilities.py new/waitress-1.4.3/waitress/utilities.py --- old/waitress-1.4.0/waitress/utilities.py 2019-12-20 11:31:09.000000000 +0100 +++ new/waitress-1.4.3/waitress/utilities.py 2019-12-24 15:18:17.000000000 +0100 @@ -22,6 +22,8 @@ import stat import time +from .rfc7230 import OBS_TEXT, VCHAR + logger = logging.getLogger("waitress") queue_logger = logging.getLogger("waitress.queue") @@ -63,6 +65,7 @@ long_day_reg = group(join(long_days, "|")) daymap = {} + for i in range(7): daymap[short_days[i]] = i daymap[long_days[i]] = i @@ -85,6 +88,7 @@ ] monmap = {} + for i in range(12): monmap[months[i]] = i + 1 @@ -113,6 +117,7 @@ def unpack_rfc822(m): g = m.group + return ( int(g(4)), # year monmap[g(3)], # month @@ -142,8 +147,10 @@ def unpack_rfc850(m): g = m.group yr = g(4) + if len(yr) == 2: yr = "19" + yr + return ( int(yr), # year monmap[g(3)], # month @@ -180,6 +187,7 @@ def build_http_date(when): year, month, day, hh, mm, ss, wd, y, z = time.gmtime(when) + return "%s, %02d %3s %4d %02d:%02d:%02d GMT" % ( weekdayname[wd], day, @@ -194,28 +202,31 @@ def parse_http_date(d): d = d.lower() m = rfc850_reg.match(d) + if m and m.end() == len(d): retval = int(calendar.timegm(unpack_rfc850(m))) else: m = rfc822_reg.match(d) + if m and m.end() == len(d): retval = int(calendar.timegm(unpack_rfc822(m))) else: return 0 + return retval # RFC 5234 Appendix B.1 "Core Rules": # VCHAR = %x21-7E # ; visible (printing) characters -vchar_re = "\x21-\x7e" +vchar_re = VCHAR # RFC 7230 Section 3.2.6 "Field Value Components": # quoted-string = DQUOTE *( qdtext / quoted-pair ) DQUOTE # qdtext = HTAB / SP /%x21 / %x23-5B / %x5D-7E / obs-text # obs-text = %x80-FF # quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text ) -obs_text_re = "\x80-\xff" +obs_text_re = OBS_TEXT # The '\\' between \x5b and \x5d is needed to escape \x5d (']') qdtext_re = "[\t \x21\x23-\x5b\\\x5d-\x7e" + obs_text_re + "]" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/waitress-1.4.0/waitress.egg-info/PKG-INFO new/waitress-1.4.3/waitress.egg-info/PKG-INFO --- old/waitress-1.4.0/waitress.egg-info/PKG-INFO 2019-12-20 11:31:59.000000000 +0100 +++ new/waitress-1.4.3/waitress.egg-info/PKG-INFO 2020-02-03 06:51:29.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: waitress -Version: 1.4.0 +Version: 1.4.3 Summary: Waitress WSGI server Home-page: https://github.com/Pylons/waitress Author: Zope Foundation and Contributors @@ -36,6 +36,65 @@ For more information, see the "docs" directory of the Waitress package or visit https://docs.pylonsproject.org/projects/waitress/en/latest/ + 1.4.3 (2020-02-02) + ------------------ + + Security Fixes + ~~~~~~~~~~~~~~ + + - In Waitress version 1.4.2 a new regular expression was added to validate the + headers that Waitress receives to make sure that it matches RFC7230. + Unfortunately the regular expression was written in a way that with invalid + input it leads to catastrophic backtracking which allows for a Denial of + Service and CPU usage going to a 100%. + + This was reported by Fil Zembowicz to the Pylons Project. Please see + https://github.com/Pylons/waitress/security/advisories/GHSA-73m2-3pwg-5fgc + for more information. + + 1.4.2 (2020-01-02) + ------------------ + + Security Fixes + ~~~~~~~~~~~~~~ + + - This is a follow-up to the fix introduced in 1.4.1 to tighten up the way + Waitress strips whitespace from header values. This makes sure Waitress won't + accidentally treat non-printable characters as whitespace and lead to a + potental HTTP request smuggling/splitting security issue. + + Thanks to ZeddYu Lu for the extra test cases. + + Please see the security advisory for more information: + https://github.com/Pylons/waitress/security/advisories/GHSA-m5ff-3wj3-8ph4 + + CVE-ID: CVE-2019-16789 + + Bugfixes + ~~~~~~~~ + + - Updated the regex used to validate header-field content to match the errata + that was published for RFC7230. + + See: https://www.rfc-editor.org/errata_search.php?rfc=7230&eid=4189 + + + 1.4.1 (2019-12-24) + ------------------ + + Security Fixes + ~~~~~~~~~~~~~~ + + - Waitress did not properly validate that the HTTP headers it received were + properly formed, thereby potentially allowing a front-end server to treat a + request different from Waitress. This could lead to HTTP request + smuggling/splitting. + + Please see the security advisory for more information: + https://github.com/Pylons/waitress/security/advisories/GHSA-m5ff-3wj3-8ph4 + + CVE-ID: CVE-2019-16789 + 1.4.0 (2019-12-20) ------------------ @@ -74,6 +133,11 @@ For more information I can highly recommend the blog post by ZeddYu Lu https://blog.zeddyu.info/2019/12/08/HTTP-Smuggling-en/ + Please see the security advisory for more information: + https://github.com/Pylons/waitress/security/advisories/GHSA-pg36-wpm5-g57p + + CVE-ID: CVE-2019-16785 + - Waitress used to treat LF the same as CRLF in ``Transfer-Encoding: chunked`` requests, while the maintainer doesn't believe this could lead to a security issue, this is no longer supported and all chunks are now validated to be @@ -99,6 +163,11 @@ ``Transfer-Encoding: chunked`` instead of ``Transfer-Encoding: identity, chunked``. + Please see the security advisory for more information: + https://github.com/Pylons/waitress/security/advisories/GHSA-g2xc-35jw-c63p + + CVE-ID: CVE-2019-16786 + - While validating the ``Transfer-Encoding`` header, Waitress now properly handles line-folded ``Transfer-Encoding`` headers or those that contain multiple comma seperated values. This closes a potential issue where a @@ -114,6 +183,9 @@ pipelining support in Waitress. If Waitress is now unable to parse the Content-Length header, a 400 Bad Request is sent back to the client. + Please see the security advisory for more information: + https://github.com/Pylons/waitress/security/advisories/GHSA-4ppp-gpcr-7qf6 + Keywords: waitress wsgi server http Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/waitress-1.4.0/waitress.egg-info/SOURCES.txt new/waitress-1.4.3/waitress.egg-info/SOURCES.txt --- old/waitress-1.4.0/waitress.egg-info/SOURCES.txt 2019-12-20 11:31:59.000000000 +0100 +++ new/waitress-1.4.3/waitress.egg-info/SOURCES.txt 2020-02-03 06:51:30.000000000 +0100 @@ -43,6 +43,7 @@ waitress/parser.py waitress/proxy_headers.py waitress/receiver.py +waitress/rfc7230.py waitress/runner.py waitress/server.py waitress/task.py