Open-source cybersecurity labs that run in Docker. Exploit a real service, find the flag, verify the solve. No accounts, no scoring server. A duckurity project.
Quick start · Labs · Wiki · Contribute
Press play to hear the welcome.
Your browser does not support the audio element.Three things stand between you and your first flag.
git clone https://github.com/Duckurity/openlabs
cd openlabs/labs/web/duck-cross
docker compose up -dOpen http://localhost:8377, work the brief until the flag turns up, then
check the solve:
python3 scripts/check.py labs/web/duck-crossThe checker hashes your input with SHA-256 and compares it against
flag_hash in lab.yml. It prints solved or not solved.1
Tip
After images are pulled, nothing leaves your machine. Labs are self-contained and fully offline.
Every lab is a self-contained exercise: one vulnerable service, one brief, one flag inside. You solve at your own pace, and honesty is built in. The repository stores only the SHA-256 hash of each flag, never the plaintext.
| Self-contained | Runs offline once images are pulled. No phone-home. |
| Reproducible | Pinned base images, one documented host port. |
| Honest | Plaintext flags stay inside lab internals; only the hash ships. |
| Graded | A four-step difficulty ladder from easy to insane. |
| Track | Examples |
|---|---|
web |
injection, broken access control, auth bypass, SSRF |
binary |
memory corruption, exploitation, reverse engineering |
crypto |
weak primitives, protocol misuse, implementation faults |
network |
protocol abuse, traffic analysis, pivoting |
osint |
recon, source analysis, signature tracing |
easy → medium → hard → insane. Grades describe what a player does,
not how long it takes.
| Level | Expectation |
|---|---|
| one vector, minimal recon | |
| chained steps, some enumeration | |
| multiple systems, custom tooling | |
| research-level, an original technique |
| Lab | Track | Difficulty | Description |
|---|---|---|---|
duck-cross |
web |
a reports portal with a missing object-level authorization check |
duck{...}. Lowercase letters, digits, and underscores between the braces, 16 to 40 characters.2
The plaintext flag lives inside the lab; the repository stores only its SHA-256 hash. Reading lab source to find the flag is a legitimate solve. Open labs work that way.
labs/<track>/<lab>/
├── lab.yml # name, track, difficulty, description, flag_hash
├── README.md # player brief: story, setup, goal
├── docker-compose.yml # service definition
├── Dockerfile # pinned base image
└── app/ # lab internals; the flag lives here
labs/_template/ carries the skeleton. Copy it, fill it in, and open a
pull request. CI validates structure, metadata, and flag hygiene on every
change.
A writeup is your own explanation of a solve. Publish them anywhere. Link the lab so other people can follow the path you took.
Labs are welcome. Read CONTRIBUTING.md before you open a pull request. For behavior standards, see CODE_OF_CONDUCT.md. The full player and authoring guides live on the project wiki.
How a lab ships
flowchart LR
idea["Lab idea<br>issue form"] --> author["Copy<br>labs/_template"]
author --> pr["Pull request"]
pr --> ci{"CI validates"}
ci -->|"fix"| author
ci -->|"pass"| review["Review"]
review --> ship["Merged into<br>labs/"]
Code, configuration, and scripts fall under Apache-2.0. Lab briefs, docs, and prose fall under CC-BY-4.0. One repository, two licenses.
The vulnerabilities inside labs are the product; they need no report. Weaknesses in lab infrastructure, repo tooling, or CI go through GitHub Private Vulnerability Reporting. Details in SECURITY.md.
