Update dependency deepdiff to v8 [SECURITY] #38
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR contains the following updates:
==7.0.*->==8.6.*GitHub Vulnerability Alerts
CVE-2025-58367
Summary
Python class pollution is a novel vulnerability categorized under CWE-915. The
Deltaclass is vulnerable to class pollution via its constructor, and when combined with a gadget available in DeltaDiff itself, it can lead to Denial of Service and Remote Code Execution (via insecure Pickle deserialization).The gadget available in DeepDiff allows
deepdiff.serialization.SAFE_TO_IMPORTto be modified to allow dangerous classes such asposix.system, and then perform insecure Pickle deserialization via the Delta class. This potentially allows any Python code to be executed, given that the input toDeltais user-controlled.Depending on the application where DeepDiff is used, this can also lead to other vulnerabilities. For example, in a web application, it might be possible to bypass authentication via class pollution.
Details
The
Deltaclass can take different object types as a parameter in its constructor, such as aDeltaDiffobject, a dictionary, or even just bytes (that are deserialized via Pickle).When it takes a dictionary, it is usually in the following format:
Trying to apply class pollution here does not work, because there is already a filter in place: https://github.com/seperman/deepdiff/blob/b639fece73fe3ce4120261fdcff3cc7b826776e3/deepdiff/path.py#L23
However, this code only runs when parsing the path from a string.
The
_path_to_elementsfunction helpfully returns the given input if it is already a list/tuple:https://github.com/seperman/deepdiff/blob/b639fece73fe3ce4120261fdcff3cc7b826776e3/deepdiff/path.py#L52-L53
This means that it is possible to pass the path as the internal representation used by Delta, bypassing the filter:
Going back to the possible inputs of
Delta, when it takes abytesas input, it uses pickle to deserialize them.Care was taken by DeepDiff to prevent arbitrary code execution via the
SAFE_TO_IMPORTallow list.https://github.com/seperman/deepdiff/blob/b639fece73fe3ce4120261fdcff3cc7b826776e3/deepdiff/serialization.py#L62-L98
However, using the class pollution in the
Delta, an attacker can add new entries to thisset.This then allows a second call to
Deltato unpickle an insecure class that runsos.system, for example.Using dict
Usually, class pollution does not work when traversal starts at a
dict/list/tuple, because it is not possible to reach__globals__from there.However, using two calls to
Delta(or just one call if the target dictionary that already contains at least one entry) it is possible to first change one entry of the dictionary to be of typedeepdiff.helper.Opcode, which then allows traversal to__globals__, and notablysys.modules, which in turn allows traversal to any module already loaded by Python.Passing
Opcodearound can be done via pickle, whichDeltawill happily accept given it is in the default allow list.Proof of Concept
With deepdiff 8.6.0 installed, run the following scripts for each proof of concept.
All input to
Deltais assumed to be user-controlled.Denial of Service
This script will pollute the value of
builtins.int, preventing the class from being used and making code crash whenever invoked.Remote Code Execution
This script will create a file at
/tmp/pwnedwith the output ofid.Who is affected?
Only applications that pass (untrusted) user input directly into
Deltaare affected.While input in the form of
bytesis the most flexible, there are certainly other gadgets, depending on the application, that can be used via just a dictionary. This dictionary could easily be parsed, for example, from JSON. One simple example would be overridingapp.secret_keyof a Flask application, which would allow an attacker to sign arbitrary cookies, leading to an authentication bypass.Mitigations
A straightforward mitigation is preventing traversal through private keys, like it is already done in the path parser.
This would have to be implemented in both
deepdiff.path._get_nested_objanddeepdiff.path._get_nested_obj_and_force,and possibly in
deepdiff.delta.Delta._get_elements_and_details.Example code that raises an error when traversing these properties:
However, if it is desirable to still support attributes starting and ending with
__, but still protect against this vulnerability, it is possible to only forbid__globals__and__builtins__, which stops the most serious cases of class pollution (but not all).This was the solution adopted by pydash: https://github.com/dgilland/pydash/issues/180
Release Notes
seperman/deepdiff (deepdiff)
v8.6.1Compare Source
DeepDiff 8-6-1
v8.6.0Compare Source
v8.5.0v8.4.1Compare Source
v8.4.0Compare Source
v8.3.0Compare Source
v8.2.0Compare Source
v8.1.1Compare Source
Adding Python 3.13 to setup.py
v8.1.0Compare Source
prefixoption topretty()v8.0.1Compare Source
8.0.1 - extra import of numpy is removed
v8.0.0Compare Source
With the introduction of
threshold_to_diff_deeper, the values returned are different than in previous versions of DeepDiff. You can still get the older values by settingthreshold_to_diff_deeper=0. However to signify that enough has changed in this release that the users need to update the parameters passed to DeepDiff, we will be doing a major version update.use_enum_value=Truemakes it so when diffing enum, we use the enum's value. It makes it so comparing an enum to a string or any other value is not reported as a type change.threshold_to_diff_deeper=floatis a number between 0 and 1. When comparing dictionaries that have a small intersection of keys, we will report the dictionary as anew_valueinstead of reporting individual keys changed. If you set it to zero, you get the same results as DeepDiff 7.0.1 and earlier, which means this feature is disabled. The new default is 0.33 which means if less that one third of keys between dictionaries intersect, report it as a new object.ordered-setand switched toorderly-set. Theordered-setpackage was not being maintained anymore and starting Python 3.6, there were better options for sets that ordered. I forked one of the new implementations, modified it, and published it asorderly-set.use_log_scale:boolandlog_scale_similarity_threshold:float. They can be used to ignore small changes in numbers by comparing their differences in logarithmic space. This is different than ignoring the difference based on significant digits.iterable_compare_funcis used.v7.0.1new_pathwhen thepathandnew_pathare different (for example when ignore_order=True and the index of items have changed).datetime.dateobjects where it treated them as numbers instead of dates (fixes #445).Configuration
📅 Schedule: Branch creation - "" (UTC), Automerge - At any time (no schedule defined).
🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR was generated by Mend Renovate. View the repository job log.