Each application runs as 4 load-balanced Docker containers behind nginx upstream pools, accessible through the nginx reverse proxy on the VM. Sticky sessions ensure stateful applications (Juice Shop, DVWA, VAmPI, CSD Demo) route consistently. All applications are intentionally vulnerable and designed for security testing.
Replace <ORIGIN> with http://<PUBLIC_IP> in all examples below. After deploying via Terraform, get the IP with terraform output -raw public_ip.
Path Application HTTP Method Expected Response /Landing page GET 200 HTML with links to all apps /healthHealth check GET 200 JSON {"status":"healthy","component":"origin-server",...} /juice-shop/Juice Shop GET 200 HTML (Angular SPA, ~75 KB) /juice-shop/rest/products/search?q=Juice Shop API GET 200 JSON {"status":"success","data":[...]} (36 products) /dvwa/DVWA GET 302 redirect to /dvwa/login.php /dvwa/login.phpDVWA login GET 200 HTML login form /dvwa/setup.phpDVWA setup GET 200 HTML (first-run database init) /vampi/VAmPI GET 200 HTML (API docs) /vampi/users/v1VAmPI API GET 200 JSON {"users":[...]} /vampi/users/v1/registerVAmPI API POST 200 JSON {"status":"success",...} /vampi/users/v1/loginVAmPI API POST 200 JSON {"auth_token":"...","status":"success"} /httpbin/gethttpbin GET 200 JSON with request details /httpbin/posthttpbin POST 200 JSON with posted data /httpbin/headershttpbin GET 200 JSON {"headers":{...}} /httpbin/status/:codehttpbin GET Returns the specified HTTP status code /whoami/whoami GET 200 plain text with hostname, IP, all headers /csd-demo/CSD Demo GET 200 HTML checkout form with attack panel /csd-demo/dashboardCSD attacker view GET 200 HTML showing exfiltrated data /csd-demo/healthCSD health GET 200 JSON {"status":"healthy","component":"csd-demo",...} /csd-demo/exfil/logCSD exfil log GET 200 JSON array of captured data /dvga/DVGA GraphiQL GET 200 HTML (GraphiQL IDE) /dvga/graphqlDVGA GraphQL API POST 200 JSON GraphQL response /restaurant/RESTaurant GET 200 (redirects to docs) /restaurant/docsRESTaurant Swagger GET 200 HTML (FastAPI Swagger UI) /restaurant/openapi.jsonRESTaurant OpenAPI GET 200 JSON OpenAPI spec http://<PUBLIC_IP>:8888crAPI GET 200 HTML (SPA) http://<PUBLIC_IP>:8888/identity/api/auth/signupcrAPI signup POST 200 JSON http://<PUBLIC_IP>:8888/identity/api/auth/logincrAPI login POST 200 JSON {"token":"..."}
Path /juice-shop/Image bkimminich/juice-shop:latestInstances 4 (ports 3001-3004), sticky via hash $cookie_token, proxy cache (60 s TTL) Resources 2 CPU / 1 GiB RAM per instance Framework Node.js / Angular Project owasp.org/www-project-juice-shop
OWASP Juice Shop is the most modern and actively maintained vulnerable web application. It covers the entire OWASP Top 10 with 100+ challenges in a realistic e-commerce application.
Scenario Category Attack Vector SQL Injection login bypass WAF ' OR 1=1-- in the login email fieldReflected XSS WAF, CSD Script injection via search parameter DOM-based XSS CSD Payload in URL fragment Broken authentication WAF Brute force login, JWT manipulation API abuse API Security Unauthorized access to /api/ endpoints Sensitive data exposure API Security Accessing user data without authorization CSRF WAF Cross-site request forgery on profile changes
curl -s " http://<PUBLIC_IP>/juice-shop/ " -o /dev/null -w " %{http_code} "
Path /dvwa/Image Custom dvwa-fpm:latest (php-fpm + nginx, built from ghcr.io/digininja/dvwa:latest) Instances 4 (ports 8101-8104), sticky via hash $cookie_PHPSESSID Resources 0.5 CPU / 256 MiB RAM per instance Database Shared MariaDB 10.11 (dvwa-db container, 1 CPU / 768 MiB) Framework PHP 8 / php-fpm / MariaDB Credentials admin / password
DVWA is the industry standard for WAF testing. It has adjustable security levels (Low, Medium, High, Impossible) that progressively add input validation and output encoding.
Scenario Category Security Level SQL Injection WAF Low: trivial ' OR 1=1#, High: blind SQLi Command Injection WAF Low: ; ls, High: filtered characters File Inclusion WAF Low: direct path traversal, High: sanitized XSS (Reflected) WAF, CSD Low: basic <script>, High: encoded bypass XSS (Stored) WAF, CSD Low: persistent script in guestbook File Upload WAF Low: PHP shell upload, High: extension filtering Brute Force Bot Defense Automated login attempts
Set the security level at /dvwa/security.php after logging in:
Low — No input validation. Every attack works. Good for WAF signature demonstrations.
Medium — Basic filtering. Some attacks require encoding or bypass techniques.
High — Strong filtering. Only advanced techniques succeed. Good for showing WAF limitations.
Impossible — Fully secure implementation. Demonstrates proper defensive coding.
DVWA requires a one-time database setup after first deployment:
Navigate to http://<PUBLIC_IP>/dvwa/setup.php
Click Create / Reset Database
Log in with admin / password
Path /vampi/Image erev0s/vampi:latest with gunicorn entrypoint (4 workers)Instances 4 (ports 5101-5104), sticky via ip_hash (SQLite per instance) Resources 0.5 CPU / 512 MiB RAM per instance Framework Python / Flask / gunicorn Project github.com/erev0s/VAmPI
VAmPI is purpose-built for testing the OWASP API Security Top 10. It provides a realistic REST API with deliberate vulnerabilities. Each instance runs gunicorn with 4 workers and its own SQLite database. The ip_hash sticky session ensures registration and login from the same client IP always hit the same instance.
Scenario OWASP API Top 10 Method Broken Object Level Authorization (BOLA) API1 Access other users’ data by manipulating IDs Broken Authentication API2 Weak token handling, no rate limiting Excessive Data Exposure API3 API returns more data than the client needs Mass Assignment API6 Modify admin fields via unexpected parameters SQL Injection API8 Injection through API parameters Improper Assets Management API9 Undocumented API endpoints
curl -X POST " http://<PUBLIC_IP>/vampi/users/v1/register " \
-H " Content-Type: application/json " \
-d ' {"username":"test","password":"test123","email":"test@test.com"} '
curl -X POST " http://<PUBLIC_IP>/vampi/users/v1/login " \
-H " Content-Type: application/json " \
-d ' {"username":"test","password":"test123"} '
# List users (excessive data exposure)
curl " http://<PUBLIC_IP>/vampi/users/v1 "
Path /httpbin/Image kennethreitz/httpbin:latest with gunicorn CMD override (-w 4 -k gevent --timeout 30)Instances 4 (ports 8201-8204), round-robin (stateless) Resources 0.5 CPU / 256 MiB RAM per instance Framework Python / Flask / gunicorn + gevent Project httpbin.org
httpbin is a simple HTTP request/response service useful for basic API demos, testing request headers, and verifying proxy behavior.
Endpoint Purpose /httpbin/getReturns GET request data (headers, args, origin) /httpbin/postReturns POST request data (body, form, JSON) /httpbin/headersReturns request headers /httpbin/ipReturns origin IP /httpbin/user-agentReturns User-Agent header /httpbin/status/:codeReturns specified HTTP status code /httpbin/delay/:secondsDelays response by N seconds /httpbin/anythingReturns anything passed in request
# Check what headers the origin sees (useful for verifying F5 XC header injection)
curl -s " http://<PUBLIC_IP>/httpbin/headers " | jq .
# Test a specific HTTP status code
curl -s -o /dev/null -w " %{http_code} " " http://<PUBLIC_IP>/httpbin/status/403 "
Path /whoami/Image traefik/whoami:latestInstances 4 (ports 8082-8085), round-robin (stateless) Resources 0.25 CPU / 64 MiB RAM per instance Framework Go Project github.com/traefik/whoami
whoami is Traefik’s lightweight request echo server. It displays every detail of the incoming HTTP request as the origin sees it — hostname, IP addresses, all headers, method, and URL. This is the single most important diagnostic tool when verifying that F5 XC is injecting the correct headers.
Use Case What to Look For Verify F5 XC header injection X-Forwarded-For, True-Client-IP, X-Volterra-* headersConfirm client IP visibility X-Real-IP vs RemoteAddrDebug WAF false positives Compare request headers before/after F5 XC Validate bot defense tagging X-Volterra-Bot-Type, X-Volterra-Bot-Verified headersCheck TLS termination X-Forwarded-Proto shows https when TLS terminates at F5 XC
# Basic request -- see what the origin receives
curl " http://<PUBLIC_IP>/whoami/ "
# Simulate request through F5 XC (with injected headers)
curl " http://<PUBLIC_IP>/whoami/ " \
-H " X-Forwarded-For: 203.0.113.50 " \
-H " True-Client-IP: 203.0.113.50 " \
-H " X-Forwarded-Proto: https "
Example output:
RemoteAddr: 172.17.0.1:55118
True-Client-Ip: 203.0.113.50
X-Forwarded-For: 203.0.113.50, 10.0.0.1
X-Real-Ip: 104.219.105.84
DVGA is purpose-built for testing GraphQL-specific vulnerabilities. It provides a GraphiQL IDE at /dvga/ for interactive query exploration and a GraphQL API endpoint at /dvga/graphql. Each instance uses its own SQLite database, so ip_hash sticky sessions ensure consistent state.
Scenario Category Attack Vector GraphQL Injection API Security Malicious queries via string interpolation Denial of Service API Security Deeply nested queries, batch queries, resource exhaustion Authorization Bypass API Security Accessing unauthorized data through GraphQL Information Disclosure API Security Introspection queries revealing schema details Batching Attack API Security Multiple operations in a single request
# GraphiQL UI (interactive IDE)
curl -sf " http://<PUBLIC_IP>/dvga/ " -o /dev/null -w " %{http_code} "
# Introspection query -- enumerate the full schema
curl -s " http://<PUBLIC_IP>/dvga/graphql " \
-H " Content-Type: application/json " \
-d ' {"query":"{ __schema { types { name fields { name } } } }"} '
# List pastes (example query)
curl -s " http://<PUBLIC_IP>/dvga/graphql " \
-H " Content-Type: application/json " \
-d ' {"query":"{ pastes { title content } }"} '
# Create a paste (mutation)
curl -s " http://<PUBLIC_IP>/dvga/graphql " \
-H " Content-Type: application/json " \
-d ' {"query":"mutation { createPaste(title:\"test\", content:\"hello\", public:true) { paste { title } } }"} '
Path /restaurant/Image Custom build from theowni/Damn-Vulnerable-RESTaurant-API-Game Instances 4 (ports 8301-8304), round-robin (shared PostgreSQL) Resources 0.5 CPU / 256 MiB RAM per instance Database Shared PostgreSQL 15.4 (restaurant-db container, 0.5 CPU / 512 MiB) Framework Python / FastAPI / PostgreSQL Credentials admin / password (PostgreSQL)Project github.com/theowni/Damn-Vulnerable-RESTaurant-API-Game
RESTaurant is a gamified vulnerable REST API covering the OWASP API Security Top 10 2023. It uses FastAPI with automatic Swagger UI documentation at /restaurant/docs. All 4 instances share a single PostgreSQL database, so round-robin load balancing works without sticky sessions.
Scenario OWASP API Top 10 2023 Method Broken Object Level Authorization (BOLA) API1 Access other users’ orders by manipulating IDs Broken Authentication API2 Weak token handling, credential stuffing Broken Object Property Level Authorization API3 Mass assignment on user profile fields Unrestricted Resource Consumption API4 No rate limiting on endpoints Broken Function Level Authorization (BFLA) API5 Access admin endpoints as regular user Server Side Request Forgery (SSRF) API7 Manipulate server-side URL requests Security Misconfiguration API8 Verbose error messages, default credentials
curl -sf " http://<PUBLIC_IP>/restaurant/docs " -o /dev/null -w " %{http_code} "
curl -s " http://<PUBLIC_IP>/restaurant/openapi.json " | jq .info
# BOLA -- access another user's order (after authentication)
curl -s " http://<PUBLIC_IP>/restaurant/orders/1 " \
-H " Authorization: Bearer <token> "
# BFLA -- attempt admin action as regular user
curl -s -X POST " http://<PUBLIC_IP>/restaurant/admin/users " \
-H " Authorization: Bearer <user_token> " \
-H " Content-Type: application/json "
Port 8888 (dedicated — not path-prefixed)Images crapi/crapi-web, crapi/crapi-identity, crapi/crapi-community, crapi/crapi-workshop, PostgreSQL, MongoDB, MailHogInstances 7 microservices (single instance each) Resources ~3.0 CPU / ~2.0 GiB RAM total Framework React SPA + Java/Go/Python microservices Project github.com/OWASP/crAPI
crAPI is the OWASP flagship project for API security testing. It runs as 7 microservices on a dedicated port (8888) because the React SPA hardcodes its API paths and cannot be served behind a path prefix. The NSG allows inbound traffic on port 8888.
MailHog captures all emails sent by crAPI (account verification, password reset). Access MailHog via SSH tunnel on port 18025.
Category Vulnerabilities BOLA (Broken Object Level Authorization) Access other users’ vehicles, orders, and reports BFLA (Broken Function Level Authorization) Escalate to admin, access restricted endpoints Mass Assignment Modify protected fields (role, balance) via API SSRF (Server Side Request Forgery) Manipulate server-side URL fetching JWT Manipulation Forge or modify JWT tokens for privilege escalation NoSQL Injection Inject queries into MongoDB-backed endpoints Excessive Data Exposure API returns sensitive user data
# Verify crAPI is running
curl -sf " http://<PUBLIC_IP>:8888 " -o /dev/null -w " %{http_code} "
curl -s -X POST " http://<PUBLIC_IP>:8888/identity/api/auth/signup " \
-H " Content-Type: application/json " \
-d ' {"name":"Test User","email":"test@example.com","number":"1234567890","password":"Test1234!"} '
curl -s -X POST " http://<PUBLIC_IP>:8888/identity/api/auth/login " \
-H " Content-Type: application/json " \
-d ' {"email":"test@example.com","password":"Test1234!"} '
# Access MailHog (via SSH tunnel for email verification)
# ssh -L 18025:localhost:18025 azureuser@<PUBLIC_IP>
# Then open http://localhost:18025 in your browser
Port 8888 -> crapi-web (React SPA + nginx)
-> crapi-identity (Java, user auth, JWT)
-> crapi-community (Go, forums, posts)
-> crapi-workshop (Python, vehicle service)
-> crapi-postgres (PostgreSQL)
-> crapi-mailhog (email capture, port 18025)
Demo Use Case Primary App Secondary App WAF — SQL Injection DVWA Juice Shop WAF — XSS DVWA Juice Shop WAF — Command Injection DVWA — API Security — BOLA VAmPI — API Security — Auth bypass VAmPI Juice Shop API Security — Data exposure VAmPI httpbin Bot Defense — Brute force DVWA Juice Shop Bot Defense — Scraping Juice Shop — Client-Side Defense — DOM XSS Juice Shop — Client-Side Defense — Stored XSS DVWA Juice Shop Client-Side Defense — Card Skimmer CSD Demo — Client-Side Defense — Formjacker CSD Demo — Client-Side Defense — Keylogger CSD Demo — Client-Side Defense — Cryptominer CSD Demo — Client-Side Defense — DOM Hijack CSD Demo — API Security — GraphQL injection DVGA — API Security — GraphQL DoS DVGA — API Security — OWASP API Top 10 2023 RESTaurant crAPI API Security — BFLA RESTaurant crAPI API Security — Mass assignment crAPI RESTaurant API Security — SSRF crAPI RESTaurant API Security — JWT manipulation crAPI — API Security — NoSQL injection crAPI — Basic connectivity testing httpbin — Request diagnostics whoami httpbin Header injection verification whoami —