Control: tags 1131472 + patch
Control: tags 1131472 + pending

Dear maintainer,

I've prepared an NMU for deepdiff (versioned as 8.6.2-0.1) and uploaded 
it to DELAYED/2. Please feel free to tell me if I should cancel it.

cu
Adrian
diffstat for deepdiff-8.6.1 deepdiff-8.6.2

 .bumpversion.cfg            |    2 -
 AUTHORS.md                  |    1 
 CHANGELOG.md                |    3 ++
 CITATION.cff                |    2 -
 README.md                   |    7 ++++-
 debian/changelog            |    9 +++++++
 deepdiff/__init__.py        |    2 -
 deepdiff/serialization.py   |   35 ++++++++++++++++++++++++++++-
 docs/authors.rst            |    1 
 docs/changelog.rst          |    3 ++
 docs/conf.py                |    4 +--
 docs/index.rst              |    7 +++++
 pyproject.toml              |    2 -
 tests/test_serialization.py |   52 ++++++++++++++++++++++++++++++++++++++++++++
 14 files changed, 120 insertions(+), 10 deletions(-)

diff -Nru deepdiff-8.6.1/AUTHORS.md deepdiff-8.6.2/AUTHORS.md
--- deepdiff-8.6.1/AUTHORS.md	2025-09-03 22:38:30.000000000 +0300
+++ deepdiff-8.6.2/AUTHORS.md	2026-03-18 19:26:35.000000000 +0200
@@ -76,3 +76,4 @@
 - [Jim Cipar](https://github.com/jcipar) for the fix recursion depth limit when hashing numpy.datetime64
 - [Enji Cooper](https://github.com/ngie-eign) for converting legacy setuptools use to pyproject.toml
 - [Diogo Correia](https://github.com/diogotcorreia) for reporting security vulnerability in Delta and DeepDiff that could allow remote code execution.
+- [am-periphery](https://github.com/am-periphery) for reporting CVE-2026-33155: denial-of-service via crafted pickle payloads triggering massive memory allocation.
diff -Nru deepdiff-8.6.1/.bumpversion.cfg deepdiff-8.6.2/.bumpversion.cfg
--- deepdiff-8.6.1/.bumpversion.cfg	2025-09-03 22:38:30.000000000 +0300
+++ deepdiff-8.6.2/.bumpversion.cfg	2026-03-18 19:26:35.000000000 +0200
@@ -1,5 +1,5 @@
 [bumpversion]
-current_version = 8.6.1
+current_version = 8.6.2
 commit = True
 tag = True
 tag_name = {new_version}
diff -Nru deepdiff-8.6.1/CHANGELOG.md deepdiff-8.6.2/CHANGELOG.md
--- deepdiff-8.6.1/CHANGELOG.md	2025-09-03 22:38:30.000000000 +0300
+++ deepdiff-8.6.2/CHANGELOG.md	2026-03-18 19:26:35.000000000 +0200
@@ -1,5 +1,8 @@
 # DeepDiff Change log
 
+- v8-6-2
+    - Security fix (CVE-2026-33155): Prevent denial-of-service via crafted pickle payloads that trigger massive memory allocation through the REDUCE opcode. Size-sensitive callables like `bytes()` and `bytearray()` are now wrapped to reject allocations exceeding 128 MB.
+
 - v8-6-1
     - Patched security vulnerability in the Delta class which was vulnerable to class pollution via its constructor, and when combined with a gadget available in DeltaDiff itself, it could lead to Denial of Service and Remote Code Execution (via insecure Pickle deserialization).
 
diff -Nru deepdiff-8.6.1/CITATION.cff deepdiff-8.6.2/CITATION.cff
--- deepdiff-8.6.1/CITATION.cff	2025-09-03 22:38:30.000000000 +0300
+++ deepdiff-8.6.2/CITATION.cff	2026-03-18 19:26:35.000000000 +0200
@@ -5,6 +5,6 @@
   given-names: "Sep"
   orcid: "https://orcid.org/0009-0009-5828-4345";
 title: "DeepDiff"
-version: 8.6.1
+version: 8.6.2
 date-released: 2024
 url: "https://github.com/seperman/deepdiff";
diff -Nru deepdiff-8.6.1/debian/changelog deepdiff-8.6.2/debian/changelog
--- deepdiff-8.6.1/debian/changelog	2025-12-22 19:20:48.000000000 +0200
+++ deepdiff-8.6.2/debian/changelog	2026-05-06 21:17:37.000000000 +0300
@@ -1,3 +1,12 @@
+deepdiff (8.6.2-0.1) unstable; urgency=medium
+
+  * Non-maintainer upload.
+  * New upstream release.
+    - CVE-2026-33155: Memory Exhaustion DoS through SAFE_TO_IMPORT
+      (Closes: #1131472)
+
+ -- Adrian Bunk <[email protected]>  Wed, 06 May 2026 21:17:37 +0300
+
 deepdiff (8.6.1-1) unstable; urgency=medium
 
   * Team upload.
diff -Nru deepdiff-8.6.1/deepdiff/__init__.py deepdiff-8.6.2/deepdiff/__init__.py
--- deepdiff-8.6.1/deepdiff/__init__.py	2025-09-03 22:38:30.000000000 +0300
+++ deepdiff-8.6.2/deepdiff/__init__.py	2026-03-18 19:26:35.000000000 +0200
@@ -1,6 +1,6 @@
 """This module offers the DeepDiff, DeepSearch, grep, Delta and DeepHash classes."""
 # flake8: noqa
-__version__ = '8.6.1'
+__version__ = '8.6.2'
 import logging
 
 if __name__ == '__main__':
diff -Nru deepdiff-8.6.1/deepdiff/serialization.py deepdiff-8.6.2/deepdiff/serialization.py
--- deepdiff-8.6.1/deepdiff/serialization.py	2025-09-03 22:38:30.000000000 +0300
+++ deepdiff-8.6.2/deepdiff/serialization.py	2026-03-18 19:26:35.000000000 +0200
@@ -331,6 +331,35 @@
         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-2026-33155)
+_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):
@@ -355,7 +384,11 @@
                 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 -Nru deepdiff-8.6.1/docs/authors.rst deepdiff-8.6.2/docs/authors.rst
--- deepdiff-8.6.1/docs/authors.rst	2025-09-03 22:38:30.000000000 +0300
+++ deepdiff-8.6.2/docs/authors.rst	2026-03-18 19:26:35.000000000 +0200
@@ -118,6 +118,7 @@
 - `Enji Cooper <https://github.com/ngie-eign>`__ for converting legacy
   setuptools use to pyproject.toml
 - `Diogo Correia <https://github.com/diogotcorreia>`__ for reporting security vulnerability in Delta and DeepDiff that could allow remote code execution.
+- `am-periphery <https://github.com/am-periphery>`__ for reporting CVE-2026-33155: denial-of-service via crafted pickle payloads triggering massive memory allocation.
 
 
 .. _Sep Dehpour (Seperman): http://www.zepworks.com
diff -Nru deepdiff-8.6.1/docs/changelog.rst deepdiff-8.6.2/docs/changelog.rst
--- deepdiff-8.6.1/docs/changelog.rst	2025-09-03 22:38:30.000000000 +0300
+++ deepdiff-8.6.2/docs/changelog.rst	2026-03-18 19:26:35.000000000 +0200
@@ -5,6 +5,9 @@
 
 DeepDiff Changelog
 
+- v8-6-2
+   - Security fix (CVE-2026-33155): Prevent denial-of-service via crafted pickle payloads that trigger massive memory allocation through the REDUCE opcode. Size-sensitive callables like ``bytes()`` and ``bytearray()`` are now wrapped to reject allocations exceeding 128 MB.
+
 - v8-6-1
    - Patched security vulnerability in the Delta class which was vulnerable to class pollution via its constructor, and when combined with a gadget available in DeltaDiff itself, it could lead to Denial of Service and Remote Code Execution (via insecure Pickle deserialization).
 
diff -Nru deepdiff-8.6.1/docs/conf.py deepdiff-8.6.2/docs/conf.py
--- deepdiff-8.6.1/docs/conf.py	2025-09-03 22:38:30.000000000 +0300
+++ deepdiff-8.6.2/docs/conf.py	2026-03-18 19:26:35.000000000 +0200
@@ -64,9 +64,9 @@
 # built documents.
 #
 # The short X.Y version.
-version = '8.6.1'
+version = '8.6.2'
 # The full version, including alpha/beta/rc tags.
-release = '8.6.1'
+release = '8.6.2'
 
 load_dotenv(override=True)
 DOC_VERSION = os.environ.get('DOC_VERSION', version)
diff -Nru deepdiff-8.6.1/docs/index.rst deepdiff-8.6.2/docs/index.rst
--- deepdiff-8.6.1/docs/index.rst	2025-09-03 22:38:30.000000000 +0300
+++ deepdiff-8.6.2/docs/index.rst	2026-03-18 19:26:35.000000000 +0200
@@ -4,7 +4,7 @@
    contain the root `toctree` directive.
 
 
-DeepDiff 8.6.1 documentation!
+DeepDiff 8.6.2 documentation!
 =============================
 
 *******
@@ -31,6 +31,11 @@
 What Is New
 ***********
 
+DeepDiff 8-6-2
+--------------
+
+    - Security fix (CVE-2026-33155): Prevent denial-of-service via crafted pickle payloads that trigger massive memory allocation through the REDUCE opcode. Size-sensitive callables like ``bytes()`` and ``bytearray()`` are now wrapped to reject allocations exceeding 128 MB.
+
 DeepDiff 8-6-1
 --------------
 
diff -Nru deepdiff-8.6.1/pyproject.toml deepdiff-8.6.2/pyproject.toml
--- deepdiff-8.6.1/pyproject.toml	2025-09-03 22:38:30.000000000 +0300
+++ deepdiff-8.6.2/pyproject.toml	2026-03-18 19:26:35.000000000 +0200
@@ -4,7 +4,7 @@
 
 [project]
 name = "deepdiff"
-version = "8.6.1"
+version = "8.6.2"
 dependencies = [
   "orderly-set>=5.4.1,<6",
 ]
diff -Nru deepdiff-8.6.1/README.md deepdiff-8.6.2/README.md
--- deepdiff-8.6.1/README.md	2025-09-03 22:38:30.000000000 +0300
+++ deepdiff-8.6.2/README.md	2026-03-18 19:26:35.000000000 +0200
@@ -1,4 +1,4 @@
-# DeepDiff v 8.6.1
+# DeepDiff v 8.6.2
 
 ![Downloads](https://img.shields.io/pypi/dm/deepdiff.svg?style=flat)
 ![Python Versions](https://img.shields.io/pypi/pyversions/deepdiff.svg?style=flat)
@@ -17,12 +17,15 @@
 
 Tested on Python 3.9+ and PyPy3.
 
-- **[Documentation](https://zepworks.com/deepdiff/8.6.1/)**
+- **[Documentation](https://zepworks.com/deepdiff/8.6.2/)**
 
 ## What is new?
 
 Please check the [ChangeLog](CHANGELOG.md) file for the detailed information.
 
+DeepDiff 8-6-2
+- **Security (CVE-2026-33155):** Fixed a memory exhaustion DoS vulnerability in `_RestrictedUnpickler` by limiting the maximum allocation size for `bytes` and `bytearray` during deserialization.
+
 DeepDiff 8-6-1
 - Patched security vulnerability in the Delta class which was vulnerable to class pollution via its constructor, and when combined with a gadget available in DeltaDiff itself, it could lead to Denial of Service and Remote Code Execution (via insecure Pickle deserialization).
 
diff -Nru deepdiff-8.6.1/tests/test_serialization.py deepdiff-8.6.2/tests/test_serialization.py
--- deepdiff-8.6.1/tests/test_serialization.py	2025-09-03 22:38:30.000000000 +0300
+++ deepdiff-8.6.2/tests/test_serialization.py	2026-03-18 19:26:35.000000000 +0200
@@ -155,6 +155,58 @@
             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):

Reply via email to