Web Application Pentest Methodology & the OWASP Testing Guide
Web Application Pentest Methodology & the OWASP Testing Guide
This is Chapter 1 of the Web Application Pentest notebook. The earlier notebooks built everything underneath a web assessment: the Web Fundamentals series taught how HTTP, cookies, the same-origin policy and TLS actually behave; the Scanning & Enumeration and Vulnerability Assessment notebooks taught how to find live hosts, identify services, and turn scanner output into validated findings. This notebook narrows the lens onto a single, enormous attack surface — the web application — and this opening chapter is about method, not exploits. Before you learn to break authentication, smuggle a request, or blind-inject a database in the chapters that follow, you need the discipline that makes those techniques add up to an assessment rather than a pile of anecdotes.
The single biggest difference between a beginner and a professional web tester is not how many payloads they know. It is whether they can take a scope of one or one hundred applications and work through every one the same way, cover every class of weakness, prove each finding, and hand back a report that an engineering team can act on. That repeatability comes from a methodology, and the industry has a canonical one: the OWASP Web Security Testing Guide (WSTG). This chapter teaches you what the WSTG is, how it is structured, how it relates to the far more famous OWASP Top 10, and how to turn its checklist into a phased workflow you run on autopilot. By the end you will be able to look at a login page and know — without thinking hard — the twenty things you are about to test and the order you will test them in.
Everything in this notebook assumes an authorised, scoped engagement. Sending a single crafted request to a web application you do not own or have explicit written permission to test is, in most jurisdictions, an offence under computer-misuse legislation regardless of whether any data was changed — the UK Computer Misuse Act 1990, the US Computer Fraud and Abuse Act, and equivalents elsewhere all criminalise unauthorised access, and "I only tested for SQL injection, I didn't extract anything" is not a defence. Scope and authorisation are hard boundaries, treated as such throughout, and the rules-of-engagement discipline is covered in Part 2.
flowchart LR
A[Scope + Rules<br/>of Engagement] --> B[Recon &<br/>Information Gathering]
B --> C[Map the<br/>Attack Surface]
C --> D[Test by WSTG<br/>category]
D --> E[Validate &<br/>build evidence]
E --> F[Rate severity<br/>CVSS + context]
F --> G[Report]
G --> H[Retest /<br/>remediation check]
Why This Matters
Web applications are where most organisations expose the most functionality to the most people. An external network pentest of a modern company often finds a hardened perimeter — a handful of ports, everything patched, nothing obvious — and then a single web application behind it that accepts user input in two hundred places, talks to three internal databases, calls out to a payment provider, and was written under deadline by developers who were never taught the same-origin policy. The web app is the attack surface. It is also the surface that changes weekly, which is why a method you can re-run beats a bag of one-off tricks: the app you tested last quarter is not the app in front of you now.
A structured methodology buys you four things at once. Coverage: you test every category of weakness, not just the ones you find interesting, so you don't hand back a report full of XSS that misses the broken access control that actually loses the company its data. Repeatability: two testers, or the same tester six months apart, produce comparable results. Defensibility: when a developer pushes back on a finding — and they will — you can point at the exact request, the exact response, and the exact WSTG test that governs it. Efficiency: you stop re-deciding what to do next on every page, because the method already told you.
This chapter is deliberately about the scaffolding. The exploitation chapters that follow — mapping the attack surface in depth (Chapter 2), authentication and session and access-control testing (Chapter 3), and chaining web bugs into a shell (Chapter 4) — all hang off the skeleton built here. Learn the skeleton first and the muscles attach cleanly.
Part 1: What a Web Application Pentest Actually Is
The phrase "web pentest" gets stretched to cover four quite different activities. Being precise about which one you are doing changes your scope, your time budget, your tooling, and what the client is entitled to expect.
A web application penetration test is a time-boxed, scoped, authorised assessment of one or more specific applications, aiming for coverage of the whole application against a methodology and a written report of every finding with reproduction steps and remediation advice. It is the subject of this notebook. The deliverable is the report; the goal is to find as many real, distinct weaknesses as the time allows and describe them so they can be fixed.
A bug-bounty engagement is open-ended, usually black-box, and rewards impact rather than coverage. A bounty hunter is not paid to confirm that the "forgot password" flow correctly rate-limits — they are paid for the one high-severity bug nobody found yet. Bounty work and pentest work share techniques but optimise for opposite things: the pentester must be exhaustive and boring; the hunter must be selective and lucky. Many findings in this notebook are directly reportable to a bounty programme, and where a technique is a classic bounty earner it will be called out inline — but the methodology here is the pentest methodology, built for coverage.
A vulnerability scan (Nessus, an authenticated web scan, or a DAST tool like OWASP ZAP in automated mode) is an unattended tool run that produces hypotheses. As the Vulnerability Assessment notebook hammered home, a scanner reports claims, not facts; a pentest includes automated scanning as one input but is defined by the human validation and the manual test cases a scanner cannot perform — business-logic flaws, chained access-control bypasses, anything requiring understanding of intent.
A secure code review / SAST engagement reads the source. It is white-box by definition, catches classes of bug that are invisible from the outside (a hardcoded key never sent over the wire, a race in a function you never see), and misses things that only appear at runtime (a misconfigured reverse proxy, a WAF that changes behaviour). Code review and pentest are complementary; the strongest assurance comes from both.
mindmap
root((Web security<br/>assessment))
Pentest
Scoped + timeboxed
Coverage vs methodology
Written report
Manual + automated
Bug bounty
Open-ended
Rewards impact
Mostly black-box
Vuln scan / DAST
Unattended
Produces hypotheses
Needs validation
Code review / SAST
Reads source
White-box
Catches hidden classes
Where this sits in the engagement lifecycle: the Pentest Methodology notebook (Chapter 1) laid out the generic lifecycle — pre-engagement, recon, scanning, exploitation, post-exploitation, reporting. A web pentest is that same lifecycle with the middle collapsed onto one target type. Recon and scanning become "map the application"; exploitation becomes "work the WSTG categories"; post-exploitation becomes "demonstrate impact — pivot, escalate, exfil a proof record" — all constrained by the rules of engagement.
Part 2: Scope, Authorisation, and Rules of Engagement
Nothing in this notebook is lawful without written authorisation naming the systems you are allowed to touch. The Security Foundations and Pentest Methodology notebooks covered engagement law in general; here is what specifically matters for web work, where the boundaries are unusually easy to cross by accident.
The scope is a list of origins, not a vibe. A web scope should enumerate
exact hostnames and, ideally, exact base paths: https://app.example.com/,
https://api.example.com/v2/, in scope; https://blog.example.com (WordPress
hosted by a third party) out of scope. The subtlety that trips people: a single
application routinely pulls in other origins — an OAuth provider, a CDN, an
analytics host, a payment iframe, an S3 bucket. Testing the in-scope app is
fine; firing payloads at the OAuth provider's login endpoint because it appeared
in a redirect is testing their system and is out of scope unless the document
says otherwise.
Third-party and cloud rules. If the target is hosted on AWS, Azure or GCP, the cloud provider's own testing policy applies on top of the client's authorisation. The major providers now permit customer-driven pentesting of your own resources without prior notice for most services, but denial-of-service testing is still prohibited and some managed services are off-limits. A web pentest that accidentally becomes a load test can breach the hosting agreement even when the client authorised you.
Destructive-action boundaries. Web apps have buttons that do irreversible things — "delete account", "issue refund", "send 10,000 emails", "cancel subscription". Your rules of engagement must state whether you may trigger state-changing actions, and against which data. The safe default, unless told otherwise, is: test read and auth paths freely, but for destructive endpoints prove the vulnerability with the minimum action (e.g. show you can reach the "delete" endpoint as another user by deleting your own second test account, not a real one).
Test accounts and data. Ask for at least two accounts at each privilege level (two low-priv users, two admins). You need two users at the same level to test horizontal access control (can user A read user B's order?), and users at different levels to test vertical access control (can a normal user hit an admin function?). One account is not enough to test authorisation at all.
A minimal ROE checklist for web work:
| Item | Why it matters |
|---|---|
| Exact in-scope hostnames + paths | Prevents out-of-scope origins (OAuth/CDN/payment) being tested |
| Explicitly out-of-scope hosts | Named exclusions remove ambiguity |
| Allowed source IPs / VPN | Lets the blue team distinguish you from a real attacker |
| Test window (dates/times) | Some tests are only allowed off-peak |
| Destructive-action policy | Whether state-changing endpoints may be exercised |
| DoS / brute-force limits | Rate-limit and volume caps to avoid outages |
| Test accounts (2x per role) | Required for horizontal + vertical authz testing |
| WAF/rate-limit posture | Whether protections are on, off, or IP-allowlisted for you |
| Data handling | How to store/destroy any data you access as proof |
| Emergency contact | Who to call if you knock over production |
A note the blue team will thank you for: ask whether they want you to test with the WAF on (realistic attacker view) or with your IP allowlisted through it (thorough coverage of the app itself). Both are valid; testing only through a WAF can hide real app bugs, while testing only allowlisted can over-report bugs the WAF would have blocked. The professional answer is usually "allowlisted for coverage, then spot-check key findings with the WAF on to confirm real-world exploitability" — and you state which mode each finding was found in.
Part 3: The OWASP Web Security Testing Guide (WSTG)
The OWASP Web Security Testing Guide is the closest thing the industry has to a canonical, open, vendor-neutral methodology for testing web applications. It is a free document maintained by the Open Worldwide Application Security Project, and the current stable release is v4.2. Where the OWASP Top 10 is a short awareness list of the most critical risk categories, the WSTG is a long, structured checklist of test cases — hundreds of them — each with an identifier, an objective, how to test (black-box and, where relevant, grey/white-box), and remediation guidance. If the Top 10 tells you what tends to go wrong, the WSTG tells you what to actually do at the keyboard.
Why you build your methodology on the WSTG rather than inventing your own: it is comprehensive (it is very hard to think of a web test class it omits), it is stable and versioned (so a report can cite "WSTG-ATHN-03" and any competent reader knows exactly which test), and it is neutral (no tool vendor owns it, so it doesn't push you toward one product). Most commercial pentest methodologies are, under the marketing, a WSTG derivative.
The WSTG identifier scheme. Every test case has an ID of the form
WSTG-<CATEGORY>-<NN>. The category is a short code; the number is the test
within that category. So WSTG-INPV-05 is the fifth Input Validation test (SQL
Injection), and WSTG-SESS-01 is the first Session Management test (testing for
session-management schema and cookie attributes). Citing these in a report is
enormously valuable: it makes your coverage auditable ("we performed
WSTG-ATHN-01 through -10") and lets the client's own team re-run any test you
describe.
The WSTG groups its test cases into twelve categories (plus a large information-gathering group). Learn these codes — they become the spine of your workflow:
| Code | Category | Representative test |
|---|---|---|
| WSTG-INFO | Information Gathering | Fingerprint web server, enumerate app entry points |
| WSTG-CONF | Configuration & Deploy Mgmt | Test for old/backup files, HTTP methods, HSTS, admin interfaces |
| WSTG-IDNT | Identity Management | Role definitions, account provisioning, username enumeration |
| WSTG-ATHN | Authentication | Default creds, lockout, weak reset, credentials over encrypted channel |
| WSTG-ATHZ | Authorization | Directory traversal, privilege escalation, IDOR/insecure direct object refs |
| WSTG-SESS | Session Management | Cookie attributes, session fixation, CSRF, logout, timeout |
| WSTG-INPV | Input Validation | XSS, SQLi, LDAP/XML/command injection, SSRF, SSTI, header injection |
| WSTG-ERRH | Error Handling | Analysis of error codes and stack traces |
| WSTG-CRYP | Cryptography | Weak TLS, padding oracle, sensitive data over unencrypted channels |
| WSTG-BUSL | Business Logic | Logic data validation, workflow circumvention, function abuse |
| WSTG-CLNT | Client-Side | DOM XSS, JavaScript execution, clickjacking, postMessage, CORS |
| WSTG-APIT | API Testing | API-specific reconnaissance and testing (added in 4.2) |
How the categories map to a workflow. You do not test them in alphabetical order — you test them in a dependency order that mirrors how you learn the app. Information Gathering and Configuration first (you must know the app before you attack it); then Identity, Authentication, Session, Authorization (the whole access-control stack, because a session bug and an authz bug interact); then Input Validation and Client-Side (the injection surface); then Error Handling and Cryptography (often observed while doing the above); and Business Logic threaded throughout, because logic flaws only make sense once you understand the app's intended workflow.
flowchart TD
INFO[WSTG-INFO<br/>Information Gathering] --> CONF[WSTG-CONF<br/>Configuration]
CONF --> IDNT[WSTG-IDNT<br/>Identity]
IDNT --> ATHN[WSTG-ATHN<br/>Authentication]
ATHN --> SESS[WSTG-SESS<br/>Session Mgmt]
SESS --> ATHZ[WSTG-ATHZ<br/>Authorization]
ATHZ --> INPV[WSTG-INPV<br/>Input Validation]
INPV --> CLNT[WSTG-CLNT<br/>Client-Side]
CLNT --> CRYP[WSTG-CRYP<br/>Cryptography]
CONF -.observed throughout.-> ERRH[WSTG-ERRH<br/>Error Handling]
ATHZ -.threaded throughout.-> BUSL[WSTG-BUSL<br/>Business Logic]
INFO -.for APIs.-> APIT[WSTG-APIT<br/>API Testing]
Part 4: The OWASP Top 10 — and Why It Is Not a Methodology
The OWASP Top 10 is the most famous artefact OWASP produces, and it is routinely misused. It is an awareness document — a periodically updated list of the ten most critical web application security risk categories, ranked from real-world data (incidence in tested apps, CVE/CVSS data, and a survey of practitioners). It exists to give developers, managers and auditors a shared vocabulary and a priority order. It is not a test plan: you cannot "test the OWASP Top 10" and claim coverage, because each entry is a broad category containing many distinct test cases that live in the WSTG.
The current list is OWASP Top 10 (2021):
| Rank | Category | Maps to WSTG (primary) |
|---|---|---|
| A01 | Broken Access Control | WSTG-ATHZ (IDOR, priv-esc, traversal) |
| A02 | Cryptographic Failures | WSTG-CRYP (weak TLS, data in the clear) |
| A03 | Injection | WSTG-INPV (SQLi, XSS, command, LDAP, SSTI) |
| A04 | Insecure Design | Cross-cutting; WSTG-BUSL, threat modelling |
| A05 | Security Misconfiguration | WSTG-CONF (headers, methods, default files) |
| A06 | Vulnerable & Outdated Components | WSTG-INFO/CONF + SCA tooling |
| A07 | Identification & Authentication Failures | WSTG-ATHN, WSTG-SESS |
| A08 | Software & Data Integrity Failures | WSTG-INPV (insecure deserialization), CI/CD |
| A09 | Security Logging & Monitoring Failures | Detection side; largely blue-team |
| A10 | Server-Side Request Forgery (SSRF) | WSTG-INPV-19 |
Two things to take from this. First, Broken Access Control is number one — it moved to the top in 2021 because it is both extremely common and extremely damaging, and because scanners are bad at finding it (it requires understanding of who should be able to do what). That is why access control gets its own dedicated chapter (Chapter 3) later and why you always test with multiple accounts. Second, the Top 10 and WSTG are complementary, not competing: use the Top 10 to communicate risk and prioritise, and the WSTG to actually test. A good report groups findings by Top 10 category (management understands it) while every individual finding cites its specific WSTG test ID (engineers can reproduce it).
A note on the API Security Top 10. OWASP maintains a separate Top 10 for APIs (current: API Security Top 10 2023), because API risks skew differently — Broken Object Level Authorization (BOLA, the API cousin of IDOR) dominates. When the target is primarily an API (as most modern "web apps" partly are), you test against both the web WSTG and the API Security Top 10; the WSTG's WSTG-APIT category and the API Top 10 overlap heavily.
Part 5: Threat-Modelling the Application Before You Touch It
The best testers spend the first hour of an engagement thinking, not typing. Threat modelling (covered generically in the Security Foundations notebook with STRIDE and attack trees) applies directly here: before you send payloads, you build a mental — and ideally written — model of what the application is, what it protects, and where the valuable, dangerous, or trust-crossing operations are. That model tells you where to spend your limited time.
Ask, and write down answers to, four questions:
- What does the app do, and who uses it? A banking app, a CMS, an internal HR tool and a public marketing site have wildly different risk profiles and different high-value targets. Identify the actors: anonymous visitor, registered user, privileged user, admin, service/API caller, support agent.
- What are the assets? The data and operations worth protecting: user PII, payment data, the ability to move money, the ability to change other users' data, admin functionality, the underlying server. These are what an attacker (and therefore you) will aim at.
- Where are the trust boundaries? Every point where data crosses from a less-trusted zone to a more-trusted one is a place to test: browser to server, server to database, app to third-party API, user-role to admin-role, tenant A to tenant B in a multi-tenant SaaS. Injection and access-control bugs cluster on these boundaries.
- What is the intended workflow, and how could it be abused? For each valuable operation (checkout, password reset, funds transfer, file upload), what is the designed sequence of steps, and what happens if you do them out of order, skip one, repeat one, or supply a value the designer didn't expect? This is the seed of every business-logic finding.
graph LR
subgraph Untrusted
A[Anonymous user]
U[Authenticated user]
end
subgraph AppTier[App tier - trust boundary 1]
W[Web / API server]
end
subgraph DataTier[Data tier - trust boundary 2]
DB[(Database)]
FS[(File store)]
end
subgraph External[External - trust boundary 3]
P[Payment API]
O[OAuth IdP]
end
A -->|HTTP| W
U -->|HTTP + session| W
W -->|SQL| DB
W -->|read/write| FS
W -->|API call| P
W -->|redirect/token| O
A written threat model does not need to be elaborate — a one-page list of actors, assets, boundaries and high-value workflows is enough, and it directly seeds your test plan: each trust boundary becomes a set of WSTG-INPV and WSTG-ATHZ tests, each workflow becomes a WSTG-BUSL test, each actor pair becomes a horizontal/vertical access-control test.
Part 6: Grey-Box, Black-Box, and White-Box Web Engagements
How much the client tells you up front changes your method, your time budget, and your coverage. The three models are points on a spectrum of information provided to the tester.
Black-box: you get a URL and (usually) test credentials, nothing else — no source, no architecture docs, no internal knowledge. It simulates an external attacker and tests the app and the difficulty of discovering things. It is realistic but time-expensive: you spend a large fraction of the budget just mapping what a white-box tester would be handed. Pure black-box is common in bug bounty and in "assumed breach not granted" red-team style engagements.
Grey-box: the pragmatic default for most commercial web pentests. You get credentials at each role, maybe an API spec (OpenAPI/Swagger), maybe an architecture diagram, and someone to answer questions — but not the source. This is the sweet spot: you skip the wasteful pure-discovery phase and spend the budget on actually testing, while still exercising the running system the way an attacker would. Almost everything in this notebook assumes grey-box.
White-box: you get source code, credentials, architecture, and often a developer to walk you through it. This yields the deepest coverage — you can read the exact query behind an injection, confirm a fix, find the hardcoded key that never traverses the wire — and pairs naturally with a code review. It is the most thorough and the most efficient per bug found, but it is the least representative of what a blind external attacker faces.
| Dimension | Black-box | Grey-box | White-box |
|---|---|---|---|
| Info provided | URL + creds | Creds + specs/diagram | Source + creds + docs |
| Realism (external attacker) | Highest | Medium | Lowest |
| Coverage per unit time | Lowest | Medium | Highest |
| Finds hidden/logic bugs | Hard | Medium | Easiest |
| Typical use | Bounty, red team | Standard web pentest | Assurance + code review |
A grey-box tip that saves days: always ask for an API definition file
(OpenAPI/Swagger, a Postman collection, or a GraphQL introspection schema).
Modern apps are mostly a thin front-end over an API, and the definition hands
you every endpoint, parameter and expected type — turning a blind fuzzing
exercise into a targeted one. If they won't give it, you may still be able to
pull it from the running app (a /swagger.json, /openapi.json, /graphql
introspection query), which is itself a WSTG-INFO finding if it was meant to be
private.
Part 7: Building the Web Tester's Toolkit — From Scratch
You can perform a competent web pentest with a browser, an intercepting proxy, a
content-discovery tool, and curl. Everything else is convenience. This section
teaches the core four from zero, per the tool-from-scratch rule — later chapters
go deep on each.
Burp Suite — the intercepting proxy
What it is and why it exists. Burp Suite (by PortSwigger) is the de-facto standard web-app testing platform. At its heart it is an intercepting proxy: it sits between your browser and the target so every HTTP request and response passes through it, where you can view, pause, modify and replay it. The entire premise of manual web testing is that the browser is a convenience, not a security boundary — the server only ever sees HTTP, so if you can see and edit the raw HTTP, you can send anything the browser would never let you (a negative quantity, another user's ID, a header the JavaScript stripped). Burp is how you get at that raw HTTP.
Editions. The Community Edition is free and sufficient to learn everything in this notebook — it has the proxy, Repeater, Decoder, Comparer, and a throttled Intruder. The Professional Edition (paid) adds the automated active scanner, unthrottled Intruder, and the BApp extension store. Learn on Community; know that Pro's scanner is a time-saver, not a substitute for the manual method.
Install on Kali. Burp ships with Kali:
# Burp Suite Community is pre-installed on Kali; launch it:
burpsuite &
# Or install/update explicitly:
sudo apt update && sudo apt install -y burpsuiteCore architecture — the tabs you will live in:
| Tab | Purpose |
|---|---|
| Proxy | Intercept, view and modify live traffic; the HTTP history log |
| Target / Site map | The tree of every host/path Burp has seen — your map of the app |
| Repeater | Send a single request over and over, editing it each time — the manual-testing workhorse |
| Intruder | Automate sending a request with payloads substituted into positions (fuzzing, brute force) |
| Decoder | Encode/decode URL, Base64, hex, HTML, etc. |
| Comparer | Diff two responses byte-by-byte (great for spotting subtle auth differences) |
| Sequencer | Statistically analyse randomness of session tokens |
Core workflow — get traffic flowing through Burp:
1. Start Burp -> use the pre-configured "Temporary project" (Community).
2. Proxy -> Options: default listener is 127.0.0.1:8080.
3. Use Burp's built-in browser (Proxy -> Intercept -> "Open browser") —
it is pre-configured to proxy through Burp and trust Burp's CA.
(Manual alternative: point your browser proxy at 127.0.0.1:8080 and
install Burp's CA cert from http://burp so HTTPS doesn't error.)
4. Browse the target normally; every request appears in Proxy -> HTTP history.
5. Right-click any request -> "Send to Repeater" to start manual testing.The single habit that turns Burp from a curiosity into a weapon: browse the whole app once with intercept off, so the site map and HTTP history fill up, then work from that history. You now have every request the app makes, ready to send to Repeater and mangle.
OWASP ZAP — the free, open-source alternative
What it is. OWASP ZAP (Zed Attack Proxy) is a free, open-source intercepting proxy and scanner maintained by OWASP — think "Burp, but fully free and open, with a built-in automated scanner". It is the tool of choice when you cannot afford Burp Pro's scanner, when you want to script/CI-integrate scanning (ZAP has a strong automation/API story), or on principle. Its concepts map onto Burp's: the Sites tree is Burp's site map, the Manual Request Editor is Repeater, the Fuzzer is Intruder, and the Automated Scan and Spider/AJAX Spider are Burp Pro's crawl+scan.
# ZAP on Kali:
sudo apt install -y zaproxy
zaproxy &You do not need both Burp and ZAP for one engagement — pick one intercepting proxy as your home base. This notebook demonstrates in Burp because it dominates the industry, but every technique is reproducible in ZAP.
ffuf — content and parameter discovery
What it is. ffuf ("Fuzz Faster U Fool") is a fast, Go-based web fuzzer.
Its one job is to send many requests, substituting a wordlist into a marked
position (FUZZ), and report the responses — used to discover hidden
directories and files, virtual hosts, parameters, and values. It is how you find
the /admin panel, the .git folder, the backup.zip, or the undocumented
debug=true parameter that the site map alone never revealed.
# Install (pre-installed on recent Kali; else):
sudo apt install -y ffuf # or: go install github.com/ffuf/ffuf/v2@latest
# Directory discovery: FUZZ marks where each wordlist entry is inserted
ffuf -u https://target.example.com/FUZZ \
-w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt \
-mc 200,204,301,302,307,401,403 \
-fs 0 -t 40Flag by flag: -u the target URL with the FUZZ keyword marking the insertion
point; -w the wordlist (SecLists' raft-medium-directories is a sane
default); -mc match only these HTTP status codes (200/204 = exists, 301/302
= redirect worth chasing, 401/403 = exists-but-protected, which is
interesting); -fs 0 filter out responses of size 0 (noise); -t 40 use 40
concurrent threads. You will meet ffuf in depth in Chapter 2 (mapping the
attack surface).
curl and the browser dev-tools — the always-available pair
curl is the universal HTTP client: no proxy, no GUI, scriptable, and
present on every box. When you want to send one precisely-controlled request and
read the exact response — headers and all — reach for curl:
# -i include response headers; -s silent; -k ignore TLS cert errors (lab only)
curl -i -s https://target.example.com/api/user/1 \
-H "Authorization: Bearer eyJhbGciOi..." \
-H "Accept: application/json"
# -X method, -d body, -b send cookies, --data-binary for exact bytes
curl -i -s -X POST https://target.example.com/login \
-d 'username=admin&password=admin' \
-H 'Content-Type: application/x-www-form-urlencoded'Flag by flag: -i include response headers in the output (you almost always
want to see Set-Cookie, Location, WWW-Authenticate); -s silent (no
progress meter); -k skip TLS verification — lab only, never a habit; -H
add a request header; -X set the method; -d send a URL-encoded body (implies
POST); -b send cookies. curl is invaluable for reproducing a finding in a
report — a one-line curl an engineer can paste is far better than "open Burp
and…".
Browser dev-tools (F12 in Chrome/Firefox) give you the client's view: the
Network tab shows every request the page made (including the XHR/fetch calls the
app fires in the background), the Console runs JavaScript in the page's origin
(essential for DOM-XSS and client-side testing), the Application/Storage tab
shows cookies, localStorage and sessionStorage, and the Debugger lets you
read the front-end source to find endpoints and client-side logic. The proxy
sees the wire; dev-tools see the DOM. You need both.
flowchart LR
B[Browser<br/>+ dev-tools] -->|HTTP| P[Burp / ZAP<br/>intercepting proxy]
P -->|HTTP| T[Target app]
C[curl<br/>scriptable client] -->|HTTP| T
F[ffuf<br/>content discovery] -->|HTTP x1000s| T
P --> R[Repeater / Intruder<br/>manual + fuzz]
Part 8: The Phased Web Pentest Workflow
Now assemble the pieces into the workflow you will run on every engagement. Each phase maps to WSTG categories and produces an output that feeds the next. The phases are ordered, but real testing loops — a finding in one phase sends you back to an earlier one.
Phase 0 — Setup. Confirm scope and ROE (Part 2), stand up your toolkit (Part 7), configure the proxy, load test accounts, and confirm you can reach the target from your authorised source IP. Take a baseline: what does an unauthenticated request to the root return? What server, what framework, what headers?
Phase 1 — Information Gathering (WSTG-INFO). Fingerprint the stack (server,
framework, language, CMS, WAF, CDN), enumerate entry points (every page, form,
parameter, API endpoint), discover hidden content with ffuf, read the
JavaScript for endpoints, pull any API spec. Output: a map of the application's
surface. This is Chapter 2's whole subject.
Phase 2 — Configuration & Deployment (WSTG-CONF). Test for the low-hanging
misconfigurations: exposed admin interfaces, backup/old files (.bak, ~,
.git/), permitted HTTP methods (OPTIONS, PUT, TRACE), missing security
headers (HSTS, CSP, X-Content-Type-Options), verbose error pages, default
credentials on any management interface, and cloud-metadata exposure. Much of
this overlaps the vuln-scan output you already have.
Phase 3 — Identity & Authentication (WSTG-IDNT, WSTG-ATHN). Enumerate roles and how accounts are provisioned; test username enumeration (does "unknown user" differ from "wrong password"?); test the login for default creds, weak lockout, credentials sent over an unencrypted channel, and weaknesses in the password-reset and "remember me" flows. Chapter 3 goes deep here.
Phase 4 — Session Management (WSTG-SESS). Inspect the session token: is it
in a cookie with Secure, HttpOnly, SameSite? Is it random (Sequencer)?
Test session fixation, absence of rotation on privilege change, logout that
doesn't actually invalidate, timeout, and CSRF on state-changing requests.
Phase 5 — Authorization (WSTG-ATHZ). The number-one risk. With two same-level accounts, test horizontal access control (can A read/modify B's objects — IDOR/BOLA?); with different-level accounts, test vertical (can a user hit admin functions directly?). Test directory traversal and forced browsing to protected resources. This requires the multiple accounts you asked for in Part 2.
Phase 6 — Input Validation (WSTG-INPV). The classic injection surface: reflected/stored/DOM XSS, SQL and NoSQL injection, command injection, LDAP/XML/XPath injection, SSTI, HTTP header/host-header injection, open redirects, file-upload abuse, insecure deserialization, and SSRF. This is the bulk of several later chapters.
Phase 7 — Client-Side (WSTG-CLNT). DOM-based XSS, JavaScript execution
sinks, clickjacking, insecure postMessage, CORS misconfiguration, client-side
storage of secrets, and third-party script risk. Tested with dev-tools and the
proxy together.
Phase 8 — Error Handling & Cryptography (WSTG-ERRH, WSTG-CRYP). Usually harvested while doing the above: note every stack trace, verbose error, and information leak; check TLS configuration (version, ciphers, cert), sensitive data sent or stored in the clear, and any home-rolled crypto.
Phase 9 — Business Logic (WSTG-BUSL). The hardest to automate and often the highest-impact: can you buy something for a negative price, skip the payment step, reuse a one-time coupon, race two requests to double-spend, or drive a workflow out of its intended order? Seeded directly by your Part 5 threat model.
Phase 10 — Validate, rate, report, retest. Prove every finding (Part 10), rate it (Part 11), write it up (Part 12), and re-test after the client fixes it.
stateDiagram-v2
[*] --> Setup
Setup --> InfoGathering
InfoGathering --> Configuration
Configuration --> IdentityAuthn
IdentityAuthn --> Session
Session --> Authorization
Authorization --> InputValidation
InputValidation --> ClientSide
ClientSide --> ErrorsCrypto
ErrorsCrypto --> BusinessLogic
BusinessLogic --> Report
Report --> Retest
Retest --> [*]
InputValidation --> Authorization: new access path found
BusinessLogic --> InputValidation: logic reveals injection
Part 9: Hands-On Lab — First Request to First Finding on OWASP Juice Shop
This lab walks the methodology end-to-end on a safe, legal target: OWASP Juice Shop, the deliberately vulnerable modern web app OWASP maintains for exactly this. Everything below runs on your own machine — a lawful target you fully control. The point is not to speed-run a specific bug; it is to feel the workflow: baseline, map, pick a WSTG test, execute, validate, and write it down.
Step 1 — Stand up the target
# Run Juice Shop locally with Docker (safest — isolated, disposable):
docker run --rm -d -p 3000:3000 --name juice bkimminich/juice-shop
# Confirm it's up:
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:3000
# Expected: 200docker run flags: --rm delete the container on exit (disposable lab); -d
detached (background); -p 3000:3000 map host port 3000 to container port 3000;
--name juice a friendly name so you can docker stop juice later. Browse to
http://localhost:3000 and you get a functional shopping app.
Step 2 — Baseline and fingerprint (WSTG-INFO)
Send the plainest possible request and read the response headers — the fingerprint is right there:
curl -i -s http://localhost:3000/ | head -n 20Realistic (abridged) output:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Feature-Policy: payment 'self'
Content-Type: text/html; charset=utf-8
Content-Length: 1987
ETag: W/"7c3-..."
Vary: Accept-Encoding
Date: ...
Connection: keep-alive
Keep-Alive: timeout=5Two immediate reads. Access-Control-Allow-Origin: * on the front page is a
CORS note to follow up in Phase 7. The absence of Strict-Transport-Security
and Content-Security-Policy are Configuration (WSTG-CONF) observations to
record. Already, before any "attack", the methodology has produced two leads and
a stack hint (the app is a single-page Angular front-end over a Node/Express API
— visible from the served bundle and the /api and /rest paths it calls).
Step 3 — Route everything through Burp and build the site map
Open Burp -> Proxy -> "Open browser", browse to http://localhost:3000, and
click around the whole app once: view products, register a user, log in, add to
basket, view your basket, open your profile. Now Burp's Target / Site map is
populated and Proxy / HTTP history holds every request — including the
background XHR calls to /rest/products/search, /api/Users,
/rest/basket/{id}, and so on that the browser fired invisibly. This is your
attack surface, and you found it by browsing, not guessing.
Step 4 — Discover hidden content with ffuf (WSTG-INFO / CONF)
The site map shows what the app told you about. Now find what it didn't:
ffuf -u http://localhost:3000/FUZZ \
-w /usr/share/seclists/Discovery/Web-Content/common.txt \
-mc 200,301,302,401,403 -t 40 -fs 0Abridged, realistic output:
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
:: Method : GET
:: URL : http://localhost:3000/FUZZ
:: Wordlist : FUZZ: common.txt
________________________________________________
ftp [Status: 200, Size: 11266, Words: 210, Lines: 42]
robots.txt [Status: 200, Size: 28, Words: 3, Lines: 2]
metrics [Status: 200, Size: 2843, Words: 141, Lines: 62]
video [Status: 200, Size: 30452, Words: 12, Lines: 41]
:: Progress: [4700/4700] :: Job [1/1] :: 0 req/sec :: Errors: 0 ::/ftp returning 200 is a genuine lead — an exposed file-serving path (a
WSTG-CONF / WSTG-ATHZ candidate for directory traversal). /metrics is an
exposed monitoring endpoint (information disclosure). robots.txt often names
paths the developers wanted hidden. Each of these becomes a test-plan item; none
appeared in the browser-built site map.
Step 5 — Pick a WSTG test and execute it in Repeater (WSTG-ATHZ / IDOR)
From the HTTP history, the basket is fetched via GET /rest/basket/{id}. That
numeric {id} is a direct object reference — a textbook IDOR / Broken Object
Level Authorization candidate (WSTG-ATHZ, OWASP A01). The methodology says:
with your own session, request your basket, note the id, then request the
neighbouring id and see whether access control stops you.
Right-click the /rest/basket/1 request -> Send to Repeater. In Repeater,
with your valid session cookie/token attached, change the id and resend:
GET /rest/basket/2 HTTP/1.1
Host: localhost:3000
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9... <- YOUR token
Accept: application/jsonIf the server returns basket 2's contents (a different user's basket) despite you authenticating as the owner of basket 1, access control is broken — you have read another user's data by changing a number, authenticated only as yourself. That is a confirmed IDOR. The exact response to record:
HTTP/1.1 200 OK
Content-Type: application/json
{"status":"success","data":{"id":2,"Products":[{"id":6,"name":"...",
"price":9.99,"BasketItem":{"quantity":2}}]}}Step 6 — Validate and capture evidence
One 200 is a hypothesis; validation makes it a finding. Confirm it is access
control, not just "the id happens to be public": show that (a) as user-1 you
can read basket-2, and (b) basket-2 belongs to a different account (log in as
your second test user, confirm their basket id is 2). Capture, for the report:
the exact request (method, path, headers with the token redacted), the exact
response, the two account contexts, and a one-line curl reproduction:
curl -s http://localhost:3000/rest/basket/2 \
-H "Authorization: Bearer <user1-token>" | jq .data.id
# -> 2 (user 1 reading user 2's basket = broken access control)Step 7 — Write the finding (preview of Part 12)
You now have a complete, defensible finding: title (IDOR: authenticated users can read arbitrary baskets via /rest/basket/{id}), WSTG ref (WSTG-ATHZ-04, Insecure Direct Object References), Top-10 ref (A01 Broken Access Control), evidence (the two requests/responses above), impact (any user can read any other user's basket contents — a confidentiality breach), and remediation (enforce that the authenticated principal owns the requested object server-side; do not trust the id from the client). That is the whole loop, in miniature — and it is exactly the loop you scale across every WSTG category on a real target.
Tear down the lab when done:
docker stop juice # container had --rm, so it's removed automaticallyBug-bounty & CTF connection: this exact /rest/basket/{id} pattern — a
numeric object reference with no server-side ownership check — is one of the
most-paid bug classes on HackerOne and Bugcrowd, and IDOR/BOLA is the number-one
category on the API Security Top 10. Juice Shop, PortSwigger's Web Security
Academy "Access control" labs, and HTB/THM web boxes drill it repeatedly; if you
can run this loop cleanly you have a reportable skill, not just a lab trick.
Part 10: Validation and Evidence — Turning Requests into Findings
The Vulnerability Assessment notebook's central lesson carries straight into web work: a response that looks like a bug is a hypothesis until you have proven it and captured evidence a sceptic can reproduce. Web-specific validation traps are worth calling out:
- Reflected input is not XSS. Seeing your string echoed in the response proves
reflection, not execution. Prove XSS by demonstrating the payload runs (an
alert/promptfiring, a benign DOM change, or better, reading a cookie into a controlled sink) — and note the context (HTML body, attribute, JS string, URL) because that determines exploitability. - A 500 error is not SQL injection. An error on a quote proves the input
reaches something fragile; prove injection by controlling the query's logic (a
boolean-based
' OR 1=1-- -changing results, or a provable time delay) — minimally, never by dumping the database in a live engagement. - A redirect to your URL is not full open-redirect impact. Confirm the
redirect actually happens (follow the
Location) and assess whether it can be weaponised (phishing, OAuth token theft) rather than reporting the raw reflection. - Backported/patched frameworks. A version banner can mislead exactly as it did with OS packages; confirm the behaviour, not the version string.
Evidence package per finding: the exact request (raw HTTP, secrets
redacted), the exact response (or the relevant excerpt), the account/role
context, a minimal reproduction (a curl line or numbered Repeater steps), a
screenshot where the visual is the proof (a fired XSS, an admin page reached
as a normal user), and a note of whether it was found WAF-on or allowlisted.
Store any data you accessed per the ROE's data-handling clause and never retain
real user data beyond what proves the point.
Part 11: Rating Severity — CVSS in Context
A finding without a severity is hard to prioritise, and a severity without context misleads. The industry standard is CVSS (the Vulnerability Assessment notebook covered the metric model); for web findings the discipline is to compute an honest base score and then adjust for this environment.
Score the base metrics from the vulnerability's intrinsics: Attack Vector (web bugs are almost always Network), Attack Complexity, Privileges Required (none for a pre-auth bug, low for an authenticated-user bug), User Interaction (a stored XSS that fires for any viewer is None; a reflected XSS needing a click is Required), and the Confidentiality/Integrity/Availability impacts with Scope (does the bug break out of the vulnerable component — e.g. SSRF reaching internal systems, or XSS in one tenant affecting another?). Then apply environmental metrics: a self-XSS on a throwaway field in a marketing site is not the same risk as a stored XSS in an admin dashboard of a banking app even at the same base score.
| Example web finding | Typical CVSS base band | Why |
|---|---|---|
| Stored XSS in admin view, no interaction | High–Critical | Runs in a privileged context, no click needed |
| IDOR reading other users' PII | High | Confidentiality breach at scale, low privilege |
| Pre-auth SQL injection | Critical | Network, no privileges, full data/integrity impact |
| Reflected XSS needing a crafted link | Medium | Requires user interaction |
| Missing HSTS header | Low | Real but contingent (needs MITM position) |
| Verbose stack trace / version disclosure | Info–Low | Aids an attacker; not directly exploitable |
Two rules keep severity honest. First, rate the demonstrated impact, not the theoretical worst case — if you proved read-only IDOR, rate read-only IDOR and note the potential for more; don't inflate to "could delete everything" without showing it. Second, let the client's context move the number — the same bug is graver on a payment app than a status blog, and your environmental adjustment (and a sentence explaining it) is what makes the rating credible.
Part 12: The Report and the Retest
The report is the deliverable — the app is fixed from the report, not from your Burp history. A professional web pentest report has a predictable structure, and predictability is a feature: the reader knows where to look.
Structure:
- Executive summary — one page, non-technical: what was tested, the overall risk posture, the count of findings by severity, and the two or three things leadership must care about. Group the narrative by OWASP Top 10 category here, because that is the vocabulary management already knows.
- Scope & methodology — exactly what was in scope, when, from where, in which mode (black/grey/white, WAF-on/allowlisted), and a statement that testing followed the OWASP WSTG (cite the version). This is where citing WSTG makes your coverage auditable.
- Findings — one entry per distinct issue, each with: title, severity + CVSS vector, affected endpoint(s), WSTG and Top-10 references, description, step-by-step reproduction, evidence (request/response, screenshot), impact, and specific remediation. De-duplicate: the same root cause in ten endpoints is one finding with ten instances, not ten findings.
- Appendices — full request/response logs, tooling and versions, out-of-scope observations, and an informational list of things checked and not found (which demonstrates coverage and is quietly reassuring).
Remediation advice must be specific and actionable. "Validate input" is
useless. "Enforce server-side that the authenticated principal owns the
requested basketId before returning it; return 403 otherwise" is a fix a
developer can implement and you can retest.
The retest closes the loop: after the client remediates, you re-run the exact reproduction steps for each finding and record it as fixed, partially fixed, or still present. A finding is not "closed" because a ticket was marked done — it is closed because you re-sent the request and the bug is gone. Retest scope should be the findings, not a whole fresh assessment, unless the fix was a large refactor that plausibly introduced new issues.
Part 13: Detection & Defense Angle
Everything above is the offense-with-permission view. The blue-team counterpart matters both because you will often be asked to comment on detectability, and because understanding detection makes you a quieter, more realistic tester. This is the one consolidated defensive section (per the notebook's style); offensive/defensive notes elsewhere were woven inline.
What a web pentest looks like from the defender's logs. Content-discovery
fuzzing (ffuf) is loud: hundreds-to-thousands of requests to non-existent
paths, producing a spike of 404s (and telltale 403/401 on the paths that
do exist) from one source in seconds. IDOR testing shows as a single
authenticated session requesting object ids it has never requested before, often
sequentially. Injection testing shows as suspicious metacharacters (', <,
../, ${, ;) in parameters and as 500s clustering on specific endpoints.
A defender with decent logging sees all of this.
Controls that catch or blunt each phase:
| Phase / attack | Detection signal | Preventive control |
|---|---|---|
| Content discovery (ffuf) | Burst of 404s from one IP; unusual UA | Rate limiting; WAF; alert on 404 spikes |
| Auth brute force | Many failed logins per account/IP | Lockout, throttling, MFA, credential-stuffing detection |
| IDOR / BOLA | Session accessing objects it doesn't own | Server-side object-ownership checks; anomaly detection |
| Injection (SQLi/XSS) | Metacharacters in params; 500 spikes | Parameterised queries, output encoding, WAF, CSP |
| SSRF | App making outbound requests to internal IPs | Egress filtering, allowlists, metadata-endpoint blocks |
| Session attacks | Token reuse across IPs; no rotation | Secure/HttpOnly/SameSite cookies, rotation, short TTL |
Logging & monitoring is itself a Top-10 category (A09). During a pentest you can — and in a purple-team engagement, should — check whether the app even records the attacks you launched. A frequent, quietly serious finding is that a critical action (admin login, password change, bulk export) produces no audit log at all: the organisation could be breached and never know. Report the absence of logging as a finding in its own right.
The purple-team framing. The most value a web pentest delivers is not the list of bugs — it is the shared understanding it creates. Walk the defenders through which of your actions they did and did not see, tune their detections against your recorded requests, and the organisation comes out with both fewer bugs and better eyes. That is why your authorised source IP and test window (Part 2) matter: they let the blue team correlate "was that spike us being tested, or a real attack?" — a distinction that is otherwise agonising during the engagement.
Part 14: Common Mistakes and How to Avoid Them
- Skipping the map and diving into payloads. Firing XSS at the first form you see, before you've enumerated the app, guarantees missed surface. Map first (Phase 1), then test. The bug you never find is on the endpoint you never discovered.
- Testing authorization with one account. You cannot find IDOR or privilege escalation with a single user. Insist on two accounts per role at scoping time.
- Reporting reflection as XSS / errors as injection. Validate execution/logic control, not mere echoes or 500s (Part 10). Unvalidated findings destroy report credibility.
- Testing only through the WAF, or only allowlisted. Each alone gives a distorted picture. Do coverage allowlisted, then confirm key findings WAF-on, and state which for each finding.
- Straying out of scope via redirects and third parties. An OAuth provider, CDN or payment host appearing in traffic is not an invitation to test it. Re-read Part 2 before every "interesting" out-of-origin lead.
- Confusing the Top 10 with a methodology. "We tested the OWASP Top 10" is not a coverage claim. Test against the WSTG; report against the Top 10.
- No baseline, no evidence. If you can't reproduce a finding with a clean
curlor numbered steps, you don't have a finding yet — you have a memory. - Triggering destructive actions on real data. Prove "delete" against your own second test account, never a real user's. Re-read the ROE's destructive-action clause.
- Padding the report with scanner output. Ten unvalidated Nikto "interesting file" lines are not ten findings. De-duplicate, validate, and rate honestly.
Part 15: Final Revision / Summary
- A web application pentest is a scoped, authorised, time-boxed assessment aiming for coverage of the whole app against a methodology, distinct from bug bounty (impact-driven), vuln scanning (hypotheses), and code review (source-based). All four are complementary.
- Authorisation and scope are hard legal boundaries. A web scope is a list of exact origins and paths; third-party origins that appear in traffic (OAuth, CDN, payment) are out of scope unless named. Get two accounts per role or you cannot test access control at all.
- The OWASP WSTG (v4.2) is the canonical methodology: hundreds of test cases
in twelve categories, each with a
WSTG-CAT-NNidentifier. Cite these IDs in reports so coverage is auditable. - The OWASP Top 10 (2021) is an awareness/risk list, not a test plan. Broken Access Control (A01) leads because it is common, damaging, and hard for scanners to find. Use the Top 10 to communicate and prioritise; use the WSTG to test.
- Threat-model first: actors, assets, trust boundaries, intended workflows. That model seeds your test plan — boundaries to injection/authz tests, workflows to business-logic tests.
- Choose an engagement model: grey-box is the pragmatic default; ask for credentials at every role and an API spec.
- Core toolkit from scratch: an intercepting proxy (Burp or ZAP) as home base, ffuf for content discovery, curl for precise reproducible requests, and browser dev-tools for the client view. Browse the app once with intercept off to build the map, then work from history.
- The phased workflow (setup, info, config, identity/authn, session, authz, input validation, client-side, errors/crypto, business logic, validate/rate/report/retest) maps one-to-one onto the WSTG categories.
- Validate every finding (execution/logic control, not echoes/500s), rate with CVSS in context, and deliver a structured report grouped by Top 10 with per-finding WSTG references and specific remediation — then retest by re-running the exact steps.
Part 16: Cheat Sheet / Quick Reference
WSTG category codes: INFO (info gathering) · CONF (configuration) · IDNT (identity) · ATHN (authentication) · ATHZ (authorization) · SESS (session) · INPV (input validation) · ERRH (error handling) · CRYP (cryptography) · BUSL (business logic) · CLNT (client-side) · APIT (API).
OWASP Top 10 2021: A01 Broken Access Control · A02 Cryptographic Failures · A03 Injection · A04 Insecure Design · A05 Security Misconfiguration · A06 Vulnerable & Outdated Components · A07 Identification & Authentication Failures · A08 Software & Data Integrity Failures · A09 Security Logging & Monitoring Failures · A10 SSRF.
# --- Recon / baseline ---
curl -i -s https://TARGET/ | head -n 30 # headers = fingerprint
curl -s https://TARGET/robots.txt # hinted-hidden paths
curl -s https://TARGET/openapi.json | jq keys # grab an API spec if exposed
# --- Content discovery ---
ffuf -u https://TARGET/FUZZ \
-w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt \
-mc 200,204,301,302,401,403 -fs 0 -t 40
# -mc match codes | -fs filter size | -t threads | FUZZ = insertion point
# --- Parameter discovery ---
ffuf -u 'https://TARGET/page?FUZZ=test' \
-w /usr/share/seclists/Discovery/Web-Content/burp-parameter-names.txt \
-mc 200 -fs <baseline-size>
# --- Precise reproducible request (for the report) ---
curl -i -s -X POST https://TARGET/login \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'username=admin&password=admin'
# --- IDOR check (two ids, same session) ---
curl -s https://TARGET/api/object/1 -H "Authorization: Bearer $TOK"
curl -s https://TARGET/api/object/2 -H "Authorization: Bearer $TOK" # can you read it?Burp muscle memory: Proxy -> "Open browser"; browse whole app intercept-off; work from HTTP history; right-click -> Send to Repeater for manual testing; Send to Intruder for fuzzing; Comparer to diff auth responses; Sequencer for token randomness.
Per-finding evidence checklist: exact request (secrets redacted) · exact
response/excerpt · role/account context · minimal curl/numbered repro ·
screenshot if the visual is the proof · WAF-on vs allowlisted · WSTG + Top-10
references · CVSS vector · specific remediation.
Part 17: Practice Labs & Resources
Run the whole method end-to-end:
- OWASP Juice Shop (
bkimminich/juice-shop) — the target used in this chapter's lab; a full modern SPA+API with bugs across every WSTG category and a built-in scoreboard. The ideal first sandbox for practising the workflow. - OWASP WebGoat — lesson-structured, walks you through vulnerability classes one at a time; good for learning what each WSTG test is actually probing.
- PortSwigger Web Security Academy (free) — the canonical, topic-organised labs from the makers of Burp. Start with the "Access control" and "Information disclosure" tracks to reinforce this chapter, then follow the notebook's later chapters into XSS, SQLi, and SSRF tracks. Each lab maps cleanly onto a WSTG test.
- HackTheBox / TryHackMe web tracks — THM's "Web Fundamentals" and "OWASP Top 10" rooms and HTB's easy web boxes let you practise mapping and access-control testing on varied stacks.
Reference documents to keep open while testing:
- OWASP Web Security Testing Guide v4.2 — your checklist; keep the category
index open and tick off
WSTG-xxxIDs as you cover them. - OWASP Top 10 (2021) and OWASP API Security Top 10 (2023) — for grouping and communicating risk, and for API-heavy targets.
- OWASP Application Security Verification Standard (ASVS) — when the engagement is a verification against a security standard rather than an open hunt, ASVS gives you leveled requirements to test against.
- Disclosed reports on HackerOne / Bugcrowd — reading real disclosed IDOR, access-control and injection reports teaches you what a well-written, well-evidenced finding looks like — exactly the standard Part 12 asks you to hit.
Practice tasks to cement this chapter:
- On Juice Shop, produce a one-page threat model (actors, assets, trust boundaries, three high-value workflows) before testing, then check which of your later findings you predicted.
- Map the app two ways — by browsing through Burp, and with
ffuf— and list three endpoints that only theffufpass revealed. - Take the IDOR from the lab and write it up as a full report finding (title, CVSS vector, WSTG + Top-10 refs, repro, impact, remediation) to Part 12's structure.
- Re-run one finding with a simple WAF (e.g. ModSecurity CRS in front of the app) and document how the detection signal and exploitability change — the Part 13 blue-team view from the offense side.
- Draft a WSTG coverage matrix: list the twelve categories and, for each, name the one test you would run first on a login-plus-dashboard app.