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 <[email protected]>
+
+- 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="[email protected]",
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