Web Security Testing in Practice

Web security testing in practice is a repeatable, authorised check of a running web application, done inside a written scope and in a fixed order: observe what the site already sends, probe its configuration with ordinary requests, triage the dependency scan of the build, scan where the scope allows, add manual tests from the OWASP Web Security Testing Guide (WSTG), and finish with a private report.

Before a bookshop release, for example, a tester walks staging through the intercepting proxy and returns with four leads: a stack trace on a malformed order id, a directory listing under /static/, and two dependency alerts, one rated 9.8 Critical. Each lead is verified, mapped to an OWASP Top 10:2025 category and filed privately, and the 9.8 alert turns out not to affect the product.

Why it matters

Careful code is easily undone by how it is deployed and what it is built from. A debug page left on, a default admin account or an old library with a published vulnerability opens a door without a single coding mistake in the feature you tested. Both are OWASP Top 10:2025 categories, Security Misconfiguration (A02:2025) and Software Supply Chain Failures (A03:2025), and both are easy to find with the automated tools that attackers point at public sites.

For the tester, the workflow makes the work safe and defensible: scope, environment, test accounts and the reporting channel are agreed before the first request, and afterwards you can show what was tested, how, and what was deliberately left out.

The workflow: seven steps in a fixed order

Permission comes before any request, low-impact checks before active ones, verification before reporting. The OWASP WSTG is the checklist behind the steps: tests grouped by area, each with an identifier such as WSTG-CONF-06, objectives and remediation advice. Pick the areas that fit the product's risks, mark each test done, not applicable or finding, and quote the identifier in the report.

Route a dedicated test browser through the intercepting proxy as set up in the lesson on intercepting proxies: its history becomes the map, its passive scanner flags missing headers and cookie attributes, and its scope setting keeps every request inside the authorisation.

  • 1. Scope and permission: hosts, test window, excluded actions, an emergency contact and the channel for findings, in writing.
  • 2. Map through the proxy: pages, roles, API endpoints, uploads, third-party scripts; a test account per role.
  • 3. Passive pass: HTTPS redirect, HSTS, TLS 1.2 or 1.3, security headers and cookie attributes on every page type.
  • 4. Configuration probes: default accounts, debug output, errors, directory listing, HTTP methods, admin paths.
  • 5. Components: triage the dependency scan and the SBOM of the build under test.
  • 6. Scanner and manual tests: an active DAST scan, which can create records and send e-mails, only where the scope allows; manual WSTG tests for access control, business logic and CSRF, which scanners cannot judge reliably.
  • 7. Verify, map, report, retest: reproduce each lead by hand, name its Top 10 category, file it privately, retest after the fix.
A web security check in seven steps: written permission, a map through the proxy, passive checks, configuration probes, component triage, a scoped scan with manual tests, and a verified private report.
  1. 1Scope and permissionHosts, test window, exclusions, emergency contact, channel for findings

    Gate: only with written permission

  2. 2Map through the proxyPages, roles, API endpoints, uploads, third-party scripts
  3. 3Passive passA04:2025 and A02:2025HTTPS and HSTS, TLS 1.2 or 1.3, headers and cookie attributes per page type
  4. 4Configuration probesA02:2025 and A10:2025Default accounts, debug, errors, directory listing, methods, admin paths
  5. 5ComponentsA03:2025SCA alerts: CVE, CVSS vector, SBOM of the build, four triage questions
  6. 6Scanner and manual testsActive scan only where the scope allows; WSTG tests for access control and logic

    Gate: every result is a lead until reproduced

  7. 7Verify, map and reportReproduce by hand, name the Top 10 category, file privately, redact evidence

    Repeats: retest after each fix

Throughout steps 3–5 Low impact: ordinary requests and reading results

Then:Again before major releases and after infrastructure changes

Try it: Redirect Checker Try it: Security Header Analyzer Try it: Cookie Analyzer

Security misconfiguration and failing safely

A misconfiguration is a weakness in how software is set up, not how it is coded: a framework default, a feature nobody switched off, a setting copied from development. Each check is an ordinary request and a careful reading of the response.

Failing safely is the other half. A10:2025 Mishandling of Exceptional Conditions covers unhandled exceptions, checks that fail open (access granted because the permission service timed out) and operations left half-done. Provoke the condition safely, with a malformed value or a dependency stub that times out on the test environment, and check that the request is refused, the message is generic and no partial record remains.

  • Default accounts (WSTG-ATHN-02): try only the vendor's documented defaults on each console the map found, a few attempts at most. Expected: rejected.
  • Debug modes: debug pages and toolbars, source maps, test-only endpoints. Confirm on the release candidate that the release configuration switches them off.
  • Stack traces and verbose errors (WSTG-ERRH-01): send a wrong type (/api/orders/abc), a missing field, an over-long value. Expected: a 4xx status and a short message with a reference id; no stack trace, SQL, file paths or versions.
  • Directory listing: request folders such as /static/. Expected: 403 or 404, not an "Index of" page.
  • HTTP methods (WSTG-CONF-06): send OPTIONS and read Allow; TRACE should be refused and unneeded methods should get 405. Try PUT or DELETE only on a record you created.
  • Admin and diagnostic endpoints (WSTG-CONF-05): consoles and detailed health, metrics or status pages must not answer from the internet without an admin login.
  • Security headers: recorded in the passive pass; they often go missing on error pages, redirects and API responses.

Try it: API Request Builder

Vulnerable and supply-chain components: SCA, CVE, CVSS and SBOM

Many components of a web application arrive indirectly, through other components. A03:2025 Software Supply Chain Failures covers known-vulnerable, unmaintained, untracked or compromised components and build steps. The scan usually runs in the pipeline; the tester reads it, triages it with a developer and brings it to the release decision.

Triage each alert with four questions. Is the vulnerable version in the shipped build, or only in a development dependency? Is the vulnerable code reached the way the product uses the component? Is a fix available, and what does it change? Is the vulnerability known to be exploited (the advisory, or a public list such as CISA's Known Exploited Vulnerabilities catalog, says so)? The outcomes: fix now, fix in a planned release, not affected with the reason recorded, or false positive. Accepting a risk is the security or product owner's call.

  • SCA (software composition analysis) reads the dependency files (for example package.json and its lock file package-lock.json, or a Maven pom.xml), lists every direct and transitive dependency with its version and matches them against published advisories.
  • A CVE ID (CVE-<year>-<number>) names one publicly disclosed vulnerability; it links the advisory, the scanner and the fix, and lets you merge duplicates.
  • CVSS, the Common Vulnerability Scoring System maintained by FIRST, gives a base score from 0.0 to 10.0: None 0.0, Low 0.1–3.9, Medium 4.0–6.9, High 7.0–8.9, Critical 9.0–10.0. The vector says why: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H (9.8) means a network attack, low complexity, no privileges, no user action, and high impact on confidentiality, integrity and availability. Check the version prefix (3.1 or 4.0) before comparing scores.
  • CVSS calls these bands severity ratings, but the base score rates the vulnerability in general, not in your product: it is an input to the severity of your defect report, not that severity.
  • An SBOM (software bill of materials) lists the components of one build with versions, suppliers and dependency relations, in a standard format such as SPDX or CycloneDX, so "are we affected?" becomes a search.

Try it: JSON Tree Viewer Try it: JSON Diff

Mapping findings to the OWASP Top 10:2025

Each report entry names the WSTG test (how it was checked) and the Top 10 category with its year (what kind of risk it is). When a finding fits two categories, choose the root cause: a debug page left on is A02, a stack trace from an unhandled exception is A10.

  • A02:2025 Security Misconfiguration: default accounts, debug modes, verbose error settings, directory listing, unneeded methods, exposed admin or diagnostic endpoints, missing headers and cookie attributes.
  • A10:2025 Mishandling of Exceptional Conditions: leaked stack traces, fail-open checks, half-done operations.
  • A03:2025 Software Supply Chain Failures: vulnerable, unmaintained or untracked components and build tools.
  • A04:2025 Cryptographic Failures: plain HTTP, outdated TLS.
  • A01:2025 Broken Access Control: an admin endpoint that answers without the right role; findings from the manual role tests.
  • A08:2025 Software or Data Integrity Failures: scripts from an untrusted CDN without an integrity check, unverified updates.

Worked example: triage and report a scanner finding

A security report is a map for an attacker. File it only in the channel the scope names, usually a restricted tracker project, never a public issue or a team chat. Redact session identifiers, tokens, passwords and personal data, and prove only as far as needed: one response that shows another user's e-mail address is proof; downloading the table is an incident.

On the bookshop check, the dependency scan of build 412 raised two alerts; the developer and the tester checked both against the SBOM of the build. The names and the advisory ID are invented.

  • The other alert, a test-runner library rated 9.8 Critical, was recorded as not affected: a development dependency absent from the shipped SBOM. Its upgrade was still scheduled, because it runs on CI machines that hold secrets.
  • The 8.8 alert became the finding because the vulnerable version ships and any logged-in user reaches it: presence and reachability decided, not the score. The proposed severity is Critical on the team's scale, not the CVSS band High, because per the advisory any logged-in user could run code on the image service.
  • Retest on build 413: rescan and confirm the fixed version in its SBOM before closing. A flaw in the component itself goes to its maintainer through the published security contact, never a public issue.
Finding WS-05  Vulnerable image library in avatar upload   Severity: Critical (proposed)
Category:  A03:2025 Software Supply Chain Failures
Source:    dependency scan (SCA), build 412
Component: acme-img-resize 3.2.0, transitive via avatar-service 1.4.2, runtime
Advisory:  CVE-YYYY-NNNNN  CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H  8.8 High
Fixed in:  acme-img-resize 3.2.4 (per the advisory)
Triage:    in the SBOM of build 412; reached on every avatar upload, which any
           logged-in user can make. No exploit attempted.
Impact:    per the advisory, a crafted image can run code on the image service.
Fix:       upgrade avatar-service, or pin acme-img-resize >= 3.2.4; rescan.
Evidence:  scan report and SBOM excerpt attached; no tokens or user data in them.
Status:    filed as SEC-231 (restricted security project); retest on build 413.

Common mistakes

  • Starting before the written scope exists, or stepping beyond it for "just one more request".
  • Running an active scan or trying default credentials on production or a shared environment.
  • Treating the CVSS base score as the severity: a 9.8 in a development-only dependency may not touch the product; a 6.5 on the login path may.
  • Filing scanner and SCA output unverified: duplicates, false positives, lost credibility.
  • Checking headers and errors only on the home page; error, admin and API responses are configured separately.
  • Reporting through public channels or with unredacted evidence, or proving a finding further than needed.

The QA perspective

The full workflow runs on staging before major releases and after infrastructure changes (a new load balancer, CDN or framework version), which alter headers, TLS and error pages without touching application code. The cheap parts run constantly: the dependency scan as a pipeline quality gate on every build, and a header check in the non-functional stage.

Agree the scope with the security and product owners, triage alerts with the developer who owns the component, and let the security team confirm severities. Keep the scope, the proxy or scanner log, the SBOM of the tested build, the evidence and the report together. Ask before you start: which environment and build, what is excluded, which test accounts, who receives findings, and how open Critical and High alerts affect the release.

Practice exercise

Triage the leads from a clinic staging check

Your task

You have written permission to test https://staging.clinic.example for three days; production, the payment page and active scanning are excluded. The material lists six leads (component names and advisory IDs are invented).

For each lead decide: finding or not, how to verify it safely, its WSTG test where one applies and its Top 10:2025 category, a proposed severity with a reason, and the fix. Then decide what to redact and which finding cannot wait.

Material
Scope:    https://staging.clinic.example, 3 days
Excluded: production, the payment page, active scanning

1  OPTIONS /api/appointments       -> 200  Allow: GET, POST, PUT, DELETE, TRACE
2  GET /api/appointments/abc       -> 500  java.lang.NumberFormatException:
                                           For input string: "abc" at com.clinic.api...
3  GET /static/reports/ (no login) -> 200  "Index of /static/reports", 3 PDF files
4  GET /login                      -> 200  no Content-Security-Policy;
                                           X-Frame-Options: DENY
5  SCA build 88  acme-pdfgen 1.9.0  runtime  CVE-YYYY-11111  7.5 High      fix: 1.9.3
6  SCA build 88  acme-mocker 0.8.1  dev      CVE-YYYY-22222  9.8 Critical  fix: 0.9.0
Steps
  1. Mark each lead: finding to verify, not affected, or question for the team.
  2. Write how you would verify each one without changing or downloading real data.
  3. Triage the two SCA alerts with the four questions.
  4. Write the report decisions: category, severity, fix, redaction, channel.
Show the model answer
Model answer

Lead 3 cannot wait: an unauthenticated listing of what look like clinic reports. Record the page and the file names only, open nothing, ask the developers whether the files load without login, and tell the emergency contact the same day. A02:2025, plus A01:2025 if the files load without login; no single WSTG test covers listings, so record it under configuration testing (WSTG-CONF). Proposed severity: Critical if they hold patient data. Fix: switch off the listing and serve reports only through an authorised endpoint.

Lead 2: A10:2025 and WSTG-ERRH-01; an unchecked id leaks a stack trace with internal class names. Major: it reveals internals on an endpoint with patient data. Fix: validate the id, return 400 with a generic message and a reference id, keep the trace in the server log.

Lead 1: WSTG-CONF-06 and A02:2025. Verify TRACE with one harmless request; PUT and DELETE may be legitimate for rescheduling and cancelling, so check the API contract and use only your own appointment. Minor; fix: disable TRACE. Lead 4: a passive-pass result, A02:2025. Framing is already blocked by X-Frame-Options: DENY, and a missing CSP removes a layer of protection against XSS rather than being exploitable on its own. Minor (hardening); fix: add a Content-Security-Policy.

Leads 5 and 6 come from the dependency scan, not a WSTG test. Lead 5 is a runtime dependency: check the shipped SBOM, ask whether report generation calls the vulnerable function, note that a fix exists (1.9.3) and check whether the vulnerability is known to be exploited, which would make it urgent. Shipped and reached: an A03:2025 finding, Critical or Major depending on the impact the advisory describes, not on its 7.5 High band; fix: upgrade to 1.9.3 and rescan. Not reached: not affected, with the reason recorded. Lead 6 is marked dev: confirm it is absent from the shipped SBOM, record it as not affected with the reason, and let the team schedule the upgrade for the CI machines.

Redact session cookies, the test account's password and any patient names in file names or screenshots; file everything in the restricted project, and send lead 3 to the emergency contact first.

Frequently asked questions

Is running a DAST scanner the same as a penetration test?

No. A scanner automates known patterns and produces leads that still need verification. A penetration test is a human-led, goal-driven engagement that chains findings together and tests the authorization and business logic a scanner cannot judge. Scanner results are an input to a penetration test, not a replacement for it.

The scanner reports a Critical CVE scored 9.8. Do we have to stop the release?

Not automatically. The base score rates the vulnerability in general. What decides is whether the vulnerable version ships, whether its code is reached, whether a fix exists and whether the vulnerability is known to be exploited. Your job is to bring those facts; the release decision follows the team's policy and belongs to the security and product owners.

What is the difference between an SBOM and an SCA report?

An SBOM is the inventory of one build: what is in it. An SCA report matches that inventory against vulnerability advisories at one point in time: what is known to be wrong today. When a new CVE is published next month, the SBOM of each released build tells you at once which builds contain the component.

What if I notice a vulnerability by accident on a site I do not own?

Stop probing, even "to be sure". Look for the site's security contact, such as a security.txt file or a published vulnerability disclosure policy, tell them only what you saw, and publish nothing. Testing without permission can be a criminal offence, whatever your intention.

References

Practise with Mutqan tools

Grade HTTP security headers (CSP, HSTS, X-Frame-Options, Referrer-Policy, Permissions-Policy, COOP/CORP) from pasted headers or a public URL.

Validation

Parse Set-Cookie headers and check Secure, HttpOnly, SameSite, Domain, Path, expiry and size best practices.

Validation

Trace redirect chains (301/302/307/308) and see every hop, status and final URL.

Web

Compose and send HTTP requests (method, URL, headers, auth, body) and inspect the response — a lightweight Postman in your browser.

API Testing

Explore JSON as a collapsible tree with paths, types and value counts.

JSON & Data

Compare two JSON documents semantically and highlight added, removed and changed values.

JSON & Data

Go deeper

Your progress on this topic

Part of the QA Roadmap