DOCUMENTATION

Everything you need to
spin up Breachforge.

A practical reference for running the platform locally: prerequisites, quickstart, port configuration, architecture, challenge and lab mechanics, and flag format. Keep this open in a second tab while you build.

Quickstart

Getting started

Breachforge runs entirely in Docker. One command brings the full stack online: nginx reverse proxy, three language runtimes (PHP 8 + Apache, Python 3 + Flask, Node.js 20 + Express), MySQL, MongoDB, and every challenge + lab container. Nothing installs on your host beyond Docker itself.

Authorization reminder

Breachforge is a training target. The techniques you learn here are only legal to use against systems you own or have written permission to test. The platform ships with its own deliberately vulnerable services — do not point exploit tooling at anything else.

Prerequisites

  • Docker 24 or newer (with the Compose plugin; docker compose version should work).
  • ~4 GB free RAM. The hub itself is light, but labs spin up multiple microservices per stack.
  • ~3 GB free disk for pulled base images and MongoDB/MySQL volumes.
  • A modern browser. Labs use crypto.subtle for flag hashing — Chrome, Firefox, Safari, and Edge all work.

Install & run

Clone the repo, then bring the stack up with a single command. The first run pulls base images and seeds MySQL/MongoDB, which takes a minute or two.

# clone
git clone https://github.com/your-org/breachforge.git
cd breachforge

# build + run everything
docker compose up -d --build

# follow logs
docker compose logs -f

Once it settles, open http://localhost:8080 in your browser. You should see the Breachforge hub. Click through to Challenges to launch single-vulnerability targets, or Labs for multi-stage attack chains.

Port configuration

The hub binds to 8080 by default. If you already have something on that port, override it with the BREACHFORGE_PORT environment variable before running compose:

# one-shot override
BREACHFORGE_PORT=9090 docker compose up -d

# or persist it in .env
echo "BREACHFORGE_PORT=9090" >> .env
docker compose up -d

Internal service ports (MySQL 3306, Mongo 27017, individual challenge containers) are not exposed to the host. Everything is routed through the nginx proxy at BREACHFORGE_PORT.

Architecture

Breachforge is a single docker-compose.yml that orchestrates four layers:

  • Frontend. Static HTML/CSS/JS served by nginx. No build step. Handles routing, challenge launch UI, flag submission, and the labs dashboard.
  • Nginx reverse proxy. The only host-exposed container. Routes / to the frontend, /api/* to backend services, and /chain/NN/* to lab services.
  • Backend services. One PHP+Apache, one Python+Flask, and one Node+Express container host the single-vulnerability challenges. Each is a thin wrapper around the vulnerable code samples.
  • Lab services. Multi-container labs (Nimbus, MarketOne, Corely, MicroHub) run as independent compositions under /chain/NN/ with their own databases, admin bots, and internal metadata endpoints.

Both databases (MySQL, MongoDB) are shared between challenges for efficiency. Labs that need clean state spin up their own DB instances.

Challenges

The Challenges page lists 30 single-vulnerability targets. Each one isolates a single technique — SQLi, SSRF, XXE, prototype pollution, deserialization, etc. — so you can focus on the exploitation primitive without solving a whole puzzle to reach it.

Click a challenge card to open the detail panel, pick a difficulty (Low / Medium / High — same bug, different hardening), and hit Launch. The target opens in a new tab served through the proxy. Exploit it, pull the BF{…} string out, and come back to submit.

Attack labs

Labs chain multiple bugs into a realistic kill path. Lab 04 (MicroHub), for example, asks you to chain NoSQLi → SSRF → zip-slip → IDOR to pull a treasury user's premium invoice. No lab is solvable with one bug.

Each lab card on the Labs page has a flag-submission input at the bottom. Paste the BF{…} string you recover at the end of the chain and hit submit. The page hashes your input with SHA-256 in your browser and compares against the expected hash baked into the page — so the flag is never visible in HTML source. Successful submissions are stored in localStorage under the key breachforge.captured.labs.

Reset progress

To clear your captured labs, open devtools on the Labs page and run localStorage.removeItem('breachforge.captured.labs'). Refresh — all labs reset to uncaptured.

Stacks reference

Ten challenges per stack. Pick the one you want to train against:

PHP 8 · Apache Classic web bugs

Include/LFI, SQL injection, unrestricted upload, session fixation, deserialization, XXE — the canonical LAMP attack surface.

Python 3 · Flask Template & framework flaws

SSTI, SSRF via requests, pickle deserialization, JWT misuse, directory traversal, weak crypto.

Node 20 · Express JS ecosystem pitfalls

Prototype pollution, NoSQL injection, eval sinks, JWT alg=none, open redirect, race conditions.

Flag format

All flags follow the shape BF{…} — a 12-character HMAC-derived hex string. For example, BF{a1b2c3d4e5f6}. When you exploit a challenge or lab, the full flag is printed to the response body, written to a /flag.txt file, or returned in an API field — location depends on the bug. Flags are cryptographically generated at container startup from a secret, so they can't be guessed.

Submission is exact match. Copy the full string including the braces. No trailing whitespace. No partial credit.

Troubleshooting

port in use
Another process is bound to 8080. Set BREACHFORGE_PORT=9090 (or any free port) and docker compose up -d again.
502 from nginx
A backend container is still warming up. Wait ~30 s after a fresh compose up, then retry. If it persists, check docker compose logs php python node.
lab flag rejected
Flag is exact-match. Make sure you copied from BF{ through the closing } with no extra whitespace. The hash check is client-side — no server round-trip needed.
MySQL won't start
Volume conflict from a previous run. Stop everything (docker compose down -v) to wipe volumes and rebuild. Note: this also clears your lab captures if they're stored server-side, but the default flag submission is localStorage only.