DAST — Architecture
DAST is the active testing module: it sends real payloads (fuzzing and injection-class checks) to find vulnerabilities — SQLi, XSS, RCE, SSRF, SSTI — that only surface when an app is actually probed. It tests only the web apps EASM discovered, and it rides the same shared engine for normalization and finalization. For the shared engine see Platform Architecture.
The DAST pipeline
Code:
app/engine/runner.py(DAST_PIPELINE),app/scanners/dast/*(katana, waybackurls, the two Nuclei stages),app/scanners/manifests.py(DAST_NUCLEI,DAST_NUCLEI_CVE).
| Stage | Scanner | What it does |
|---|---|---|
| Crawl (active) | katana | Crawl each discovered app into endpoint/parameterized URLs — bounded (see Guardrails). |
| Crawl (passive) | waybackurls | Add historical URLs for the same hosts (no requests to the target). |
| Fuzz | nuclei (-dast) | Blind fuzzing templates (dast/, http/fuzzing/) over the URL set. |
| Inject | nuclei (CVE) | The payload-based injection-class CVE/vuln templates (the intrusive set EASM excludes). |
Active vs. non-intrusive
DAST runs exactly the templates EASM leaves out — the INTRUSIVE_TAGS set
(sqli, xss, rce, ssrf, ssti, traversal, command-injection, …). Where EASM infers a
CVE from a version banner, DAST confirms exploitability by sending the payload.
That's why it's gated and bounded (see Guardrails & Access).
Gating
DAST consumes InputKind.DAST_TARGETS — the surface EASM promoted (the web
apps it discovered). With no surface there is nothing to test, so the API blocks
the scan (409). EASM feeds the surface but never runs DAST; a human
triggers it. Output normalizes into the shared model with module = "dast".