Lesson 8 of 9 · 20m
DAST: Attacking the Running App
SAST reads the recipe; DAST tastes the soup — it finds the findings that only exist because the app runs, if you can get it authenticated and pointed at the right target.
Static analysis will never tell you that your session cookie lacks Secure, that /api/admin/users answers without auth in staging because someone disabled middleware for a demo, or that a reflected XSS only exists when three services assemble the page. Dynamic testing finds what exists because the app runs — and it needs a running app to do it.
What DAST is and isn't
A DAST scanner (OWASP ZAP for the general case, Nuclei for templated checks) is a robot attacker pointed at a URL: it spiders the site, pokes parameters, injects probes, and reports what the server actually did. It needs no source code and speaks every language — which also means it knows nothing about intent. Expect it to find:
- Missing or misconfigured security headers, cookies, and TLS settings.
- Reflected/stored XSS and injection that survives to the response.
- Auth and session misconfiguration — if the scanner can get logged in.
- Known-CVE exposures via Nuclei templates:
nuclei -u https://staging.acme.internal.
It won't find business-logic flaws, and coverage is only as deep as the crawl — an endpoint the spider never discovers is a page it never tests.
The ZAP baseline vs the full scan
# baseline: passive checks + light active probing — minutes, safe to schedule
docker run -v "$(pwd):/zap/wrk" -t zaproxy/zap-stable zap-baseline.py -t https://staging.acme.internal -r zap-baseline.html
# full scan: active attacks, hours, staging only
docker run -v "$(pwd):/zap/wrk" -t zaproxy/zap-stable zap-full-scan.py -t https://staging.acme.internal -r zap-full.htmlThe distinction matters. A baseline is polite enough to run nightly against staging; a full active scan creates garbage data, fires alerts, and trips WAFs — run it deliberately, in an environment built for it.
Authentication is the whole ballgame
An unauthenticated DAST run against a logged-in app scans exactly the login page. Real coverage needs a context: a recorded login flow or scripted auth (form auth plus a verification URL, or an API token header), plus session handling that survives expiry. For APIs, skip the crawler entirely and feed ZAP the OpenAPI spec — zap-api-scan.py -t openapi.yaml -f openapi — and suddenly it knows every endpoint.
Where it fits in the pipeline
Nightly or weekly against stable staging or ephemeral review environments — not a PR gate. It's too slow, too flaky, and too prone to re-finding the same thing. Output lands in the same findings queue as everything else, triaged like a finding rather than a build failure.
Field notes
- Flakiness is the enemy of credibility: seed deterministic data, mark destructive endpoints out of scope, handle auth expiry in config — a scan that fails silently reports nothing and nobody notices.
- Filter Nuclei templates to your stack (
-tags); running all 8,000 gets you a CVE dump, not signal. - DAST on production is a different discipline — passive only, rate-limited, agreed with ops. Don't learn that the hard way.