LOADING
PREYANSH
SHAH
WRITING
001
ARTICLE
MARCH 19, 2026 PREYANSH SHAH

The Cookie That Executed Code on Their Server

Insecure deserialization in a session cookie. I modified my cookie. Their server deserialized it. My code ran. Remote code execution from a cookie. Still feels unreal.

002

Remote code execution.

Three words that make every security team’s heart rate spike. The category of vulnerability where “impact” stops being a checklist item and becomes a very serious phone call.

I found RCE in a cookie.

Not the session ID. Not a session token. The cookie itself — when deserialized by the server — executed arbitrary code.

I ran sleep 10 on their production server to prove it. The response took 10 seconds. That was the proof.


What Is Insecure Deserialization

Applications often need to store complex objects — user preferences, session state, shopping carts — somewhere persistent. One approach: serialize the object to a byte string, store it in a cookie or database, deserialize it when you need it back.

Serialization formats encode not just data but sometimes type information — what class this object is, what methods it has. When you deserialize, the runtime reconstructs the object including its class.

The vulnerability: if an attacker can modify the serialized data before it’s deserialized, they can substitute a different class with different behavior. A class whose constructor, destructor, or magic methods execute arbitrary code when the object is created or destroyed.

In Java, Python’s pickle, PHP’s unserialize, Ruby’s Marshal — all have this problem. The deserialization process is powerful by design. That power is dangerous when the input isn’t trusted.


Finding It

The target — redacted-portal.com — was a legacy enterprise portal. Java backend, clearly old. The session cookie was not an opaque token — it was a Base64 string that decoded to recognizable Java serialization bytes: aced 0005 — the Java serialization magic bytes.

I recognized them immediately.

Whenever you see aced0005 (or its Base64 equivalent rO0AB) in a cookie, you’re looking at a Java serialized object. And Java deserialization is one of the most well-documented RCE surfaces in existence.

The tooling for this is mature: ysoserial generates gadget chain payloads for dozens of common Java libraries. If the target application has any of those libraries on the classpath — and most enterprise Java apps have all of them — you have RCE.

I generated a time-delay payload using ysoserial’s CommonsCollections6 gadget chain:

java -jar ysoserial.jar CommonsCollections6 'sleep 10' | base64

Replaced my session cookie with the output.

Sent the request.

Response time: 10.3 seconds.

The server had deserialized my payload and executed sleep 10.

Remote code execution on a production Java server via a modified cookie.


Stopping Before It Got Real

At this point, a different person might run whoami, cat /etc/passwd, id, check what permissions the Java process had.

I did not do this. I had proven RCE. sleep 10 is sufficient proof. The time delay is unambiguous. No other reasonable explanation for a 10-second delay on a command that normally takes 300ms.

I didn’t need to know what user the server ran as. I didn’t need to read any files. I didn’t need to make any further calls.

The report writes itself from sleep 10. Everything else is risk with no additional reward.


The Report and Response

Title: Insecure Java Deserialization in Session Cookie — Remote Code Execution via CommonsCollections6 Gadget Chain (Confirmed via Time-Delay Payload)

Severity: Critical — Remote Code Execution

CVSS: 10.0

Impact: The session cookie contains a Java serialized object that is deserialized server-side without integrity verification. Using ysoserial with a CommonsCollections6 gadget chain, arbitrary operating system commands can be executed in the context of the application server process. Confirmed via a sleep 10 time-delay payload producing a consistent 10.3 second response time versus baseline of 0.3 seconds.

Remediation: Never deserialize untrusted data. If serialization is required for session state, use a cryptographically signed format (HMAC-signed JSON, encrypted JWT) that cannot be modified by the client. If Java serialization is unavoidable, implement a deserialization filter (Java 9+ serialization filters) that allowlists permitted classes.

Response time: 2 hours. Triage: Critical. Fix timeline: 72 hours (required replacing the session handling mechanism entirely — not a quick patch).

Bounty: $$$$


The Lesson Nobody Wants to Hear

Don’t deserialize user-controlled data. Full stop.

This isn’t a subtle misconfiguration. This isn’t a missing header. This is a fundamental architectural decision: trusting client-supplied serialized objects as safe to deserialize.

The cookie is client-controlled. The client is the adversary. Deserializing attacker-controlled bytes and having the runtime reconstruct classes from them is one of the most dangerous things an application can do.

If you’re maintaining a Java application with cookie-based session serialization and you haven’t audited this: stop reading and go check.


Reported through the official bug bounty program. The only payload executed was sleep 10. No files were read, no commands beyond the time-delay PoC were run, no persistence was established. Domain redacted per responsible disclosure norms.

003
END
← BACK TO WRITING
The Cookie That Executed Code on Their Server READY TO PLAY