Skip to content

Applications

This repository provides two distinct origins; they are not feature-equivalent:

  • Azure full-origin: a VM running nginx in front of 41 containers for all nine applications and the path-based URLs documented below. Set ORIGIN from terraform output -raw origin_url in terraform/.
  • AWS Juice Shop: private Fargate tasks behind an Application Load Balancer (ALB). It serves Juice Shop directly at the ALB root (/), not at /juice-shop/. Set ORIGIN from the consuming configuration’s module output, for example terraform output -raw origin_url. The ALB is internal by default, so that URL resolves and responds only from an authorized routed network unless public exposure was explicitly configured.

The AWS module does not deploy nginx, a container host, or the other eight applications. Every path in the quick reference below, including non-Juice-Shop APIs, requires the Azure full-origin unless stated otherwise.

PathApplicationHTTP MethodExpected Response
/Landing pageGET200 HTML with links to all apps
/healthHealth checkGET200 JSON {"status":"healthy","component":"origin-server",...}
/juice-shop/Juice ShopGET200 HTML (Angular SPA, ~75 KB)
/juice-shop/rest/products/search?q=Juice Shop APIGET200 JSON {"status":"success","data":[...]} (36 products)
/dvwa/DVWAGET302 redirect to /dvwa/login.php
/dvwa/login.phpDVWA loginGET200 HTML login form
/dvwa/setup.phpDVWA setupGET200 HTML (first-run database init)
/vampi/VAmPIGET200 HTML (API docs)
/vampi/users/v1VAmPI APIGET200 JSON {"users":[...]}
/vampi/users/v1/registerVAmPI APIPOST200 JSON {"status":"success",...}
/vampi/users/v1/loginVAmPI APIPOST200 JSON {"auth_token":"...","status":"success"}
/httpbin/gethttpbinGET200 JSON with request details
/httpbin/posthttpbinPOST200 JSON with posted data
/httpbin/headershttpbinGET200 JSON {"headers":{...}}
/httpbin/status/:codehttpbinGETReturns the specified HTTP status code
/whoami/whoamiGET200 plain text with hostname, IP, all headers
/csd-demo/CSD DemoGET200 HTML checkout form with attack panel
/csd-demo/dashboardCSD attacker viewGET200 HTML showing exfiltrated data
/csd-demo/healthCSD healthGET200 JSON {"status":"healthy","component":"csd-demo",...}
/csd-demo/exfil/logCSD exfil logGET200 JSON array of captured data
/dvga/DVGA GraphiQLGET200 HTML (GraphiQL IDE)
/dvga/graphqlDVGA GraphQL APIPOST200 JSON GraphQL response
/restaurant/RESTaurantGET200 (redirects to docs)
/restaurant/docsRESTaurant SwaggerGET200 HTML (FastAPI Swagger UI)
/restaurant/openapi.jsonRESTaurant OpenAPIGET200 JSON OpenAPI spec
http://<PUBLIC_IP>:8888crAPIGET200 HTML (SPA)
http://<PUBLIC_IP>:8888/identity/api/auth/signupcrAPI signupPOST200 JSON
http://<PUBLIC_IP>:8888/identity/api/auth/logincrAPI loginPOST200 JSON {"token":"..."}

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.

OfferingURL behaviorRuntime
Azure full-origin${ORIGIN}/juice-shop/Four Docker containers behind nginx with sticky routing and a 60-second proxy-cache TTL
AWS Juice Shop${ORIGIN}/Private Fargate task or tasks behind an ALB; no nginx or host SSH

For Azure, obtain ORIGIN from the root configuration:

Terminal window
ORIGIN=$(terraform -chdir=terraform output -raw origin_url)
curl -sf "${ORIGIN}/juice-shop/" -o /dev/null -w "%{http_code}\n"

For AWS, expose the module’s origin_url from the consuming root configuration and use it without a /juice-shop/ prefix:

output "origin_url" {
value = module.juice_shop.origin_url
}
Terminal window
ORIGIN=$(terraform output -raw origin_url)
curl -sf "${ORIGIN}/" -o /dev/null -w "%{http_code}\n"
curl -sf "${ORIGIN}/rest/products/search?q=" | jq .
ScenarioCategoryAttack Vector
SQL Injection login bypassWAF' OR 1=1-- in the login email field
Reflected XSSWAF, CSDScript injection via search parameter
DOM-based XSSCSDPayload in URL fragment
Broken authenticationWAFBrute force login, JWT manipulation
API abuseAPI SecurityUnauthorized access to /api/ endpoints
Sensitive data exposureAPI SecurityAccessing user data without authorization
CSRFWAFCross-site request forgery on profile changes
Path/dvwa/
ImageCustom dvwa-fpm:latest (php-fpm + nginx, built from ghcr.io/digininja/dvwa:latest)
Instances4 (ports 8101-8104), sticky via hash $cookie_PHPSESSID
Resources0.5 CPU / 256 MiB RAM per instance
DatabaseShared MariaDB 10.11 (dvwa-db container, 1 CPU / 768 MiB)
FrameworkPHP 8 / php-fpm / MariaDB
Credentialsadmin / 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.

ScenarioCategorySecurity Level
SQL InjectionWAFLow: trivial ' OR 1=1#, High: blind SQLi
Command InjectionWAFLow: ; ls, High: filtered characters
File InclusionWAFLow: direct path traversal, High: sanitized
XSS (Reflected)WAF, CSDLow: basic <script>, High: encoded bypass
XSS (Stored)WAF, CSDLow: persistent script in guestbook
File UploadWAFLow: PHP shell upload, High: extension filtering
Brute ForceBot DefenseAutomated 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:

  1. Navigate to http://<PUBLIC_IP>/dvwa/setup.php
  2. Click Create / Reset Database
  3. Log in with admin / password
Path/vampi/
Imageerev0s/vampi:latest with gunicorn entrypoint (4 workers)
Instances4 (ports 5101-5104), sticky via ip_hash (SQLite per instance)
Resources0.5 CPU / 512 MiB RAM per instance
FrameworkPython / Flask / gunicorn
Projectgithub.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.

ScenarioOWASP API Top 10Method
Broken Object Level Authorization (BOLA)API1Access other users’ data by manipulating IDs
Broken AuthenticationAPI2Weak token handling, no rate limiting
Excessive Data ExposureAPI3API returns more data than the client needs
Mass AssignmentAPI6Modify admin fields via unexpected parameters
SQL InjectionAPI8Injection through API parameters
Improper Assets ManagementAPI9Undocumented API endpoints
Terminal window
# Register a new user
curl -X POST "http://<PUBLIC_IP>/vampi/users/v1/register" \
-H "Content-Type: application/json" \
-d '{"username":"test","password":"test123","email":"admin@example.com"}'
# Login
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/
Imagekennethreitz/httpbin:latest with gunicorn CMD override (-w 4 -k gevent --timeout 30)
Instances4 (ports 8201-8204), round-robin (stateless)
Resources0.5 CPU / 256 MiB RAM per instance
FrameworkPython / Flask / gunicorn + gevent
Projecthttpbin.org

httpbin is a simple HTTP request/response service useful for basic API demos, testing request headers, and verifying proxy behavior.

EndpointPurpose
/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
Terminal window
# 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/
Imagetraefik/whoami:latest
Instances4 (ports 8082-8085), round-robin (stateless)
Resources0.25 CPU / 64 MiB RAM per instance
FrameworkGo
Projectgithub.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 CaseWhat to Look For
Verify F5 XC header injectionX-Forwarded-For, True-Client-IP, X-Volterra-* headers
Confirm client IP visibilityX-Real-IP vs RemoteAddr
Debug WAF false positivesCompare request headers before/after F5 XC
Validate bot defense taggingX-Volterra-Bot-Type, X-Volterra-Bot-Verified headers
Check TLS terminationX-Forwarded-Proto shows https when TLS terminates at F5 XC
Terminal window
# 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:

Hostname: <container-hostname>
IP: <container-loopback-ip>
RemoteAddr: <immediate-peer-ip>:<ephemeral-port>
GET / HTTP/1.1
Host: <origin-hostname-or-ip>
User-Agent: curl/<version>
Accept: */*
True-Client-Ip: <simulated-client-ip>
X-Forwarded-For: <simulated-client-ip>, <trusted-proxy-ip>
X-Forwarded-Proto: https
X-Real-Ip: <observed-client-ip>

DVGA (Damn Vulnerable GraphQL Application)

Section titled “DVGA (Damn Vulnerable GraphQL Application)”
Path/dvga/
Imagedolevf/dvga:latest
Instances4 (ports 5201-5204), sticky via ip_hash (SQLite per instance)
Resources0.5 CPU / 256 MiB RAM per instance
FrameworkPython / Flask / GraphQL
Projectgithub.com/dolevf/Damn-Vulnerable-GraphQL-Application

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.

ScenarioCategoryAttack Vector
GraphQL InjectionAPI SecurityMalicious queries via string interpolation
Denial of ServiceAPI SecurityDeeply nested queries, batch queries, resource exhaustion
Authorization BypassAPI SecurityAccessing unauthorized data through GraphQL
Information DisclosureAPI SecurityIntrospection queries revealing schema details
Batching AttackAPI SecurityMultiple operations in a single request
Terminal window
# 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 } } }"}'

RESTaurant (Damn Vulnerable RESTaurant API Game)

Section titled “RESTaurant (Damn Vulnerable RESTaurant API Game)”
Path/restaurant/
ImageCustom build from theowni/Damn-Vulnerable-RESTaurant-API-Game
Instances4 (ports 8301-8304), round-robin (shared PostgreSQL)
Resources0.5 CPU / 256 MiB RAM per instance
DatabaseShared PostgreSQL 15.4 (restaurant-db container, 0.5 CPU / 512 MiB)
FrameworkPython / FastAPI / PostgreSQL
Credentialsadmin / password (PostgreSQL)
Projectgithub.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.

ScenarioOWASP API Top 10 2023Method
Broken Object Level Authorization (BOLA)API1Access other users’ orders by manipulating IDs
Broken AuthenticationAPI2Weak token handling, credential stuffing
Broken Object Property Level AuthorizationAPI3Mass assignment on user profile fields
Unrestricted Resource ConsumptionAPI4No rate limiting on endpoints
Broken Function Level Authorization (BFLA)API5Access admin endpoints as regular user
Server Side Request Forgery (SSRF)API7Manipulate server-side URL requests
Security MisconfigurationAPI8Verbose error messages, default credentials
Terminal window
# Swagger UI
curl -sf "http://<PUBLIC_IP>/restaurant/docs" -o /dev/null -w "%{http_code}"
# OpenAPI spec
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"
Port8888 (dedicated — not path-prefixed)
Imagescrapi/crapi-web, crapi/crapi-identity, crapi/crapi-community, crapi/crapi-workshop, PostgreSQL, MongoDB, MailHog
Instances7 microservices (single instance each)
Resources~3.0 CPU / ~2.0 GiB RAM total
FrameworkReact SPA + Java/Go/Python microservices
Projectgithub.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.

CategoryVulnerabilities
BOLA (Broken Object Level Authorization)Access other users’ vehicles, orders, and reports
BFLA (Broken Function Level Authorization)Escalate to admin, access restricted endpoints
Mass AssignmentModify protected fields (role, balance) via API
SSRF (Server Side Request Forgery)Manipulate server-side URL fetching
JWT ManipulationForge or modify JWT tokens for privilege escalation
NoSQL InjectionInject queries into MongoDB-backed endpoints
Excessive Data ExposureAPI returns sensitive user data
Terminal window
# Verify crAPI is running
curl -sf "http://<PUBLIC_IP>:8888" -o /dev/null -w "%{http_code}"
# Sign up a new user
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!"}'
# Log in
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-mongo (MongoDB)
-> crapi-mailhog (email capture, port 18025)
Demo Use CasePrimary AppSecondary App
WAF — SQL InjectionDVWAJuice Shop
WAF — XSSDVWAJuice Shop
WAF — Command InjectionDVWA—
API Security — BOLAVAmPI—
API Security — Auth bypassVAmPIJuice Shop
API Security — Data exposureVAmPIhttpbin
Bot Defense — Brute forceDVWAJuice Shop
Bot Defense — ScrapingJuice Shop—
Client-Side Defense — DOM XSSJuice Shop—
Client-Side Defense — Stored XSSDVWAJuice Shop
Client-Side Defense — Card SkimmerCSD Demo—
Client-Side Defense — FormjackerCSD Demo—
Client-Side Defense — KeyloggerCSD Demo—
Client-Side Defense — CryptominerCSD Demo—
Client-Side Defense — DOM HijackCSD Demo—
API Security — GraphQL injectionDVGA—
API Security — GraphQL DoSDVGA—
API Security — OWASP API Top 10 2023RESTaurantcrAPI
API Security — BFLARESTaurantcrAPI
API Security — Mass assignmentcrAPIRESTaurant
API Security — SSRFcrAPIRESTaurant
API Security — JWT manipulationcrAPI—
API Security — NoSQL injectioncrAPI—
Basic connectivity testinghttpbin—
Request diagnosticswhoamihttpbin
Header injection verificationwhoami—