[Bug 2136906] [NEW] python3-urllib3 in 24.04 is now incompatible with shipped python3-zstandard

m4t 2136906 at bugs.launchpad.net
Sat Dec 20 03:34:20 UTC 2025


Public bug reported:

This seems to be a direct result of a backport of upstream fixes per
2.0.7-1ubuntu0.3:

  * SECURITY UPDATE: Denial of service due to decompression bomb.
    - debian/patches/CVE-2025-66471.patch: Fix decompression bomb in
      src/urllib3/response.py. Add tests in test/test_response.py.
    - debian/patches/CVE-2025-66471-post1.patch: Remove brotli version warning
      due to intrusive backport for brotli fixes and upstream version warning
      not being appropriate for distro backporting.
    - CVE-2025-66471

Specifically the patch debian/patches/CVE-2025-66471.patch.

When urllib3 attempts to decode a zstd response from a remote server,
the following stack trace is now seen (this is from 'urlwatch', which
utilizes urllib3). This is because urllib3 is expecting 2 things from
python3-zstandard which don't exist in 0.22.0-1build1.

1. decompress() taking an optional max_length parameter; it expects only 1.
2. The decoder object having a "needs_input" parameter.

Traceback (most recent call last):
  File "/usr/bin/urlwatch", line 33, in <module>
    sys.exit(load_entry_point('urlwatch==2.28', 'console_scripts', 'urlwatch')())
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/urlwatch/cli.py", line 109, in main
    urlwatch_command.run()
  File "/usr/lib/python3/dist-packages/urlwatch/command.py", line 458, in run
    self.handle_actions()
  File "/usr/lib/python3/dist-packages/urlwatch/command.py", line 256, in handle_actions
    sys.exit(self.test_filter(self.urlwatch_config.test_filter))
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/urlwatch/command.py", line 139, in test_filter
    raise job_state.exception
  File "/usr/lib/python3/dist-packages/urlwatch/handler.py", line 113, in process
    data = self.job.retrieve(self)
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/urlwatch/jobs.py", line 327, in retrieve
    response = requests.request(url=self.url,
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/requests/api.py", line 59, in request
    return session.request(method=method, url=url, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/requests/sessions.py", line 589, in request
    resp = self.send(prep, **send_kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/requests/sessions.py", line 747, in send
    r.content
  File "/usr/lib/python3/dist-packages/requests/models.py", line 899, in content
    self._content = b"".join(self.iter_content(CONTENT_CHUNK_SIZE)) or b""
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/requests/models.py", line 816, in generate
    yield from self.raw.stream(chunk_size, decode_content=True)
  File "/usr/lib/python3/dist-packages/urllib3/response.py", line 1123, in stream
    yield from self.read_chunked(amt, decode_content=decode_content)
  File "/usr/lib/python3/dist-packages/urllib3/response.py", line 1271, in read_chunked
    decoded = self._decode(
              ^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/urllib3/response.py", line 613, in _decode
    data = self._decoder.decompress(data, max_length=max_length)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/urllib3/response.py", line 267, in decompress
    part = self._obj.decompress(data, max_length=max_length)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: decompress() takes at most 1 argument (2 given)


I was able to workaround the issue by making the following change (which disables the "fix"):

--- /storage/root/_btrbk/@.20251219//usr/lib/python3/dist-packages/urllib3/response.py	2025-12-10 14:26:11.000000000 -0500
+++ /usr/lib/python3/dist-packages/urllib3/response.py	2025-12-19 22:02:38.609540775 -0500
@@ -264,7 +264,7 @@
             if self._obj.eof:
                 data = self._obj.unused_data + data
                 self._obj = zstd.ZstdDecompressor().decompressobj()
-            part = self._obj.decompress(data, max_length=max_length)
+            part = self._obj.decompress(data)
             length = len(part)
             data_parts = [part]
             # Every loop iteration is supposed to read data from a separate frame.
@@ -294,7 +294,7 @@

         @property
         def has_unconsumed_tail(self) -> bool:
-            return not (self._obj.needs_input or self._obj.eof) or bool(
+            return not self._obj.eof or bool(
                 self._obj.unused_data
             )

Some info:
Ubuntu 24.04.3 amd64
python3-urllib3 2.0.7-1ubuntu0.3
python3-zstandard 0.22.0-1build1

** Affects: python-urllib3 (Ubuntu)
     Importance: Undecided
         Status: New

** Description changed:

  This seems to be a direct result of a backport of upstream fixes per
  2.0.7-1ubuntu0.3:
  
-   * SECURITY UPDATE: Denial of service due to decompression bomb.
-     - debian/patches/CVE-2025-66471.patch: Fix decompression bomb in
-       src/urllib3/response.py. Add tests in test/test_response.py.
-     - debian/patches/CVE-2025-66471-post1.patch: Remove brotli version warning
-       due to intrusive backport for brotli fixes and upstream version warning
-       not being appropriate for distro backporting.
-     - CVE-2025-66471
+   * SECURITY UPDATE: Denial of service due to decompression bomb.
+     - debian/patches/CVE-2025-66471.patch: Fix decompression bomb in
+       src/urllib3/response.py. Add tests in test/test_response.py.
+     - debian/patches/CVE-2025-66471-post1.patch: Remove brotli version warning
+       due to intrusive backport for brotli fixes and upstream version warning
+       not being appropriate for distro backporting.
+     - CVE-2025-66471
  
  Specifically the patch debian/patches/CVE-2025-66471.patch.
  
  When urllib3 attempts to decode a zstd response from a remote server,
  the following stack trace is now seen (this is from 'urlwatch', which
  utilizes urllib3). This is because urllib3 is expecting 2 things from
  python3-zstandard which don't exist in 0.22.0-1build1.
  
  1. decompress() taking an optional max_length parameter; it expects only 1.
  2. The decoder object having a "needs_input" parameter.
  
  Traceback (most recent call last):
+   File "/usr/bin/urlwatch", line 33, in <module>
+     sys.exit(load_entry_point('urlwatch==2.28', 'console_scripts', 'urlwatch')())
+              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   File "/usr/lib/python3/dist-packages/urlwatch/cli.py", line 109, in main
+     urlwatch_command.run()
+   File "/usr/lib/python3/dist-packages/urlwatch/command.py", line 458, in run
+     self.handle_actions()
+   File "/usr/lib/python3/dist-packages/urlwatch/command.py", line 256, in handle_actions
+     sys.exit(self.test_filter(self.urlwatch_config.test_filter))
+              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   File "/usr/lib/python3/dist-packages/urlwatch/command.py", line 139, in test_filter
+     raise job_state.exception
    File "/usr/lib/python3/dist-packages/urlwatch/handler.py", line 113, in process
      data = self.job.retrieve(self)
             ^^^^^^^^^^^^^^^^^^^^^^^
    File "/usr/lib/python3/dist-packages/urlwatch/jobs.py", line 327, in retrieve
      response = requests.request(url=self.url,
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   File "/home/matt/.local/lib/python3.12/site-packages/requests/api.py", line 59, in request
+   File "/usr/lib/python3/dist-packages/requests/api.py", line 59, in request
      return session.request(method=method, url=url, **kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   File "/home/matt/.local/lib/python3.12/site-packages/requests/sessions.py", line 589, in request
+   File "/usr/lib/python3/dist-packages/requests/sessions.py", line 589, in request
      resp = self.send(prep, **send_kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   File "/home/matt/.local/lib/python3.12/site-packages/requests/sessions.py", line 746, in send
+   File "/usr/lib/python3/dist-packages/requests/sessions.py", line 747, in send
      r.content
-   File "/home/matt/.local/lib/python3.12/site-packages/requests/models.py", line 902, in content
+   File "/usr/lib/python3/dist-packages/requests/models.py", line 899, in content
      self._content = b"".join(self.iter_content(CONTENT_CHUNK_SIZE)) or b""
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   File "/home/matt/.local/lib/python3.12/site-packages/requests/models.py", line 820, in generate
+   File "/usr/lib/python3/dist-packages/requests/models.py", line 816, in generate
      yield from self.raw.stream(chunk_size, decode_content=True)
    File "/usr/lib/python3/dist-packages/urllib3/response.py", line 1123, in stream
      yield from self.read_chunked(amt, decode_content=decode_content)
    File "/usr/lib/python3/dist-packages/urllib3/response.py", line 1271, in read_chunked
      decoded = self._decode(
                ^^^^^^^^^^^^^
    File "/usr/lib/python3/dist-packages/urllib3/response.py", line 613, in _decode
      data = self._decoder.decompress(data, max_length=max_length)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File "/usr/lib/python3/dist-packages/urllib3/response.py", line 267, in decompress
      part = self._obj.decompress(data, max_length=max_length)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  TypeError: decompress() takes at most 1 argument (2 given)
  
- I was able to workaround the issue by making the following change (which
- disables the "fix"):
+ 
+ I was able to workaround the issue by making the following change (which disables the "fix"):
  
  --- /storage/root/_btrbk/@.20251219//usr/lib/python3/dist-packages/urllib3/response.py	2025-12-10 14:26:11.000000000 -0500
  +++ /usr/lib/python3/dist-packages/urllib3/response.py	2025-12-19 22:02:38.609540775 -0500
  @@ -264,7 +264,7 @@
-              if self._obj.eof:
-                  data = self._obj.unused_data + data
-                  self._obj = zstd.ZstdDecompressor().decompressobj()
+              if self._obj.eof:
+                  data = self._obj.unused_data + data
+                  self._obj = zstd.ZstdDecompressor().decompressobj()
  -            part = self._obj.decompress(data, max_length=max_length)
  +            part = self._obj.decompress(data)
-              length = len(part)
-              data_parts = [part]
-              # Every loop iteration is supposed to read data from a separate frame.
+              length = len(part)
+              data_parts = [part]
+              # Every loop iteration is supposed to read data from a separate frame.
  @@ -294,7 +294,7 @@
-  
-          @property
-          def has_unconsumed_tail(self) -> bool:
+ 
+          @property
+          def has_unconsumed_tail(self) -> bool:
  -            return not (self._obj.needs_input or self._obj.eof) or bool(
  +            return not self._obj.eof or bool(
-                  self._obj.unused_data
-              )
-  
+                  self._obj.unused_data
+              )
  
  Some info:
  Ubuntu 24.04.3 amd64
  python3-urllib3 2.0.7-1ubuntu0.3
  python3-zstandard 0.22.0-1build1

-- 
You received this bug notification because you are a member of Ubuntu
OpenStack, which is subscribed to python-urllib3 in Ubuntu.
https://bugs.launchpad.net/bugs/2136906

Title:
  python3-urllib3 in 24.04 is now incompatible with shipped
  python3-zstandard

Status in python-urllib3 package in Ubuntu:
  New

Bug description:
  This seems to be a direct result of a backport of upstream fixes per
  2.0.7-1ubuntu0.3:

    * SECURITY UPDATE: Denial of service due to decompression bomb.
      - debian/patches/CVE-2025-66471.patch: Fix decompression bomb in
        src/urllib3/response.py. Add tests in test/test_response.py.
      - debian/patches/CVE-2025-66471-post1.patch: Remove brotli version warning
        due to intrusive backport for brotli fixes and upstream version warning
        not being appropriate for distro backporting.
      - CVE-2025-66471

  Specifically the patch debian/patches/CVE-2025-66471.patch.

  When urllib3 attempts to decode a zstd response from a remote server,
  the following stack trace is now seen (this is from 'urlwatch', which
  utilizes urllib3). This is because urllib3 is expecting 2 things from
  python3-zstandard which don't exist in 0.22.0-1build1.

  1. decompress() taking an optional max_length parameter; it expects only 1.
  2. The decoder object having a "needs_input" parameter.

  Traceback (most recent call last):
    File "/usr/bin/urlwatch", line 33, in <module>
      sys.exit(load_entry_point('urlwatch==2.28', 'console_scripts', 'urlwatch')())
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File "/usr/lib/python3/dist-packages/urlwatch/cli.py", line 109, in main
      urlwatch_command.run()
    File "/usr/lib/python3/dist-packages/urlwatch/command.py", line 458, in run
      self.handle_actions()
    File "/usr/lib/python3/dist-packages/urlwatch/command.py", line 256, in handle_actions
      sys.exit(self.test_filter(self.urlwatch_config.test_filter))
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File "/usr/lib/python3/dist-packages/urlwatch/command.py", line 139, in test_filter
      raise job_state.exception
    File "/usr/lib/python3/dist-packages/urlwatch/handler.py", line 113, in process
      data = self.job.retrieve(self)
             ^^^^^^^^^^^^^^^^^^^^^^^
    File "/usr/lib/python3/dist-packages/urlwatch/jobs.py", line 327, in retrieve
      response = requests.request(url=self.url,
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File "/usr/lib/python3/dist-packages/requests/api.py", line 59, in request
      return session.request(method=method, url=url, **kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File "/usr/lib/python3/dist-packages/requests/sessions.py", line 589, in request
      resp = self.send(prep, **send_kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File "/usr/lib/python3/dist-packages/requests/sessions.py", line 747, in send
      r.content
    File "/usr/lib/python3/dist-packages/requests/models.py", line 899, in content
      self._content = b"".join(self.iter_content(CONTENT_CHUNK_SIZE)) or b""
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File "/usr/lib/python3/dist-packages/requests/models.py", line 816, in generate
      yield from self.raw.stream(chunk_size, decode_content=True)
    File "/usr/lib/python3/dist-packages/urllib3/response.py", line 1123, in stream
      yield from self.read_chunked(amt, decode_content=decode_content)
    File "/usr/lib/python3/dist-packages/urllib3/response.py", line 1271, in read_chunked
      decoded = self._decode(
                ^^^^^^^^^^^^^
    File "/usr/lib/python3/dist-packages/urllib3/response.py", line 613, in _decode
      data = self._decoder.decompress(data, max_length=max_length)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File "/usr/lib/python3/dist-packages/urllib3/response.py", line 267, in decompress
      part = self._obj.decompress(data, max_length=max_length)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  TypeError: decompress() takes at most 1 argument (2 given)

  
  I was able to workaround the issue by making the following change (which disables the "fix"):

  --- /storage/root/_btrbk/@.20251219//usr/lib/python3/dist-packages/urllib3/response.py	2025-12-10 14:26:11.000000000 -0500
  +++ /usr/lib/python3/dist-packages/urllib3/response.py	2025-12-19 22:02:38.609540775 -0500
  @@ -264,7 +264,7 @@
               if self._obj.eof:
                   data = self._obj.unused_data + data
                   self._obj = zstd.ZstdDecompressor().decompressobj()
  -            part = self._obj.decompress(data, max_length=max_length)
  +            part = self._obj.decompress(data)
               length = len(part)
               data_parts = [part]
               # Every loop iteration is supposed to read data from a separate frame.
  @@ -294,7 +294,7 @@

           @property
           def has_unconsumed_tail(self) -> bool:
  -            return not (self._obj.needs_input or self._obj.eof) or bool(
  +            return not self._obj.eof or bool(
                   self._obj.unused_data
               )

  Some info:
  Ubuntu 24.04.3 amd64
  python3-urllib3 2.0.7-1ubuntu0.3
  python3-zstandard 0.22.0-1build1

To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/python-urllib3/+bug/2136906/+subscriptions




More information about the Ubuntu-openstack-bugs mailing list