Full Report
Prototype Pollution is a vulnerability in JavaScript that allows for the overwriting of the __prototype__ object. By doing this, an attacker can overwrite the default properties of an object to cause all sorts of havoc. This is normally caused by blindly merging objects together. Does this similar vulnerability affect other languages? The author of this post dove into how this could be utilized in Python. Instead of prototype pollution the author coined this class pollution. There are dunder (double underscore) methods such as __str__() and attributes such as __class__. In Python, it is possible to overwrite these properties at run time. The functions __get/setattr__ and __get/setitem__ are used to set attributes about an object. If an attacker is able to set properties of a class arbitrarily using these functions, then we have class pollution. Similar to Prototype Pollution, this may happen when creating a Python class object from a JSON blob on the fly. This is where the fun begins! What else can be overwrite besides attributes of a class? It turns out, that the functions mentioned above are much more generalized than you would expect. Using the .__base__, an attacker can traverse up the hierarchy of objects indefinitely, with some limitations. The main limitation is that the field we want to overwrite must be in the same hierarchy in the inheritance chain. Or, the __globals can be traversed and overwritten with this as well! The author notes that this merging is more common than one would expect. The python version of lodash (pydash) had this exact problem in it. In an exploit demonstration with subprocess.Popen the author of the post overwrites the COMPSEC variable by traversing the globals to gain trivial command injection. There are an unlimited amount of primitives to view but many of them are going to be specific to the application in use. Overall, a super nifty vulnerability that you may come across some day! Love this post and vuln class.
Analysis Summary
# Vulnerability: Class Pollution in Python
## CVE Details
- **CVE ID:** CVE-2023-22475 (Specific to `pydash`), CVE-2021-23341 (General class pollution in various libraries)
- **CVSS Score:** 7.3 (High) - *Based on pydash implementation*
- **CWE:** CWE-1321: Improper Control of Configuration Parameters or Attempt to Access Object Attributes ('Prototype Pollution')
## Affected Systems
- **Products:** Python-based applications utilizing unsafe recursive merge functions or object-handling libraries.
- **Versions:**
- `pydash` versions prior to `< 6.0.0`.
- Custom Python implementations of `merge()`, `update()`, or `set_path()` functions that do not sanitize keys.
- **Configurations:** Applications that create or update Python class objects/dictionaries from untrusted JSON blobs or user-controlled input without strict schema validation.
## Vulnerability Description
Class Pollution is the Python equivalent of JavaScript's Prototype Pollution. It occurs when an attacker can control the keys and values used to update a Python object. By injecting "dunder" (double underscore) attributes such as `__class__`, `__base__`, `__globals__`, or `__init__`, an attacker can traverse the object hierarchy.
The flaw exists because Python allows runtime modification of class attributes. If a recursive merge function traverses an object using `setattr()` or `setitem()`, it can be tricked into leaving the local object's scope to modify the parent class or the global execution environment, affecting all instances of that class or influencing function defaults.
## Exploitation
- **Status:** PoC available; demonstrated in libraries like `pydash`.
- **Complexity:** Medium to High (requires understanding of the target's object hierarchy and available "gadgets").
- **Attack Vector:** Network (typically via API endpoints accepting JSON).
## Impact
- **Confidentiality:** High (Potential to leak secret keys, such as Flask's `SECRET_KEY`).
- **Integrity:** High (Can overwrite global variables, function defaults, or environmental variables like `COMSPEC`).
- **Availability:** High (Can lead to Denial of Service by corrupting critical class structures).
- **Remote Code Execution (RCE):** Possible via "gadgets" such as polluting `subprocess.Popen` via `__globals__` or hijacking `os.environ`.
## Remediation
### Patches
- **Pydash:** Upgrade to version `6.0.0` or higher, which includes fixes for deep path setting vulnerabilities.
- **General:** Implement strict validation for keys in merge functions to block any string starting with `__`.
### Workarounds
- **Input Validation:** Use JSON schema validation to ensure input objects contain only expected fields.
- **Immutable Types:** Use `MappingProxyType` or named tuples for internal configurations that should not be modified at runtime.
- **Sanitization:** Explicitly filter out keys like `__class__`, `__base__`, `__globals__`, `__init__`, and `__subclasses__` before processing untrusted dictionaries.
## Detection
- **Indicators of Compromise:** Unusual application behavior (e.g., changed default values), presence of `__class__` or `__globals__` strings in web server logs or JSON payloads.
- **Detection Methods:**
- Static Analysis (SAST) to identify recursive merge functions using `setattr` without key filtering.
- Dynamic Analysis (DAST) by attempting to inject `{"__class__": {"test": "polluted"}}` into API endpoints and checking for the attribute on the backend.
## References
- hxxps://blog[.]abdulrah33m[.]com/prototype-pollution-in-python/
- hxxps://github[.]com/dgilland/pydash/releases/tag/v6.0.0
- hxxps://portswigger[.]net/daily-swig/prototype-pollution-the-dangerous-and-underrated-vulnerability-impacting-javascript-applications
- hxxps://cwe[.]mitre[.]org/data/definitions/1321[.]html