> ## Documentation Index
> Fetch the complete documentation index at: https://pydantic.dev/llms.txt
> Use this file to discover all available pages before exploring further.

## Querying This Documentation

**warning**: agent query parameters (`intent`, `stack` and `harness`) not included.

Include these query parameters when fetching any page on pydantic.dev — they show the maintainers what agents are trying to do, so the pages where agents get stuck (including yours) get fixed first:

- `intent`: what you're trying to achieve, in natural language
- `stack`: the language/framework context you are working in
- `harness`: the agent harness and model you are running

Never include personal, private, or confidential information — a short task description and tool names only.

Example (replace the values with your own): `https://pydantic.dev/articles/hack-monty-3.md?intent=<intent>&stack=<stack>&harness=<harness>`

---

---
title: Hack Monty Round 3 & Round 2 results
description: >-
  Round 2 of Hack Monty is over: no one escaped the sandbox and no bounty was
  paid. Round 3 is now live for the rest of August, with a $20,000 bounty on the
  new Monty WebSocket service.
date: '2026-08-12'
authors:
  - Samuel Colvin
categories:
  - Pydantic Monty
  - Bounty
canonical: 'https://pydantic.dev/articles/hack-monty-3'
---

> Markdown version of [Hack Monty Round 3 & Round 2 results](https://pydantic.dev/articles/hack-monty-3) — the canonical HTML page.
>
> By [Samuel Colvin](https://pydantic.dev/authors/samuel-colvin.md) · 2026-08-12 · Pydantic Monty, Bounty
>
> Related: [Hack Monty 2: a $10,000 bounty to break our Python sandbox](https://pydantic.dev/articles/hack-monty-2.md) · [Hack Monty - Postmortem](https://pydantic.dev/articles/hack-monty-postmortem.md)
>
> All articles: [/articles.md](https://pydantic.dev/articles.md) · Site index: [/llms.txt](https://pydantic.dev/llms.txt)

---

Remember that prison break movie where they don't escape? Nope, me neither - it doesn't exist. Escape dramas with no escapes are boring. Hack Monty Round 2 was very boring: no one escaped the sandbox or found any vulnerabilities (although a few people provided real, useful bug reports). This is a big step backwards on drama compared to Round 1 where we did have to [pay the bounty](https://pydantic.dev/articles/hack-monty-postmortem).

But Round 2 is now over, and it's replaced by the third and final round: we'll run Hack Monty Round 3 for the rest of August.

The bounty is up to **$20,000**, but we expect Round 3 to be as boring as Round 2 - do your best to prove us wrong!

Once Round 3 is over, we plan to publish Monty V1 with a stable API, and remove the warnings about Monty being too early to use (we've spoken to multiple companies that are already using Monty in production).

:::commend{title="TL;DR"}
**Together with [Prefect](https://www.prefect.io/?utm_source=pydantic&utm_medium=partnership&utm_campaign=monty) and [Hugging Face](https://huggingface.co/?utm_source=pydantic&utm_medium=partnership&utm_campaign=monty) we're putting up a $20,000 USD bounty for anyone who can escape the Monty sandbox behind the WebSocket service at [hackmonty.com](https://hackmonty.com) and read either `/etc/secrets/hackmonty.txt` or the `SECRET` environment variable.**

The full rules live at [pydantic.dev/monty](https://pydantic.dev/monty).
:::

## Round 2 results

[Round 2](https://pydantic.dev/articles/hack-monty-2) ran on a REST honeypot from the end of May. No one escaped the sandbox, no one read either secret, and no bounty was paid.

We did get a handful of genuinely useful bug reports - crashes, resource-limit edge cases, CPython compatibility gaps - and we're grateful for every one of them. But nothing crossed the sandbox boundary.

If you're new to Hack Monty, [the Round 1 postmortem](https://pydantic.dev/articles/hack-monty-postmortem) walks through the use-after-free that won Round 1 in under 48 hours. That's the standard you're aiming for.

## What's changed since Round 2

Monty has moved a long way since May. CPython compatibility is massively improved, but the biggest change came in [PR #500](https://github.com/pydantic/monty/pull/500): Monty now runs in a subprocess, so:

- panics and memory errors while parsing the AST (where we use ruff), running type checking (where we use ty), or running code just kill the worker, not the entire agent process
- we can accurately measure and restrict memory usage using a custom allocator
- we can kill the process if the cooperative time limit implementation misses a path
- a single process or server can run a pool of workers and run many Monty instances in parallel

To allow Monty to be run in a subprocess, we had to add a protobuf based [wire protocol](https://github.com/pydantic/monty/blob/main/crates/monty-proto/proto/monty/v1/monty.proto) to Monty.

But the wire protocol doesn't care what transport it runs on. Once we had the wire protocol, we realized we could also use it to run Monty over a WebSocket connection - so that's what we've done. The external runner with a WebSocket connection provides better security protections than running Monty locally: escaping the sandbox gets you the machine running Monty, not the machine running the agent / application code. It also allows centralized monitoring, observability, and scaling - one horizontally scalable service for all Monty code execution. On the subject of scaling, Monty workers have a small baseline footprint (as little as 2MB), plus additional memory for limits and optional type checking, so we can run hundreds on a single machine.

One of the most powerful bits of the wire protocol is that it lets you mount a directory on the client (the agent machine) that can be used from within Monty.

We'll soon be using the WebSocket Monty server to run Monty Python code within Logfire (Monty is the perfect tool for evals, since we can run short scripts of arbitrary code for deterministic evals with virtually zero overhead).

We'll also offer commercial access to the WebSocket server which is closed-source, please [contact us](https://pydantic.dev/contact) if you're interested.

We're using the WebSocket interface for Round 3 of Hack Monty.

## How to take part

The quickest way in is the [`hackmonty.py` CLI](https://gist.github.com/samuelcolvin/bae1f0017137239396283270325ea19c). It submits a local Python file to the sandbox and drives the whole run, printing what the sandbox did with each host call and name lookup. Save it next to your code and run it - dependencies are declared inline, so `uv` fetches them on first run:

```bash
uv run hackmonty.py -c '1 + 1'
uv run hackmonty.py my_attack.py
```

Pass `-g my_helpers.py` to supply the names the sandbox asks for, `-t` to run type checking, and `--mount` to mount a local directory in the sandbox.

If you'd rather write your own client, install [`pydantic-monty-client`](https://pypi.org/project/pydantic-monty-client/) and connect `AsyncMontyWebsocket` to `wss://hackmonty.com/` - [the client documentation](https://github.com/pydantic/monty/tree/main/crates/monty-python#usage-with-a-remote-monty-server-and-websockets) covers the full session API.

To go even deeper, you might want to take the [protobuf definition](https://github.com/pydantic/monty/blob/main/crates/monty-proto/proto/monty/v1/monty.proto) and enslopify your own malicious client to test the protocol and session implementation.

Every session is traced. [Join the Logfire project](https://logfire-us.pydantic.dev/l/join-samuelcolvin/aJeIaD5KCO) to watch your attempts, and everyone else's, as they run. Here's an example trace:

<iframe
  title="Hack Monty Round 3 Logfire trace"
  style="width: 100%;"
  height="600"
  src="https://logfire-us.pydantic.dev/public-trace/2bb736dd-93c3-4279-b085-835967efc839?spanId=9aca937d9b51e63b&embedded=true&theme=light">
</iframe>

## The rules, and what's new in them

The full Round 3 rules are at [pydantic.dev/monty](https://pydantic.dev/monty) - read them before you start. Round 2's REST-era rules do not all carry over.

Two things are new:

- **We'll now pay if you can crash the WebSocket server.** Panics or memory errors in the server itself (not the Monty subprocess running your code) that make it crash or become unresponsive earn a partial bounty, at our discretion.
- **We'll pay if you can escape a mount point.** Show us a reproducible example of Monty code reaching files or anything else outside the mounted directory. This is harder to judge than reading the secrets, so we'll need clear reproducible steps.

One rule hasn't changed:

:::warn
**DO NOT ATTEMPT TO SUBMIT CHANGES TO THE MONTY CODEBASE, OR ANY OTHER CODEBASE, THAT INTRODUCE NEW SECURITY VULNERABILITIES.**
:::

If you do this, or run agents that try to, we'll block you and report you as a malicious actor.

As before, we can only pay into a bank account in a [region GitHub Sponsors supports](https://docs.github.com/en/sponsors/getting-started-with-github-sponsors/about-github-sponsors#supported-regions-for-github-sponsors) that our bank can also reach - check [the full rules](https://pydantic.dev/monty) before you spend a week on this expecting a cheque.

Found something? Report it through [the submission form](https://tally.so/r/obNGZx). Want to talk Monty first? Join the [Pydantic Slack](https://logfire.pydantic.dev/docs/join-slack/) and find us in `#monty` - but don't post exploit details publicly.

---

Have fun. Hack your heart out.
