Dynamic pentesting lab platform with AI-assisted learning.
Deploy isolated, dockerized lab environments on demand. Practice pentesting, solve CTF challenges, simulate bug bounties — all with an integrated AI coach that guides without giving away the answers.
- Dynamic Zones — Spin up isolated lab environments from templates. Each zone gets its own Docker network, resource limits, and TTL enforcement.
- Template System — Import labs from ZIP files containing
lab.ymlconfiguration. Share templates with the community. - AI Assistant — Multi-provider AI coaching (OpenAI, Anthropic, Ollama) with hint, explain, and debrief modes. Flag-leak prevention built in.
- Terminal in Browser — Full interactive terminal via xterm.js + WebSocket, connected directly to lab containers.
- Objectives & Scoring — Flag submission, progressive hints, leaderboards, and multiple scoring methods (sum, weighted, time-decay).
- Multi-Mode Labs — Pentest, CTF, Bug Bounty, and custom lab types on one platform.
- Team Support — Organizations with role-based access (owner, admin, member).
- Admin Panel — Template approval, zone management, AI usage monitoring, audit logging.
- Setup Wizard — First-run wizard handles database migration, admin account creation, and platform configuration.
┌─────────────────────────────────────────────────────────┐
│ Frontend (Next.js) │
│ Dashboard │ Zone Detail │ Terminal │ AI Chat │ Admin │
├─────────────────────────────────────────────────────────┤
│ API Gateway (Traefik) │
│ Rate Limiting │ Security Headers │ Routing │
├─────────────────────────────────────────────────────────┤
│ Control Plane (Go) │
│ Auth │ Templates │ Zone Lifecycle │ Scoring │ AI │
├─────────────────────────────────────────────────────────┤
│ Runtime Plane │
│ ComposeDriver (Docker) │ K8sDriver (Kubernetes) │
├─────────────────────────────────────────────────────────┤
│ AI Plane (LiteLLM) │
│ OpenAI │ Anthropic │ Ollama │ Fallback Chains │
├─────────────────────────────────────────────────────────┤
│ Data Layer │
│ PostgreSQL │ Redis │ Object Storage │
└─────────────────────────────────────────────────────────┘
- Docker Engine 24.0+
- Docker Compose v2
- At least one AI provider API key (OpenAI recommended)
git clone https://github.com/tegal1337/pentest-labs.git
cd pentest-labs
cp .env.example .envEdit .env with your API keys:
JWT_SECRET=your-secure-random-string-here
OPENAI_API_KEY=sk-...docker compose up -dThis starts: PostgreSQL, Redis, Traefik, LiteLLM, API backend, Worker, and Frontend.
Open http://localhost in your browser. The setup wizard will:
- Verify all services are healthy
- Create your admin account
- Configure platform settings
Templates are in the templates/ directory. Import via the web UI or API:
cd templates/01-juice-shop
zip -r juice-shop.zip lab.yml
curl -X POST http://localhost/api/v1/templates/import \
-H "Authorization: Bearer <token>" \
-F "file=@juice-shop.zip"Public labs are reachable through Traefik on ports 80 (and 443 if TLS is configured), not through random Docker-published host ports. Each running zone gets a hostname ingress_domain (default pattern: {first-8-of-zone-uuid}.labs.local).
URL format: http://<ingress_domain>/
DNS / hosts
- Same machine as Docker Desktop / Linux daemon: Often
127.0.0.1 <ingress_domain>in your hosts file is enough because Traefik publishes80:80. - Another device on your LAN: Use the LAN IP of the Docker host instead of loopback (e.g.
192.168.1.10 <ingress_domain>on the laptop you browse from). - Wildcard DNS (optional): Point
*.labs.localat the Traefik host with an internal resolver (e.g. dnsmasq) so you don’t add a hosts line per zone.
The zone detail screen in the app shows Open lab and the raw hostname as a reminder. If the hostname does not resolve, the browser cannot reach Traefik with the correct Host header and routing to that zone will fail.
| Component | Technology | Purpose |
|---|---|---|
| Backend | Go 1.25 | API server, zone orchestration |
| Frontend | Next.js 16 + TypeScript | Dashboard, terminal, AI chat |
| Database | PostgreSQL 16 | Persistent data |
| Cache | Redis 7 | Events, job queue, sessions |
| AI Gateway | LiteLLM | Multi-provider routing, rate limits |
| Reverse Proxy | Traefik v3 | Rate limiting, routing, TLS |
| Runtime | Docker Compose | Zone container orchestration |
| Terminal | xterm.js + WebSocket | Browser-based shell |
pentest-labs/
├── backend/ # Go API server
│ ├── cmd/api/ # API entrypoint
│ ├── cmd/worker/ # Background worker
│ ├── internal/
│ │ ├── ai/ # LiteLLM gateway client
│ │ ├── config/ # Environment configuration
│ │ ├── events/ # Redis pub/sub event broker
│ │ ├── handler/ # HTTP handlers
│ │ ├── middleware/ # Auth, logging middleware
│ │ ├── migrate/ # Embedded SQL migrations
│ │ ├── model/ # Domain models
│ │ ├── recording/ # Lab session recording
│ │ ├── repository/ # Database access layer
│ │ ├── runtime/ # Container runtime drivers
│ │ │ ├── compose/ # Docker Compose driver
│ │ │ └── kubernetes/ # Kubernetes driver
│ │ ├── scheduler/ # Multi-worker job scheduler
│ │ ├── scoring/ # Scoring plugin system
│ │ ├── server/ # HTTP server + routes
│ │ ├── service/ # Business logic
│ │ ├── team/ # Team/org management
│ │ ├── terminal/ # WebSocket terminal handler
│ │ ├── vpn/ # WireGuard VPN manager
│ │ └── worker/ # TTL enforcement
│ ├── pkg/validator/ # Lab config validation
│ ├── migrations/ # SQL migration files
│ ├── Dockerfile
│ └── Makefile
├── frontend/ # Next.js application
│ ├── src/
│ │ ├── app/ # Pages (App Router)
│ │ ├── components/ # React components
│ │ ├── hooks/ # Custom hooks
│ │ ├── lib/ # API client, utilities
│ │ ├── stores/ # Zustand state stores
│ │ └── types/ # TypeScript interfaces
│ └── Dockerfile
├── litellm/ # LiteLLM proxy configuration
│ └── config.yaml
├── traefik/ # Traefik gateway configuration
│ ├── traefik.yml
│ └── dynamic/
├── templates/ # Lab template library
│ ├── 01-juice-shop/
│ ├── 02-dvwa/
│ └── ...
├── docs/
│ └── PRD.md # Product Requirements Document
├── docker-compose.yml
└── .env.example
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/v1/auth/register |
Register new user |
| POST | /api/v1/auth/login |
Login, returns JWT tokens |
| POST | /api/v1/auth/refresh |
Refresh access token |
| POST | /api/v1/auth/logout |
Invalidate session |
| GET | /api/v1/auth/me |
Get current user |
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/v1/templates/import |
Upload ZIP template |
| GET | /api/v1/templates |
List templates |
| GET | /api/v1/templates/:id |
Get template details |
| POST | /api/v1/templates/:id/validate |
Dry-run validation |
| POST | /api/v1/templates/:id/publish |
Make public |
| GET | /api/v1/templates/:id/versions |
Version history |
| DELETE | /api/v1/templates/:id |
Delete template |
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/v1/zones |
Create zone from template |
| GET | /api/v1/zones |
List user's zones |
| GET | /api/v1/zones/:id |
Get zone details |
| POST | /api/v1/zones/:id/start |
Start zone |
| POST | /api/v1/zones/:id/stop |
Stop zone |
| POST | /api/v1/zones/:id/reset |
Reset to initial state |
| DELETE | /api/v1/zones/:id |
Destroy zone |
| GET | /api/v1/zones/:id/status |
Runtime status |
| GET | /api/v1/zones/:id/services |
Service list + health |
| GET | /api/v1/zones/:id/events |
SSE event stream |
| GET | /api/v1/zones/:id/terminal |
WebSocket terminal |
| GET | /api/v1/zones/:id/objectives |
Objectives + progress |
| POST | /api/v1/zones/:id/flags/submit |
Submit flag |
| GET | /api/v1/zones/:id/score |
Current score |
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/v1/zones/:id/ai/chat |
General chat |
| POST | /api/v1/zones/:id/ai/hint |
Get contextual hint |
| POST | /api/v1/zones/:id/ai/explain |
Explain vulnerability |
| POST | /api/v1/zones/:id/ai/debrief |
Session debrief |
| GET | /api/v1/ai/providers |
List AI providers |
| GET | /api/v1/ai/models |
List available models |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/leaderboards/global |
Global leaderboard |
| GET | /api/v1/leaderboards/:templateId |
Per-lab leaderboard |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/admin/stats |
Platform statistics |
| GET | /api/v1/admin/zones |
All zones (all users) |
| GET | /api/v1/admin/workers |
Worker status |
| GET | /api/v1/admin/ai/usage |
AI usage stats |
| GET | /api/v1/admin/audit |
Audit log |
| POST | /api/v1/admin/templates/:id/approve |
Approve template |
Templates are ZIP files containing a lab.yml configuration:
version: 1
metadata:
name: "My Lab"
type: "pentest" # pentest | ctf | bug-bounty | custom
difficulty: "medium" # easy | medium | hard | insane
tags: ["web", "sqli"]
services:
- name: "app"
image: "vulnerable/app:latest"
ports:
- container_port: 8080
objectives:
mode: "flags"
flags:
- id: "flag-1"
title: "Find the vulnerability"
value: "HLAB{my_flag_here}"
points: 100
ai:
enabled: true
profile: "coach-basic"See docs/PRD.md section 3.2 for the complete schema reference.
| # | Name | Type | Difficulty | Vulnerabilities |
|---|---|---|---|---|
| 1 | OWASP Juice Shop | Pentest | Easy | OWASP Top 10 |
| 2 | DVWA | Pentest | Easy | SQLi, XSS, Command Injection |
| 3 | WebGoat | Pentest | Medium | JWT, XXE, Deserialization |
| 4 | crAPI | Pentest | Medium | OWASP API Top 10 |
| 5 | DVGA | Pentest | Medium | GraphQL Security |
| 6 | SQL Injection CTF | CTF | Medium | UNION, Blind, Time-based |
| 7 | XSS Challenge | CTF | Easy | Reflected, Stored, DOM |
| 8 | Broken Auth | Pentest | Medium | JWT, Session Fixation |
| 9 | SSRF Lab | Pentest | Hard | SSRF, Filter Bypass |
| 10 | Linux Privesc | Pentest | Hard | SUID, Sudo, Cron |
cd backend
cp .env.example .env
# Edit .env with your values
make run # Run API server
make run-worker # Run background worker
make test # Run tests
make lint # Run linter
make build # Build binariescd frontend
npm install
npm run dev # Development server on :3000
npm run build # Production buildMigrations run automatically on API startup. To run manually:
make migrate-up
make migrate-downMinimum requirements: 4 CPU cores, 8 GB RAM, 100 GB SSD
# Clone and configure
git clone https://github.com/tegal1337/pentest-labs.git
cd pentest-labs
cp .env.example .env
# Edit .env
# Start everything
docker compose up -d
# Check health
curl http://localhost/health- Single VPS → All services on one machine
- Multi-Worker → Add worker nodes, scheduler distributes zones
- Kubernetes → Swap ComposeDriver for K8sDriver (same API, same templates)
- Zone Isolation — Each zone runs in its own Docker network with no inter-zone communication
- Container Hardening — No privileged containers, all capabilities dropped, seccomp profiles
- Resource Limits — CPU, memory, PID, and disk limits per container
- Egress Control — Internet access denied by default
- AI Safety — Flag-leak prevention, output filtering, rate limiting
- API Security — JWT auth, rate limiting via Traefik, input validation
See SECURITY.md for vulnerability reporting.
This project is licensed under the MIT License. See LICENSE for details.
We welcome contributions! See CONTRIBUTING.md for guidelines.