Skip to content

av dast scan

Scan a running web application or API and tier every finding RED YELLOW GREEN.

Terminal window
av dast scan --target <url> [flags]

The binary ships as alertavuln; av is the common alias - they are interchangeable in every example.

av dast scan runs the bundled scanners against a running target URL, and normalises everything they emit into a single finding set rendered as a table (or JSON with --json). A local scan runs on your own machine, costs nothing, and is not metered.

Scans are passive by default: the scanners crawl the target and observe its responses without sending attack traffic, so a passive scan is non-intrusive and safe to run anywhere, including production. Add --active to also run attack-payload rules; --intensity tunes how aggressive an active run is (request rate, concurrency, and time budget). --active is gated for production - see the authorization note above.

Before any scanner runs, a target other than localhost must pass an ownership check. You must be logged in (av login); the CLI sends the target URL and scan mode to AlertaVuln, which confirms that your organisation’s plan includes DAST (the Attack Scanning module for --active) and that your organisation has verified the target’s domain - see Prove you control the domain. A verified domain covers every host under it. A raw IP address is refused, since there is no domain to verify. If the check fails, the scan is refused with the reason and nothing runs. localhost and other loopback addresses are your own machine: they skip the check, need no login, and work offline.

Pass --project to upload the findings to that project so they appear on its Dynamic Scan page. The target’s git ref is detected from the working tree’s git metadata and recorded as provenance. --no-upload keeps a scan local-only even when --project is set. The --target value must be an absolute http(s) URL; any credentials embedded in it are stripped before the URL reaches the engines, the upload, or any log.

For CI gating, --fail-on makes the command exit non-zero when the worst finding is at or above the given tier.

Flag Default Description
--target - Target base URL to scan (required; absolute http(s) URL)
--project - Project ID to upload findings to (omit for a local-only scan)
--json false Output the scan as JSON instead of a table
--export - Export to a directory or file (HTML; raw JSON with --json)
--no-upload false Scan locally only; do not upload even if --project is set
--fail-on none Exit non-zero if the worst finding is at or above the tier: red, yellow, or none
--active false Run active (attack-payload) rules in addition to the passive checks
--intensity low Scan intensity (rate, concurrency, time budget): low, medium, or high
--environment staging Target environment: staging, production, or internal (gates --active)
--i-am-authorized false Attest you own or are authorized to test the target (required non-interactively; also gates --active against production)
--seed-urls - File of newline-separated same-site URLs to seed the crawl (SPAs, APIs); also fed to the template-scanner, which checks each URL
--openapi - OpenAPI/Swagger spec (http(s) URL or local file) to seed the web-scanner’s crawl. The template-scanner does not use the spec; the scan prints a notice saying so
--ajax-spider false Also crawl with a headless browser to find pages a client-rendered app builds in JavaScript. Slower. Needs a container runtime, or Firefox on PATH for a native run (otherwise the scan prints a notice and runs the standard crawl). Env: ALERTAVULN_DAST_AJAX_SPIDER=1

Passive scan of a running staging site (you confirm authorization at the prompt):

Terminal window
av dast scan --target https://staging.example.com

Scan and upload the findings to a project’s Dynamic Scan page:

Terminal window
av dast scan --target https://staging.example.com --project <projectId>

Gate a CI pipeline - non-interactive, so authorization is attested with the flag, and the run exits non-zero on a RED finding:

Terminal window
av dast scan --target https://staging.example.com \
--i-am-authorized --fail-on red --json

Run an active scan (attack payloads) against a non-production target at higher intensity:

Terminal window
av dast scan --target https://staging.example.com \
--active --intensity high --i-am-authorized

Active scan of a production target - permitted only with the explicit attestation:

Terminal window
av dast scan --target https://app.example.com \
--environment production --active --i-am-authorized

Scan a single-page app: seed the routes a crawler cannot find, and add the browser crawl for pages the app builds in JavaScript:

Terminal window
av dast scan --target https://staging.example.com \
--seed-urls ./urls.txt --ajax-spider

The web-scanner runs in a container when Docker or Podman is on PATH, using a pinned image. Without a container runtime it runs natively, which needs Java. Both ways run the same scan plan: the same crawl, seeds, authentication and report. If neither is available, the web-scanner is skipped with a notice and the template-scanner still runs (a form login needs the web-scanner, so that scan fails with a clear message instead).

  • Local targets work from the container. For a localhost or 127.0.0.1 target, the CLI points the container at your machine and maps every finding back to the URL you typed.
  • Linux and 127.0.0.1-only services. On Linux the container reaches your machine through its host-gateway address, which cannot see a service bound only to 127.0.0.1, so a Linux scan of a loopback target prints a notice about it. If the service listens only on 127.0.0.1, bind it to 0.0.0.0, or run the scan where no container runtime is on PATH, so the web-scanner runs natively.
  • Your identity on Linux. The container runs as your own user, so it can read and write the scan’s private working folder. Rootless Podman and rootless Docker are handled as well.

--seed-urls reaches both scanners: the web-scanner imports the URLs before it crawls, and the template-scanner runs its checks against each one. --openapi seeds the web-scanner’s crawl only; the template-scanner does not use the spec, and the scan prints ! OpenAPI seed applies to the web-scanner only. Seeds outside the target’s site are dropped. See Help us find your pages for how to build a seed list or find your spec.

The standard crawl follows links in the HTML. A client-rendered app builds many of its pages in JavaScript, so --ajax-spider (or ALERTAVULN_DAST_AJAX_SPIDER=1) adds a second crawl that drives a headless browser. With a form login, the browser crawl runs as the signed-in user too. It is opt-in because it is slower: it gets the same time limit as the standard crawl, taken from the web-scanner’s share of the time budget.

The container image includes the browser. A native run needs Firefox on PATH. When the browser crawl cannot run, the scan prints one of these notices and continues with the standard crawl:

! browser crawl skipped: no Firefox on PATH for the web-scanner to drive; the standard crawl still runs
! browser crawl skipped: the web-scanner could not start a browser

The template-scanner checks the target against a pinned set of scan templates. The first scan downloads that set once (about 10 MB), verifies its checksum, and keeps it in the CLI’s engine cache next to the scanners. Later scans reuse it, and a scan never fetches templates of its own, so the same CLI version always scans with the same templates.

On a machine that cannot reach the download, point the CLI at an extracted copy instead. Copy the alertavuln/bin/templates/<version> folder from the user config directory of a machine where a scan has run, then:

Terminal window
export ALERTAVULN_DAST_TEMPLATES_DIR=/path/to/templates

When the variable is set, nothing is downloaded. It must name an extracted copy of the templates (a directory with the http folder at its top); anything else is refused with a notice. A relative path is resolved against the directory you run the scan from. If no templates are available, the template-scanner does not run, the scan says why on stderr, and the web-scanner results still stand.

A passive scan sends no attack payloads. The two scanners cover it like this:

  • The web-scanner crawls the target (and any seed URLs), then checks every response it saw: security headers, cookies, information leaks, and similar.
  • The template-scanner runs a bounded set of checks against the target and each seed URL: missing or deprecated security headers, tokens or keys exposed in a response, revealing headers, site files such as robots.txt and security.txt, and, for an https target, certificate and TLS protocol checks (expired or self-signed certificates, weak ciphers, deprecated TLS versions). That is under 100 requests per URL, so a low-intensity scan with a handful of seed URLs finishes well inside its time budget.

A passive scan does not run CVE checks, exploit-shaped checks (path traversal, injection or cache-poisoning probes that carry attack payloads), or any intrusive, fuzzing or denial-of-service check. --active adds the intrusive and fuzzing checks.

Both tiers stay on the URL you typed. TLS checks run only against an https target, and no check probes other ports or services on the host.

Out-of-band detection is off. A scan never registers with an outside interaction server, and never makes the target call one. Checks that can only confirm a finding through such a callback (some blind injection and server-side request checks) do not run.

--intensity sets the time budget for the whole scan:

Intensity Whole scan web-scanner share (default passive scan) Left for the template-scanner (at least)
low 15 min 8 min 7 min
medium 30 min 13 min 17 min
high 60 min 23 min 37 min

The web-scanner runs first, inside its own share: its crawl limit, a two-minute wait for its analysis, and a minute to start and write its report. --ajax-spider adds a second crawl of the same length, and --active adds an attack phase of the same length. The template-scanner then runs until the whole-scan budget ends, so it also gets any time the web-scanner did not use. In a default passive scan, neither scanner can use up the other’s time.

The opt-in phases make the web-scanner’s share larger, but never larger than the whole scan less 2 minutes. The template-scanner always keeps at least those 2 minutes, which cover its passive checks on the target and a handful of seed URLs at low intensity.

Intensity web-scanner share with --active or --ajax-spider With both
low 13 min (2 min left for the template-scanner) 13 min (2 min left)
medium 23 min (7 min left) 28 min (2 min left)
high 43 min (17 min left) 58 min (2 min left)

With both options, the web-scanner’s phases can add up to more than its share. On a small site they finish early, and the template-scanner also gets the time the web-scanner leaves unused. On a large site the web-scanner can reach the end of its share before it writes its report; it is then failed, with the reason stopped at its time budget, and only the template-scanner’s findings are kept. On a large site, run the two options in separate scans, and raise --intensity when you add either one.

The template-scanner reports each finding as it finds it. If the budget runs out before it finishes, the findings it reported before then are kept and uploaded like any others, and the scan says so (see Engine status). A template-scanner cut off with results already reported is partial; one cut off before it reported anything is failed, with the reason stopped at its time budget.

When one scanner does not complete but the other does, the scan still succeeds. The CLI prints one line on stderr for each scanner that did not complete, in every output mode, so --json stdout stays a clean document:

! template-scanner did not complete: scan templates unavailable: ...
! template-scanner stopped at its time budget; the 12 finding(s) it reported before then are kept

The JSON document (--json) also carries an engines array with one entry per scanner, with a one-line reason when it did not complete. status is one of:

  • completed: the scanner ran to the end. It may have found nothing, which is a clean result. The template-scanner also ends this way when it could not reach the target, so treat an empty result as clean only when the target was up.
  • partial: the scanner stopped at its time budget, and the findings it reported before then are in the document.
  • failed: the scanner produced no results (it could not start, exited with an error, wrote no report, or reached its time budget before reporting anything).
"engines": [
{ "name": "web-scanner", "status": "completed" },
{ "name": "template-scanner", "status": "partial", "reason": "stopped at its time budget" }
]

A few settings change what a scanner does, and the scan says so once on stderr, also starting with ! :

Notice When
form login: the web-scanner signs in during the scan; the template-scanner runs unauthenticated A form login is set
OpenAPI seed applies to the web-scanner only --openapi is set
browser crawl skipped: ... --ajax-spider is set but the browser crawl cannot run (see Browser crawl)
the web-scanner runs in a container and reaches this machine through its host-gateway address; ... A loopback target on Linux with a container runtime (see How the scanners run)

Microsoft Defender can flag the pinned template-scanner binary as malware and quarantine it. This is a false positive. When it happens, the template-scanner does not run, the scan says so on stderr, and the web-scanner results still stand. The next scan downloads the binary again, and Defender may remove it again.

To keep the template-scanner running, add a Defender exclusion for the CLI’s engine cache folder, %AppData%\alertavuln\bin. From an elevated PowerShell:

Terminal window
Add-MpPreference -ExclusionPath "$env:APPDATA\alertavuln\bin"

Exclude only that folder; on a managed machine, ask your administrator to add the exclusion. The CLI checks every scanner it downloads against a pinned SHA-256 checksum before installing it. Please also report the false positive to Microsoft at microsoft.com/wdsi/filesubmission, so the detection can be corrected for everyone. Defender can also flag a freshly built av binary; report it the same way.

Variable Description
ALERTAVULN_DAST_AUTH_* Credentials for an authenticated scan (see av dast targets auth)
ALERTAVULN_DAST_AJAX_SPIDER 1 turns on the browser crawl, the same as --ajax-spider
ALERTAVULN_DAST_TEMPLATES_DIR An extracted copy of the scan templates to use instead of downloading them (see Scan templates)
Code Meaning
0 Scan completed, at least one scanner completed or returned partial findings, and no finding is at or above the --fail-on tier
1 Scan failed (including when no scanner completed), authorization was refused or declined, the ownership check refused a non-loopback target (domain not verified, no DAST plan, or not logged in), or at least one finding is at or above the --fail-on tier