Insecure Deserialization: Cookie Manipulation & RCE
What Are We Exploiting?
Modern web applications need to remember who you are between requests. One common approach is to serialize your session data (username, role, preferences) into a portable format and store it in a browser cookie. When you send the next request, the server reads the cookie and deserializes it to restore your session.
The problem: cookies are stored on the client. If the server does not cryptographically verify that the cookie was issued by itself, an attacker can modify every byte of it.
How Cookie Manipulation, Privilege Escalation, and RCE Connect
These terms describe different parts of the same attack chain:
- Cookie manipulation is the entry point. The browser sends the session cookie with each request, but the user controls what is stored in their own browser. Base64 encoding only changes how the bytes are represented; it does not protect them.
An HMAC (Hash-based Message Authentication Code) lets the server detect cookie tampering. When creating a cookie, the server combines the exact cookie bytes with a secret key known only to the server and calculates a short authentication tag. It sends both the cookie data and that tag to the browser. On a later request, the server calculates the HMAC again and compares it with the supplied tag:
cookie data + server secret key → HMAC tag
If an attacker changes role=user to role=admin, the recalculated tag no longer matches. Because the attacker does not know the secret key, they cannot calculate a valid replacement tag, so the server rejects the cookie before deserializing it. An HMAC provides integrity and authenticity—it proves that the data has not changed and was created by someone holding the key. It does not encrypt the cookie or hide its contents. The server must keep the key secret, verify the HMAC before calling pickle.loads(), and should still avoid using pickle for client-controlled session data.
- Insecure deserialization is the server-side vulnerability. The server trusts those attacker-controlled cookie bytes and passes them to
pickle.loads(). Deserialization is the moment when the bytes become a live Python object. Becausepicklecan reconstruct more than simple data, the cookie can influence both the object's values and the operations performed while rebuilding it.
- Privilege escalation is the first possible impact. A normal cookie might deserialize to
{"username": "alice", "role": "user"}. If an attacker forges it as{"username": "alice", "role": "admin"}and the application trusts that role, the attacker gains admin-only access. This is a data-only attack: no command has run, but the attacker's permissions have increased.
- Remote Code Execution is the more severe impact. Instead of supplying an object whose data says
role=admin, the attacker supplies a pickle object whose reconstruction instructions invoke a function such asos.system. When the server deserializes it, the command runs on the server, with the same operating-system permissions as the web application.
So the relationship is:
**attacker-controlled cookie → unsafe pickle.loads() → forged trusted data (privilege escalation) or executable reconstruction instructions (RCE)**
Privilege escalation is not what causes RCE, and admin access does not automatically mean code execution. They are two outcomes of the same underlying mistake: treating an untrusted, unsigned cookie as a trusted serialized Python object. This lab demonstrates them in sequence so you can first see the trust boundary fail through a visible role change, then see the full danger of the same deserialization sink.
Python's pickle Module
Python's pickle module is dangerous with untrusted input because a pickle is not just a collection of passive values. It can contain instructions for reconstructing Python objects, including instructions to import modules, locate functions, and call those functions with supplied arguments. pickle.loads() follows those instructions automatically while loading the object.
That makes pickle fundamentally different from a normal JSON parser:
- JSON describes a limited set of data values such as strings, numbers, lists, and dictionaries.
- Pickle can describe how Python should rebuild complex objects and invoke callables as part of that process.
- The dangerous operation happens **during
pickle.loads()**, before the application can inspect the resulting object or validate fields such asrole. - Base64 encoding, hiding the cookie, or checking fields after loading does not make it safe. The malicious operation may already have executed.
One mechanism pickle uses is the __reduce__ method. It can tell the deserializer, “reconstruct this object by calling this function with these arguments.” An attacker can abuse that behavior to select a dangerous callable:
import pickle, os
class Exploit(object):
def __reduce__(self):
return (os.system, ('cat /flag.txt',))
# When the server calls pickle.loads(our_bytes) → os.system('cat /flag.txt') runsThe server does not need to call os.system() itself after loading the cookie. Loading the malicious pickle is what triggers the call. The command then runs with the operating-system permissions of the web application.
Pickle is useful for trusted Python-to-Python storage, but it is not a safe interchange format for attacker-controlled data. Any endpoint that passes data you control to pickle.loads() should therefore be treated as a potential Remote Code Execution sink. Prefer a data-only format such as JSON with schema validation, and cryptographically sign client-side session data—or keep session state on the server—so tampering is rejected before parsing.
Real-World Impact
The 2019 Citrix ADC vulnerability (CVE-2019-19781) and dozens of Java deserialization CVEs in Jenkins, Apache Commons, and WebLogic all follow this pattern. In every case, an attacker sent a crafted serialized blob and gained full server access — no credentials required.
OWASP A08:2021 — Software and Data Integrity Failures covers insecure deserialization and consistently rates its impact as Critical.
What You Will Do in This Lab
PickleJar Notes is a Python notes application that stores session data in a Base64-encoded pickle cookie — with no signature verification.
You will:
- Decode the session cookie to read its structure
- Forge an admin cookie by changing
"role":"user"→"role":"admin"to demonstrate that the server trusts manipulated cookie data (privilege escalation) - Replace the data-only cookie with a malicious pickle payload that runs
cat /flag.txtduring deserialization (RCE) - Capture the flag and submit it
No tools need to be installed — everything runs in your browser.