Your message dated Sat, 11 Jul 2026 10:32:47 +0000
with message-id <[email protected]>
and subject line Released in 13.6
has caused the Debian Bug report #1141284,
regarding trixie-pu: package deepdiff/8.1.1-4+deb13u1
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact [email protected]
immediately.)


-- 
1141284: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1141284
Debian Bug Tracking System
Contact [email protected] with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
Tags: trixie
X-Debbugs-Cc: [email protected], [email protected]
Control: affects -1 + src:deepdiff
User: [email protected]
Usertags: pu

  * CVE-2025-58367: Class Pollution in Delta class
  * CVE-2026-33155: Memory Exhaustion DoS through SAFE_TO_IMPORT
    (Closes: #1131472)
diffstat for deepdiff-8.1.1 deepdiff-8.1.1

 changelog                                                               |    9 
 patches/0001-Security-fix-Prevent-class-pollution-and-remote-code.patch |  246 
++++++++++
 patches/0002-Fix-CVE-2026-33155.patch                                   |  147 
+++++
 patches/series                                                          |    2 
 4 files changed, 404 insertions(+)

diff -Nru deepdiff-8.1.1/debian/changelog deepdiff-8.1.1/debian/changelog
--- deepdiff-8.1.1/debian/changelog     2025-05-14 20:23:39.000000000 +0300
+++ deepdiff-8.1.1/debian/changelog     2026-07-02 19:38:08.000000000 +0300
@@ -1,3 +1,12 @@
+deepdiff (8.1.1-4+deb13u1) trixie; urgency=medium
+
+  * Non-maintainer upload.
+  * CVE-2025-58367: Class Pollution in Delta class
+  * CVE-2026-33155: Memory Exhaustion DoS through SAFE_TO_IMPORT
+    (Closes: #1131472)
+
+ -- Adrian Bunk <[email protected]>  Thu, 02 Jul 2026 19:38:08 +0300
+
 deepdiff (8.1.1-4) unstable; urgency=medium
 
   * Team upload.
diff -Nru 
deepdiff-8.1.1/debian/patches/0001-Security-fix-Prevent-class-pollution-and-remote-code.patch
 
deepdiff-8.1.1/debian/patches/0001-Security-fix-Prevent-class-pollution-and-remote-code.patch
--- 
deepdiff-8.1.1/debian/patches/0001-Security-fix-Prevent-class-pollution-and-remote-code.patch
       1970-01-01 02:00:00.000000000 +0200
+++ 
deepdiff-8.1.1/debian/patches/0001-Security-fix-Prevent-class-pollution-and-remote-code.patch
       2026-07-02 19:36:49.000000000 +0300
@@ -0,0 +1,246 @@
+From b73249762552ab0cc232e68b3c977b53bb5651f3 Mon Sep 17 00:00:00 2001
+From: Sep Dehpour <[email protected]>
+Date: Wed, 3 Sep 2025 09:42:30 -0700
+Subject: Security fix: Prevent class pollution and remote code execution in
+ Delta
+
+- Add validation to prevent traversing dunder attributes via check_elem()
+- Harden Delta class against malicious pickle payloads
+- Make SAFE_TO_IMPORT a frozenset for immutability
+- Add comprehensive security tests in test_security.py
+- Prevent access to __globals__ and other dangerous attributes
+---
+ deepdiff/delta.py         |   8 ++-
+ deepdiff/path.py          |   7 ++
+ deepdiff/serialization.py |   4 +-
+ tests/test_security.py    | 133 ++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 149 insertions(+), 3 deletions(-)
+ create mode 100644 tests/test_security.py
+
+diff --git a/deepdiff/delta.py b/deepdiff/delta.py
+index 8bafc9a..6d152f4 100644
+--- a/deepdiff/delta.py
++++ b/deepdiff/delta.py
+@@ -17,7 +17,7 @@ from deepdiff.helper import (
+ )
+ from deepdiff.path import (
+     _path_to_elements, _get_nested_obj, _get_nested_obj_and_force,
+-    GET, GETATTR, parse_path, stringify_path,
++    GET, GETATTR, check_elem, parse_path, stringify_path,
+ )
+ from deepdiff.anyset import AnySet
+ 
+@@ -235,6 +235,11 @@ class Delta:
+         forced_old_value=None,
+         next_element=None,
+     ):
++        try:
++            check_elem(elem)
++        except ValueError as error:
++            
self._raise_or_log(UNABLE_TO_GET_ITEM_MSG.format(path_for_err_reporting, error))
++            return not_found
+         # if forced_old_value is not None:
+         try:
+             if action == GET:
+@@ -517,6 +522,7 @@ class Delta:
+                 obj = self
+                 # obj = self.get_nested_obj(obj=self, elements=elements[:-1])
+             elem, action = elements[-1]
++            check_elem(elem)
+         except Exception as e:
+             self._raise_or_log(UNABLE_TO_GET_ITEM_MSG.format(path, e))
+             return None
+diff --git a/deepdiff/path.py b/deepdiff/path.py
+index ee63b5b..e5b64c7 100644
+--- a/deepdiff/path.py
++++ b/deepdiff/path.py
+@@ -117,6 +117,7 @@ def _path_to_elements(path, 
root_element=DEFAULT_FIRST_ELEMENT):
+ 
+ def _get_nested_obj(obj, elements, next_element=None):
+     for (elem, action) in elements:
++        check_elem(elem)
+         if action == GET:
+             obj = obj[elem]
+         elif action == GETATTR:
+@@ -134,11 +135,17 @@ def _guess_type(elements, elem, index, next_element):
+     return {}
+ 
+ 
++def check_elem(elem):
++    if isinstance(elem, str) and elem.startswith("__") and 
elem.endswith("__"):
++        raise ValueError("traversing dunder attributes is not allowed")
++
++
+ def _get_nested_obj_and_force(obj, elements, next_element=None):
+     prev_elem = None
+     prev_action = None
+     prev_obj = obj
+     for index, (elem, action) in enumerate(elements):
++        check_elem(elem)
+         _prev_obj = obj
+         if action == GET:
+             try:
+diff --git a/deepdiff/serialization.py b/deepdiff/serialization.py
+index 4119742..9884c06 100644
+--- a/deepdiff/serialization.py
++++ b/deepdiff/serialization.py
+@@ -81,7 +81,7 @@ FORBIDDEN_MODULE_MSG = "Module '{}' is forbidden. You need 
to explicitly pass it
+ DELTA_IGNORE_ORDER_NEEDS_REPETITION_REPORT = 'report_repetition must be set 
to True when ignore_order is True to create the delta object.'
+ DELTA_ERROR_WHEN_GROUP_BY = 'Delta can not be made when group_by is used 
since the structure of data is modified from the original form.'
+ 
+-SAFE_TO_IMPORT = {
++SAFE_TO_IMPORT = frozenset({
+     'builtins.range',
+     'builtins.complex',
+     'builtins.set',
+@@ -110,7 +110,7 @@ SAFE_TO_IMPORT = {
+     'collections.OrderedDict',
+     're.Pattern',
+     'deepdiff.helper.Opcode',
+-}
++})
+ 
+ 
+ TYPE_STR_TO_TYPE = {
+diff --git a/tests/test_security.py b/tests/test_security.py
+new file mode 100644
+index 0000000..e221018
+--- /dev/null
++++ b/tests/test_security.py
+@@ -0,0 +1,133 @@
++import os
++import pickle
++import pytest
++from deepdiff import Delta
++from deepdiff.helper import Opcode
++from deepdiff.serialization import ForbiddenModule
++
++
++class TestDeltaClassPollution:
++
++    def test_builtins_int(self):
++
++        pollute_int = pickle.dumps(
++            {
++                "values_changed": {"root['tmp']": {"new_value": Opcode("", 0, 
0, 0, 0)}},
++                "dictionary_item_added": {
++                    (
++                        ("root", "GETATTR"),
++                        ("tmp", "GET"),
++                        ("__repr__", "GETATTR"),
++                        ("__globals__", "GETATTR"),
++                        ("__builtins__", "GET"),
++                        ("int", "GET"),
++                    ): "no longer a class"
++                },
++            }
++        )
++
++        assert isinstance(pollute_int, bytes)
++
++        # ------------[ Exploit ]------------
++        # This could be some example, vulnerable, application.
++        # The inputs above could be sent via HTTP, for example.
++
++
++        # Existing dictionary; it is assumed that it contains
++        # at least one entry, otherwise a different Delta needs to be
++        # applied first, adding an entry to the dictionary.
++        mydict = {"tmp": "foobar"}
++
++        # Before pollution
++        assert 42 == int("41") + 1
++
++        # Apply Delta to mydict
++        result = mydict + Delta(pollute_int)
++
++        assert 1337 == int("1337")
++
++    def test_remote_code_execution(self):
++        if os.path.exists('/tmp/pwned'):
++            os.remove('/tmp/pwned')
++
++        pollute_safe_to_import = pickle.dumps(
++            {
++                "values_changed": {"root['tmp']": {"new_value": Opcode("", 0, 
0, 0, 0)}},
++                "set_item_added": {
++                    (
++                        ("root", "GETATTR"),
++                        ("tmp", "GET"),
++                        ("__repr__", "GETATTR"),
++                        ("__globals__", "GETATTR"),
++                        ("sys", "GET"),
++                        ("modules", "GETATTR"),
++                        ("deepdiff.serialization", "GET"),
++                        ("SAFE_TO_IMPORT", "GETATTR"),
++                    ): set(["posix.system"])
++                },
++            }
++        )
++
++        # From https://davidhamann.de/2020/04/05/exploiting-python-pickle/
++        class RCE:
++            def __reduce__(self):
++                cmd = "id > /tmp/pwned"
++                return os.system, (cmd,)
++
++        # Wrap object with dictionary so that Delta does not crash
++        rce_pickle = pickle.dumps({"_": RCE()})
++
++        assert isinstance(pollute_safe_to_import, bytes)
++        assert isinstance(rce_pickle, bytes)
++
++        # ------------[ Exploit ]------------
++        # This could be some example, vulnerable, application.
++        # The inputs above could be sent via HTTP, for example.
++
++        # Existing dictionary; it is assumed that it contains
++        # at least one entry, otherwise a different Delta needs to be
++        # applied first, adding an entry to the dictionary.
++        mydict = {"tmp": "foobar"}
++
++        # Apply Delta to mydict
++        with pytest.raises(ValueError) as exc_info:
++            mydict + Delta(pollute_safe_to_import)
++        assert "traversing dunder attributes is not allowed" == 
str(exc_info.value)
++
++        with pytest.raises(ForbiddenModule) as exc_info:
++            Delta(rce_pickle)  # no need to apply this Delta
++        assert "Module 'posix.system' is forbidden. You need to explicitly 
pass it by passing a safe_to_import parameter" == str(exc_info.value)
++
++        assert not os.path.exists('/tmp/pwned'), "We should not have created 
this file"
++
++    def test_delta_should_not_access_globals(self):
++
++        pollute_global = pickle.dumps(
++            {
++                "dictionary_item_added": {
++                    (
++                        ("root", "GETATTR"),
++                        ("myfunc", "GETATTR"),
++                        ("__globals__", "GETATTR"),
++                        ("PWNED", "GET"),
++                    ): 1337
++                }
++            }
++        )
++
++
++        # demo application
++        class Foo:
++            def __init__(self):
++                pass
++
++            def myfunc(self):
++                pass
++
++
++        PWNED = False
++        delta = Delta(pollute_global)
++        assert PWNED is False
++        b = Foo() + delta
++
++        assert PWNED is False
+-- 
+2.47.3
+
diff -Nru deepdiff-8.1.1/debian/patches/0002-Fix-CVE-2026-33155.patch 
deepdiff-8.1.1/debian/patches/0002-Fix-CVE-2026-33155.patch
--- deepdiff-8.1.1/debian/patches/0002-Fix-CVE-2026-33155.patch 1970-01-01 
02:00:00.000000000 +0200
+++ deepdiff-8.1.1/debian/patches/0002-Fix-CVE-2026-33155.patch 2026-07-02 
19:36:49.000000000 +0300
@@ -0,0 +1,147 @@
+From 40df1ccd17ef5aace418832c0d07adf7254d1ae4 Mon Sep 17 00:00:00 2001
+From: Sep Dehpour <[email protected]>
+Date: Tue, 17 Mar 2026 10:52:13 -0700
+Subject: Fix (CVE-2026-33155)
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+  deepdiff/serialization.py — Added a _SafeConstructor wrapper class that 
intercepts calls to
+  size-sensitive constructors (like bytes and bytearray) during pickle 
deserialization. When
+  find_class returns one of these types, it wraps it in _SafeConstructor, 
which validates that no
+  integer argument exceeds _MAX_ALLOC_SIZE (128MB) before allowing the call. 
This prevents payloads
+  like bytes(10**10) from causing memory exhaustion while still allowing 
legitimate small
+  allocations.
+
+  Tests
+
+  tests/test_serialization.py — Added TestPicklingSecurity class with two 
tests:
+  1. test_restricted_unpickler_memory_exhaustion_cve — Reproduces the attack 
with a crafted payload
+  attempting bytes(10_000_000_000), using resource.RLIMIT_AS to cap memory at 
500MB as a safety net.
+  Verifies the fix raises UnpicklingError before any allocation.
+  2. test_restricted_unpickler_allows_small_bytes — Ensures legitimate 
bytes(100) payloads still
+  deserialize correctly.
+---
+ deepdiff/serialization.py   | 35 ++++++++++++++++++++++++-
+ tests/test_serialization.py | 52 +++++++++++++++++++++++++++++++++++++
+ 2 files changed, 86 insertions(+), 1 deletion(-)
+
+diff --git a/deepdiff/serialization.py b/deepdiff/serialization.py
+index 9884c06..e961b31 100644
+--- a/deepdiff/serialization.py
++++ b/deepdiff/serialization.py
+@@ -335,6 +335,35 @@ class SerializationMixin:
+         return "\n".join(f"{prefix}{r}" for r in result)
+ 
+ 
++# Maximum size allowed for integer arguments to constructors that allocate
++# memory proportional to the argument (e.g. bytes(n), bytearray(n)).
++# This prevents denial-of-service via crafted pickle payloads. 
(CVE-2025-58367)
++_MAX_ALLOC_SIZE = 128 * 1024 * 1024  # 128 MB
++
++# Callables where an integer argument directly controls memory allocation 
size.
++_SIZE_SENSITIVE_CALLABLES = frozenset({bytes, bytearray})
++
++
++class _SafeConstructor:
++    """Wraps a type constructor to prevent excessive memory allocation via 
the REDUCE opcode."""
++    __slots__ = ('_wrapped',)
++
++    def __init__(self, wrapped):
++        self._wrapped = wrapped
++
++    def __call__(self, *args, **kwargs):
++        for arg in args:
++            if isinstance(arg, int) and arg > _MAX_ALLOC_SIZE:
++                raise pickle.UnpicklingError(
++                    "Refusing to create {}() with size {}: "
++                    "exceeds the maximum allowed size of {} bytes. "
++                    "This could be a denial-of-service attack 
payload.".format(
++                        self._wrapped.__name__, arg, _MAX_ALLOC_SIZE
++                    )
++                )
++        return self._wrapped(*args, **kwargs)
++
++
+ class _RestrictedUnpickler(pickle.Unpickler):
+ 
+     def __init__(self, *args, **kwargs):
+@@ -359,7 +388,11 @@ class _RestrictedUnpickler(pickle.Unpickler):
+                 module_obj = sys.modules[module]
+             except KeyError:
+                 raise 
ModuleNotFoundError(MODULE_NOT_FOUND_MSG.format(module_dot_class)) from None
+-            return getattr(module_obj, name)
++            cls = getattr(module_obj, name)
++            # Wrap size-sensitive callables to prevent DoS via large 
allocations
++            if cls in _SIZE_SENSITIVE_CALLABLES:
++                return _SafeConstructor(cls)
++            return cls
+         # Forbid everything else.
+         raise ForbiddenModule(FORBIDDEN_MODULE_MSG.format(module_dot_class)) 
from None
+ 
+diff --git a/tests/test_serialization.py b/tests/test_serialization.py
+index 3c50683..e3d693c 100644
+--- a/tests/test_serialization.py
++++ b/tests/test_serialization.py
+@@ -137,6 +137,58 @@ class TestLoadContet:
+             load_path_content(path)
+ 
+ 
++class TestPicklingSecurity:
++
++    @pytest.mark.skipif(sys.platform == "win32", reason="Resource module is 
Unix-only")
++    def test_restricted_unpickler_memory_exhaustion_cve(self):
++        """CVE-2026-33155: Prevent DoS via massive allocation through REDUCE 
opcode.
++
++        The payload calls bytes(10_000_000_000) which is allowed by find_class
++        but would allocate ~9.3GB of memory. The fix should reject this before
++        the allocation happens.
++        """
++        import resource
++
++        # 1. Cap memory to 500MB to prevent system freezes during the test
++        soft, hard = resource.getrlimit(resource.RLIMIT_AS)
++        maxsize_bytes = 500 * 1024 * 1024
++        resource.setrlimit(resource.RLIMIT_AS, (maxsize_bytes, hard))
++
++        try:
++            # 2. Malicious payload: attempts to allocate ~9.3GB via 
bytes(10000000000)
++            # This uses allowed builtins but passes a massive integer via 
REDUCE
++            payload = (
++                b"(dp0\n"
++                b"S'_'\n"
++                b"cbuiltins\nbytes\n"
++                b"(I10000000000\n"
++                b"tR"
++                b"s."
++            )
++
++            # 3. After the patch, deepdiff should catch the size violation
++            # and raise UnpicklingError before attempting allocation.
++            with pytest.raises((ValueError, UnpicklingError)):
++                pickle_load(payload)
++        finally:
++            # Restore original memory limit so other tests are not affected
++            resource.setrlimit(resource.RLIMIT_AS, (soft, hard))
++
++    def test_restricted_unpickler_allows_small_bytes(self):
++        """Ensure legitimate small bytes objects can still be deserialized."""
++        # Payload: {'_': bytes(100)} — well within the 128MB limit
++        payload = (
++            b"(dp0\n"
++            b"S'_'\n"
++            b"cbuiltins\nbytes\n"
++            b"(I100\n"
++            b"tR"
++            b"s."
++        )
++        result = pickle_load(payload)
++        assert result == {'_': bytes(100)}
++
++
+ class TestPickling:
+ 
+     def test_serialize(self):
+-- 
+2.47.3
+
diff -Nru deepdiff-8.1.1/debian/patches/series 
deepdiff-8.1.1/debian/patches/series
--- deepdiff-8.1.1/debian/patches/series        1970-01-01 02:00:00.000000000 
+0200
+++ deepdiff-8.1.1/debian/patches/series        2026-07-02 19:38:02.000000000 
+0300
@@ -0,0 +1,2 @@
+0001-Security-fix-Prevent-class-pollution-and-remote-code.patch
+0002-Fix-CVE-2026-33155.patch

--- End Message ---
--- Begin Message ---
Version: 13.6

This update was released as part of 13.6.

--- End Message ---

Reply via email to