DOWNLOADABLE / LOCALHOST ONLY

A vulnerable lab with a hard safety boundary.

Run secure and intentionally vulnerable controls side by side across WSHawk's web, GraphQL, browser, WebSocket, authorization, injection, OAST, chaining, binary, and defensive workflows.

Node.js 20+ or Docker · 19 verification tests · SHA-256 C88B130A2DA2…C2CB62647B

academy-lab
$ npm install
$ npm start

WSHawk Academy Lab running at
http://127.0.0.1:5177

LOCAL TRAINING ONLY
Do not expose this service.
Ready for WSHawk
Deliberately vulnerable software

Run it only on your own computer. The Node server binds to 127.0.0.1 by default and rejects arbitrary interfaces. The Docker Compose file publishes only 127.0.0.1:5177. Never deploy or tunnel it publicly.

01 / START IN THREE STEPS

From ZIP to first response.

01

Extract and install

Extract the ZIP, open a terminal inside wshawk-academy-lab, and install its single WebSocket dependency.

npm install
02

Start locally

Start the server. It must print 127.0.0.1:5177. Leave this terminal open.

npm start
03

Create the project

In WSHawk create Academy Lab, set the target origin, then send the health request.

GET http://127.0.0.1:5177/health
Prefer Docker?The compose file still publishes on loopback only.
docker compose up --build
03 / SECURE + VULNERABLE PAIRS

Know what correct behavior looks like.

Run the secure route first. It gives you the baseline needed to interpret the intentionally vulnerable pair without status-only guessing.

ExerciseSecure controlTraining flawGuide
Horizontal IDOR / BOLAGET /api/resources/resource-bGET /api/resources-insecure/resource-bOpen lesson ↗
Tenant isolationGET /api/tenants/tenant-b/reportGET /api/tenants-insecure/tenant-b/reportOpen lesson ↗
Admin-only / BFLAGET /api/admin/auditGET /api/admin-insecure/auditOpen lesson ↗
Missing authenticationGET /api/profile/user_bGET /api/profile-public?user_id=user_bOpen lesson ↗
State-changing IDORPATCH /api/resources/resource-bPATCH /api/resources-insecure/resource-bOpen lesson ↗
GraphQL BOLAresource(id: $id)resourceInsecure(id: $id)Open lesson ↗
WebSocket roomsmode: securemode: insecureOpen lesson ↗
Race conditionReset + one allowed couponTwo-request check/update raceOpen lesson ↗
SQL injectionPOST /api/search-securePOST /api/search-insecureOpen lesson ↗
Reflected + DOM XSS/xss/reflected-secure + /xss/dom-secure/xss/reflected-insecure + /xss/dom-insecureOpen lesson ↗
Command injectionPOST /api/diagnostics-securePOST /api/diagnostics-insecureOpen lesson ↗
NoSQL injectionPOST /api/users-securePOST /api/users-insecureOpen lesson ↗
Path traversal / LFIGET /files-secure?name=GET /files-insecure?name=Open lesson ↗
XXEPOST /xml-securePOST /xml-insecureOpen lesson ↗
SSRF + local OASTGET /fetch-secure?url=GET /fetch-insecure?url= + /oast/interactionsOpen lesson ↗
Prototype pollutionPOST /api/settings-securePOST /api/settings-insecureOpen lesson ↗
Open redirectGET /redirect-secure?next=GET /redirect-insecure?next=Open lesson ↗
Crawler + directoriesSame-origin bounded crawl/crawl/start + discovery filesOpen lesson ↗
Headers + sensitive dataGET /headers/secure + /secrets/secureGET /headers/insecure + /secrets/insecureOpen lesson ↗
CORSGET /cors/secureGET /cors/insecureOpen lesson ↗
CSRFPOST /api/preferences-securePOST /api/preferences-insecureOpen lesson ↗
HTTP attack chainExtract token + nextTemplate Authorization + replayOpen lesson ↗
WS scanner + SPEOne marked field + strict limitsws://127.0.0.1:5177/ws-vulnerableOpen lesson ↗
Binary protocolGET /binary/sampleSend a binary WebSocket frameOpen lesson ↗
Session securityws-secure fixation/impersonation controlsws-insecure client-trusted stateOpen lesson ↗
Bot + CSWSH validation/bot/secure + /ws-secure/bot/insecure + /ws-insecureOpen lesson ↗
Webhook integrationSanitized previewPOST /integrations/webhookOpen lesson ↗
04 / VERIFY AND RESET

The lab tests its own assumptions.

Run the included test suite before a class. It checks authorization, GraphQL, injection families, browser targets, local OAST, CORS, discovery, chaining, WebSocket scanners, Origin policy, write rollback, and bounded races.

npm test

✔ secure resource blocks foreign user
✔ insecure resource exposes owner data
✔ GraphQL 200 semantics verified
✔ WebSocket room controls verified
✔ write rollback restores state
✔ local OAST correlation verified
✔ WebSocket scanner + Origin verified
✔ binary + session controls verified
✔ bounded race reproduced

tests 19 · pass 19 · fail 0
READY TO PRACTICE

Start with the secure control.

Then change one variable, capture both outcomes, and explain what the evidence proves. Use a separately authorized target for public DNS, WHOIS, subdomain, port, and TLS practice.

Begin WSHawk Practitioner