Miggo Logo

CVE-2025-61622: Apache Pyfory python is vulnerable to deserialization of untrusted data

9.8

CVSS Score
3.1

Basic Information

EPSS Score
0.53179%
Published
10/1/2025
Updated
10/1/2025
KEV Status
No
Technology
TechnologyPython

Technical Details

CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Package NameEcosystemVulnerable VersionsFirst Patched Version
pyforypip>= 0.12.0, < 0.12.30.12.3
pyfurypip>= 0.1.0, <= 0.10.3

Vulnerability Intelligence
Miggo AIMiggo AI

Miggo AIRoot Cause Analysis

The vulnerability, CVE-2025-61622, is a critical deserialization of untrusted data flaw in Apache Fory (pyfory). The root cause is the use of a pickle-based fallback mechanism for deserializing object types that were not explicitly registered or supported. An attacker could craft a malicious data stream that, when deserialized, would force the application to use pickle.loads, leading to arbitrary code execution.

The analysis of the patch commit 379b948ecae5c3b849e5bdb3997978c9a163e40b reveals that the core of the vulnerability was in the Fory.handle_unsupported_read method, which existed in both a pure Python (_fory.py) and a Cython (_serialization.pyx) implementation. This method was responsible for invoking pickle.load (via a pickle.Unpickler instance) on the incoming data stream if the object type was not recognized.

Several serializers, such as DynamicPyArraySerializer and NDArraySerializer, relied on this insecure fallback mechanism, making them part of the vulnerable execution path. The patch addresses the vulnerability by completely removing the pickle-based fallback. The handle_unsupported_read methods were modified to no longer use pickle, and the serializers that depended on this behavior were updated to use safer, more explicit deserialization logic. The PickleSerializer class, which was the most direct implementation of this insecure behavior, was removed entirely. Therefore, any runtime profile during exploitation would have shown calls to these identified functions before the patch was applied.

Vulnerable functions

Fory.handle_unsupported_read
python/pyfory/_fory.py
This function is the core of the vulnerability. When deserializing an object of an unsupported type, this function was called. The vulnerable version would then use `pickle.load` (via `unpickler.load()`) to deserialize the data. An attacker could craft a serialized data stream that, when processed by this function, would lead to arbitrary code execution. The patch removes the pickle-based deserialization logic entirely.
Fory.handle_unsupported_read
python/pyfory/_serialization.pyx
This is the Cython implementation of the same vulnerable function `handle_unsupported_read`. It shares the same vulnerability as its Python counterpart, using `unpickler.load()` to deserialize untrusted data, which allows for remote code execution. The patch removes this insecure deserialization path.
PickleSerializer.read
python/pyfory/serializer.py
This serializer was explicitly designed to use pickle as a fallback. Its `read` method directly called the vulnerable `fory.handle_unsupported_read` function, making it a primary pathway for the exploit. The entire `PickleSerializer` class was removed in the patch to mitigate the vulnerability.
DynamicPyArraySerializer.read
python/pyfory/serializer.py
The serializer for dynamic Python arrays previously relied on the insecure pickle fallback mechanism by calling `fory.handle_unsupported_read`. This meant that a specially crafted array object in the input stream could trigger the pickle deserialization vulnerability. The patch changes this to use the safer `ReduceSerializer`.
NDArraySerializer.read
python/pyfory/serializer.py
Similar to `DynamicPyArraySerializer`, the serializer for numpy n-dimensional arrays also used the vulnerable `fory.handle_unsupported_read` as a fallback. This exposed the application to the same deserialization vulnerability when handling numpy arrays. The patch replaces the dangerous fallback with a safe, explicit implementation for deserializing numpy arrays.

WAF Protection Rules

WAF Rule

**s*ri*liz*tion o* untrust** **t* in pyt*on in py*ory v*rsions *.**.* t*rou** *.**.*, or t** l****y py*ury v*rsions *rom *.*.* t*rou** *.**.*: *llows *r*itr*ry *o** *x**ution. *n *ppli**tion is vuln*r**l* i* it r***s py*ory s*ri*liz** **t* *rom untru

Reasoning

T** vuln*r**ility, *V*-****-*****, is * *riti**l **s*ri*liz*tion o* untrust** **t* *l*w in *p**** *ory (py*ory). T** root **us* is t** us* o* * pi*kl*-**s** **ll***k m****nism *or **s*ri*lizin* o*j**t typ*s t**t w*r* not *xpli*itly r**ist*r** or supp