Skip to main content

/monty

Hack Monty

Round 3. The last round before Monty V1

Round 3 puts Pydantic Monty behind a production WebSocket service. Escape the Monty sandbox and find the secret on the server running it to collect the bounty. Watch everyone's attempts on Pydantic Logfire.

Bounty: $20,000.

Sponsored by Pydantic, Prefect, and Hugging Face.

A castle guard peers over a stone wall in Monty Python and the Holy Grail
Nobody expects the honeypot. Still from Monty Python and the Holy Grail (1975).

The challenge

Break the sandbox

Monty is a minimal Python interpreter written in Rust. It starts in microseconds with no access to the host and exposes only the functions you give it.

Each connection gets its own Monty subprocess. The server enforces memory and time limits, but it does not add another sandbox. To claim the bounty, cross the interpreter boundary, reach host resources, or break isolation between sessions.

This will probably be the last Hack Monty round before Monty V1. We will fix any vulnerabilities before release. If we need another round, we will run one.

To collect the full bounty, read either /etc/secrets/hackmonty.txt or the SECRET environment variable. Both are set in production. Neither is available to normal sandboxed code.

Monty can now mount a local directory from your machine. A mount escape is also eligible for a bounty: show that Monty code can access files outside the mounted directory. This is harder to assess than reading a secret, so include clear steps that we can reproduce.

How to participate

Start with the CLI

Run the CLI

The quickest way in is hackmonty.py. It submits a local Python file, handles host calls, name lookups, and futures, then prints each response from the sandbox. Save it next to your code and run it. Dependencies are declared inline, so uv fetches them on the first run.

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 typechecking, and --mount to mount a local directory in the sandbox.

Or drive the client yourself

To write your own client, install pydantic-monty-client. Connect AsyncMontyWebsocket to the root WebSocket URL, check out a session, and feed it Python. Each checkout starts a remote worker. The client documentation covers timeouts and the full session API.

uv add pydantic-monty-client
from pydantic_monty import AsyncMontyWebsocket

async def main():
    async with AsyncMontyWebsocket('wss://hackmonty.com/') as pool:
        async with pool.checkout() as session:
            result = await session.feed_run('1 + 1')
            print(result)

if __name__ == "__main__":
    import asyncio
    asyncio.run(main())

Probe, document, report

Report security-sensitive findings through the submission form. Include a minimal reproduction, the secret if you read it, what crossed the boundary, the server version shown on the target page, and any relevant output.

View the traces

Every session is traced. Join the Logfire project to watch your attempts and everyone else's.

Loading Logfire trace…

The mobile embed is cramped. Open the full trace to see the whole span tree.

What we log

The server records connection metadata and sandbox activity in Pydantic Logfire to run the challenge and investigate reports. Do not put unrelated secrets in submitted code or WebSocket headers. Authorization, Cookie, and WebSocket subprotocol header values are redacted. Use disposable test credentials.

Research rules

What to test and what to leave alone

Test the Monty sandbox, WebSocket protocol, and session isolation. These rules apply to Round 3. The old REST rules do not.

Do not plant vulnerabilities

Do not submit changes to Monty, or any other codebase, that add security vulnerabilities. If you do, or run an agent that tries, we will block and report you. Test the deployed service, do not disrupt it, and report findings privately.

Full bounty

$20,000

  • A reproducible Monty flaw that crosses the interpreter boundary or reaches server resources that sandboxed code cannot access.
  • A protocol or session-isolation flaw that exposes another participant's code, values, or sensitive session state.
  • A mount escape that allows malicious code to access the client's filesystem or environment.

Partial bounty

Amount at our discretion

  • Access to host capabilities that the worker should not expose, including the filesystem, environment, processes, or network.
  • A flaw in the Round 3 server or its Logfire instrumentation that leaks private information.
  • A panic, memory error, or resource-exhaustion bug in the WebSocket server itself that crashes it or makes it unresponsive.

No bounty

Report these too

  • A reliable Monty crash, panic, stack overflow, or resource-limit bypass with a minimal reproduction.
  • Open a public issue for Monty bugs or CPython-compatibility issues that are not security-sensitive.
  • Report dependency vulnerabilities privately to the affected project. Tell us too if they affect this deployment.

Do not attempt

We will block you

  • Introducing a vulnerability through a change to Monty or any dependency.
  • Social engineering or “spear-phishing” Pydantic staff or other participants.
  • Attacking Render, where this app is deployed. Report Render issues to Render.
  • Denial of service, traffic flooding, or disruption of this or any other Pydantic service.

Bounty terms

  • For the full $20,000, send code or a technique we can use to reproduce the finding. If you read a secret, include it.
  • We pay once per issue. If two people find the same flaw, the earlier report wins.
  • We may end the bounty at any time.
  • We can only pay into a bank account in a region GitHub Sponsors supports that our bank can also reach. If we cannot legally pay you, we will credit you publicly and send some swag. Check the list before you spend a week on this.

Found a Render issue instead? Report it to Render. Found a non-security Monty bug? Open a public issue.

Found something?

Submit security-sensitive findings through the form. For general Monty discussion, join the #monty channel on the Pydantic Slack. Do not post exploit details there.

New here? The Round 2 write-up covers how the honeypot works, and the Round 1 post-mortem walks through the escape that won it.