What this course is
Get oriented before you touch a target.
Glacier is a web application security scanner you built from scratch: an intercepting proxy, a passive scanner, a spider, an active scanner, a repeater, a fuzzer, and a findings tracker, all wired together and viewed through a native desktop HUD. This course doesn't re-explain what each button does — the README already does that. It teaches the order and judgment a professional applies when using it, so your findings are accurate, reproducible, and defensible.
./setup.sh and ./start.sh at least once and wants to move from "poking around" to a repeatable professional workflow.Architecture & setup
Understand what's actually running before you rely on it.
Every Glacier component talks to one shared SQLite database. The proxy and API are separate long-running processes so the API can serve the HUD live while the proxy keeps capturing in the background — that separation is why you can leave a proxy running for hours and query findings at any point without stopping it.
Bring it up
# requires Python 3.10+, Node.js 18+, optionally tmux git clone <your-repo-url> cd glacier ./setup.sh # venv + Python/Node deps ./start.sh # proxy + API + HUD together in tmux panes
No tmux? start.sh prints the three commands so you can run proxy, API, and HUD in separate terminals — do this once deliberately so you know what each process's logs look like on their own, before you ever rely on the combined tmux view during a real engagement.
http://localhost:8090, hit Connect — then immediately check the proxy log for the mitmproxy CA cert path. You'll need it in the next module.The intercepting proxy
Everything downstream depends on capture quality here.
Point your browser's HTTP/HTTPS proxy at 127.0.0.1:8081, then visit http://mitm.it through that proxy once to install and trust mitmproxy's CA certificate — without it, every HTTPS request will fail TLS validation and you'll capture nothing.
Professional habits at this stage
- Use a dedicated browser profile for the engagement so unrelated tabs don't pollute your traffic table.
- Walk the application manually first, touching every feature at least once, before you spider or scan anything — this is what gives the passive scanner real traffic to inspect and gives the spider real starting links.
- Check the traffic table (
/api/traffic) periodically to confirm requests are actually landing before you assume the proxy is working.
Passive scanning
Your free, zero-risk first pass — read it like a report, not a checklist.
The passive scanner runs automatically on every captured response, checking for missing security headers, insecure cookies, server version disclosure, verbose error messages, and exposed secrets (API keys, JWTs, private keys). It never sends anything extra, which makes it safe to run continuously and safe to run against production.
What a professional does with this pass
- Skim
/api/findings/summaryfirst for the shape of the app's baseline hygiene, not individual bugs. - Triage exposed secrets and verbose errors immediately — these can change the authorization conversation before you even get to active testing.
- Treat missing headers as context, not headline findings, unless the client's report format calls for them explicitly.
The spider
Build a real map of the attack surface before you scan anything.
The spider crawls from a starting URL, following links and form actions within the same host. Run it from a URL deep in the app (post-login, if relevant) rather than only the homepage, so it isn't limited to what's linked from the marketing pages.
POST /api/spider/start { "start_url": "https://target.example.com/dashboard" } GET /api/spider/status/{job_id} GET /api/spider/results/{job_id}
Active scanning
On-demand, per-URL testing — the first place real payloads leave your machine.
Active scanning tests for reflected XSS, SQL injection (error-based, boolean-based blind, time-based blind), path traversal / local file inclusion, OS command injection (reflected and blind/time-based), and open redirect, using standard published detection methodology. It requires confirm: true — treat that flag as a deliberate decision each time, not a default you always set.
POST /api/active/scan { "url": "https://target.example.com/search?q=test", "confirm": true } GET /api/active/status/{job_id}
| Class | Detection style |
|---|---|
| Reflected XSS | Reflection + context probing |
| SQL injection | Error-based, boolean-blind, time-blind |
| Path traversal / LFI | Payload + response inspection |
| OS command injection | Reflected and blind/time-based |
| Open redirect | Location header verification |
Authenticated testing
Most real findings live behind a login — don't skip this.
Pass an auth object to /api/spider/start, /api/active/scan, or /api/pipeline/scan so protected pages get discovered and tested instead of silently skipped.
Cookie mode — fastest for a one-off session
{ "auth": { "mode": "cookie", "cookie_header": "session=abc123" } }
Form mode — Glacier logs in itself, and re-authenticates on logout
{ "auth": {
"mode": "form",
"login_url": "https://target.example.com/login",
"username": "hackops", "password": "hackops",
"success_indicator": "Welcome back",
"logout_indicator": "Please log in"
} }
success_indicator and logout_indicator are optional but worth setting on every real engagement — they're what let a long pipeline scan notice it got logged out partway through and recover on its own, instead of quietly scanning the login page for an hour.
tools/vulnerable_test_app.py ships with a real login flow (hackops / hackops) and a protected /account page built for exactly this — confirm both auth modes work there before you point either at a client.Repeater
Manual verification — where a hit becomes a finding.
Repeater is a manual request editor: craft a request from scratch or pull one straight from History, tweak method, headers, or body, resend, and compare responses. Every send is logged, so you can always jump back to an earlier attempt. Unlike the active scanner, Repeater has no confirmation gate — it sends exactly and only the one request you typed, the same trust model as curl or a browser's dev tools.
Fuzzer
Batch testing for the parameter you already suspect.
Mark an injection point with the literal text FUZZ anywhere in a request — URL, header, or body — supply a wordlist, and one request goes out per payload. Results land in a sortable table (status code, response length, timing) so the one anomalous response in a batch of hundreds stands out. It's gated behind confirm: true and a 1000-payload hard cap, the same posture as the active scanner.
POST /api/fuzz/start { "request_id": 42, "wordlist": "common-params", "confirm": true } GET /api/fuzz/results/{job_id}?sort_by=length&order=desc
- Escalate straight into the Fuzzer with one click from History or Repeater once you've identified a promising parameter.
- Sort by response length first to spot the outlier row, then by status code to separate real anomalies from expected auth/validation errors.
/api/fuzz/wordlistslists the built-in wordlists and their sizes — check size against the 1000-payload cap before you start.
Findings triage
Turn a pile of hits into a report someone can act on.
Glacier deduplicates repeated issues across many pages into grouped findings, with open / fixed / false-positive status tracking — use that grouping as your triage queue, not the flat list.
GET /api/findingsGET /api/findings/groupedGET /api/findings/summaryPATCH /api/findings/bulk-statusExample severity labeling in a report
CRITICAL HIGH MEDIUM INFO
Automation & the API
Stop clicking through the HUD for repeatable work.
Every HUD action is just a call to the same FastAPI server, which means anything you can do by hand you can script. The pipeline endpoint is the one professionals lean on most: it crawls a site and auto-scans every discovered parameterized URL in one call.
POST /api/pipeline/scan { "start_url": "https://target.example.com/", "confirm": true, "auth": { "mode": "cookie", "cookie_header": "session=abc123" } } GET /api/pipeline/status/{job_id}
Because it accepts the same optional auth object as the spider and active scanner, one authenticated pipeline call can replace an entire manual click-through session — reserve it for hosts you've already scoped and are confident about, since it commits to crawling and actively scanning in one step.
The full methodology
How the modules above chain into one engagement.
confirm: true, small batches firstPractice range & next steps
Rehearse the whole methodology somewhere nothing is at stake.
tools/vulnerable_test_app.py is a small, deliberately vulnerable local Flask app — SQLi, XSS, path traversal, OS command injection, and open redirect endpoints, each paired with a properly-guarded "safe" endpoint as a negative control. Confirm the active scanner correctly flags the vulnerable endpoints and stays quiet on the safe ones before you ever point Glacier at something real.
. venv/bin/activate python3 tools/vulnerable_test_app.py # http://127.0.0.1:5001
- Run the full methodology from Module 11 against the practice app end to end.
- Deliberately break your own auth config (wrong
login_url, wrong indicator strings) and watch how the pipeline scan fails, so you recognize it fast on a real engagement. - Time yourself. A professional's edge is mostly how quickly they move from "hit" to "verified, minimized, triaged."