Setup Environment to Practice PyFu Examples
PyFu has a simple and practical lab environment for practicing Python exploitation techniques. All examples demonstrated throughout PyFu were tested on Ubuntu 24.04 with Python 3.12 to ensure consistency across the learning material.
In the official PyFu GitHub repository, the lab lives under the PyFuLabs/ directory, where every example is organized in a consistent structure alongside a ready-to-use docker-compose.yml file that spins up the full environment. Two files document the lab: PyFuLabs/README.md (how to run it) and PyFuLabs/LAB_PLAN.md (a coverage matrix mapping every handbook page to its runnable artifact).
This setup leverages Traefik as a reverse proxy to route traffic to the appropriate vulnerable containers.
Before running the labs, you’ll need to configure your system’s /etc/hosts file to resolve the pyfu.local domain to your local machine.
This can be done by adding the following entry to /etc/hosts:
127.0.0.1 pyfu.local
With this setup in place, you can clone the PyFu repository and bring up the full lab using the following commands:
git clone https://github.com/mhaskar/PyFu
cd PyFu/PyFuLabs
docker compose up -d --build
You can also build and run a single example by naming its service, for instance:
docker compose up -d --build flask-ssti
Lab Components
Traefik :
Acts as the central entry point for all HTTP traffic. Routes incoming requests based on the request path and forwards them to the appropriate Docker containers. Provides a built-in dashboard (http://pyfu.local:9999) for monitoring routes and services.
Flask-Fu Services:
Contains Flask applications exposed under a route prefix /flask-fu/<app-name>.
Example
http://pyfu.local/flask-fu/hello-world
FastAPI-Fu Services:
Contains FastAPI applications exposed under a route prefix
/fastapi-fu/<app-name>.
Example
http://pyfu.local/fastapi-fu/hello-world
Streamlit Services
Contains Streamlit applications exposed under a route prefix
/streamlit-fu/<app-name>.
Example
http://pyfu.local/streamlit-fu/hello-world
Streamlit apps keep their path prefix (Traefik does not strip it) because each app sets
--server.baseUrlPathso its WebSocket and static assets resolve correctly behind the proxy.
Generic-Py-Fu Scripts:
Not every example is a web application. Pure language-behaviour demonstrations (pickle, shelve, and YAML deserialization, eval/exec, object-graph and sandbox-escape chains, import-system abuse, command-execution sinks, path traversal, introspection, bytecode, JWT basics) live under generic-py-fu/ as standalone scripts.
Because several of these intentionally execute commands, write .pth files, or perform pickle RCE, the recommended way to run them is the isolated sandbox container (a single image on a pinned CPython, with no network and the third-party deps preinstalled). It uses the tools profile, so it is not started by docker compose up; invoke a script on demand:
docker compose run --rm generic-py-fu python3 object-model/subclasses-walk.py
They also still run directly on the host if you prefer (python3 generic-py-fu/<path>.py). See generic-py-fu/README.md for the full index.
Universal App Structure
Every containerized example follows the same layout, which is what makes services interchangeable and lets Traefik route them automatically:
<tier>-fu/<app-name>/
├── app.py # the application (intentionally vulnerable for attack labs)
├── Dockerfile # python:3.12-slim base
├── requirements.txt # pip dependencies
├── README.md # the vault page it maps to + exploit steps
└── templates/ # only when the app renders HTML
Flask apps listen on internal port 5000, FastAPI on 8000, and Streamlit on 8501; Traefik maps all of them under http://pyfu.local. Each app’s README.md records the exact handbook page it implements and ready-to-paste exploitation commands.
Modify a Code Example
This lab design provides complete isolation for every vulnerable service, allowing you to easily modify, test, and redeploy any application without having to worry about:
-
Port conflicts between services.
-
Traefik routing configurations.
-
Network-level access and exposure.
Each vulnerable app is fully encapsulated in its own folder, with its own Dockerfile and isolated container. This design allows for extremely fast iteration cycles when working on exploitation examples, writing new code, or modifying existing vulnerability scenarios.
To modify any of the services “examples”, you simply navigate to the corresponding service directory for example the flask-fu/flask-path-traversal/ folder, make the necessary changes to the source code in app.py file, and then rebuild the container for that specific service.
Once the modifications are complete, you can rebuild and redeploy just that container using:
docker compose up -d --build flask-path-traversal
This rebuilds the image and restarts the container so your changes take effect immediately, without touching any other service.