segrep-dast scanner

Opt-in local passive DAST scanner for deterministic runtime checks

Opt-in DAST scanner for Segrep that performs deterministic passive web checks against a target URL and can shadow external ZAP for parity comparison.

Why use segrep-dast

  • Keeps the existing zap scanner unchanged while local DAST coverage is developed.
  • Provides fast, deterministic runtime checks without Docker or ZAP.
  • Fits the same opt-in rollout model as segrep-sbom and segrep-vuln.
  • Supports Milestone 2 parity shadow against external ZAP before any promotion decision.

Scanner behavior

segrep-dast requires --target-url.

pnpm segrep scan . --scanners segrep-dast --target-url http://127.0.0.1:4010 --format json

Current local checks include:

  • missing Content-Security-Policy
  • missing X-Content-Type-Options
  • missing clickjacking protection headers
  • weak cookie flags
  • TRACE exposure via OPTIONS
  • exposed .git/HEAD
  • directory listing heuristics
  • verbose server banner detection

Modes

Configure execution mode with SEGREP_DAST_MODE:

  • auto (default): local passive checks first, external ZAP fallback if local scan fails
  • local: require the local segrep-dast path only
  • external: force external ZAP baseline path only
SEGREP_DAST_MODE=auto pnpm segrep scan . --scanners segrep-dast --target-url http://127.0.0.1:4010

Parity shadow mode

Enable parity shadow to compare local segrep-dast findings against external ZAP findings:

SEGREP_DAST_PARITY_SHADOW=true pnpm segrep scan . --scanners segrep-dast --target-url http://127.0.0.1:4010 --format json

Parity report path:

  • .segrep/segrep-dast-parity.json

Parity report fields include:

  • status (compared or skipped)
  • summary.localFindingCount
  • summary.externalFindingCount
  • summary.localOnlyCount
  • summary.externalOnlyCount

If external ZAP is unavailable, parity status is skipped and the scan still succeeds in best-effort mode.

Parity shadow requires Docker on the CI runner. On macOS, the scanner rewrites http://127.0.0.1:<port> to http://host.docker.internal:<port> so ZAP in Docker can reach a host-local fixture server. ZAP JSON is written to a mounted /zap/wrk/report.json volume (required by zap-baseline.py whenever -J is used). The host mount is chmod 777 so the non-root ZAP container user can write the report (--autooff avoids Automation Framework report path issues).

CI parity gate

Use the parity verifier script to enforce drift thresholds:

node scripts/ci-verify-dast-parity.js \
	apps/cli/fixtures/vulnerable-repo/.segrep/segrep-dast-parity.json \
	--allow-skipped \
	--max-local-only 8 \
	--max-external-only 8

Promotion-readiness signal (non-blocking):

node scripts/ci-verify-dast-parity.js \
	apps/cli/fixtures/vulnerable-repo/.segrep/segrep-dast-parity.json \
	--allow-skipped \
	--max-local-only 0 \
	--max-external-only 0 \
	--report-only \
	--label promotion-readiness

Recommended threshold tightening rollout:

  • Start with --max-local-only 8 --max-external-only 8
  • Tighten toward 0/0 once external ZAP is consistently available in CI and drift stabilizes

Environment variables

  • SEGREP_DAST_MODE=auto|local|external (default auto)
  • SEGREP_DAST_PARITY_SHADOW=true to compare local findings against external ZAP and write .segrep/segrep-dast-parity.json
  • SEGREP_DAST_TIMEOUT_MS for HTTP request timeout
  • SEGREP_DAST_USER_AGENT to override the default user agent
  • SEGREP_DAST_DISCLOSURE_PATHS for comma-separated disclosure probes

Relationship to zap scanner

  • zap scanner: external ZAP baseline wrapper
  • segrep-dast scanner: local passive runtime checks with optional ZAP fallback and parity shadow