DAST in CI/CD Pipeline
Why DAST Needs a Running Application
Unlike SAST and SCA, which analyze source code and dependency manifests without executing anything, Dynamic Application Security Testing (DAST) attacks a running instance of the application - sending real HTTP requests and observing real responses. This means it needs a deployed environment (staging, an ephemeral preview environment, or a dedicated DAST target) before it can run at all, which is why DAST typically lives later in the pipeline than SAST/SCA.
DAST's advantage is that it finds issues invisible to static analysis: runtime misconfigurations, issues that only manifest with the actual server/framework stack wired together, and authentication/session flaws that require an actual login flow to exercise.
A Real Pipeline Example: OWASP ZAP Baseline Scan
name: DAST Scan
on:
pull_request:
types: [opened, synchronize]
jobs:
deploy-preview:
runs-on: ubuntu-latest
outputs:
preview_url: ${{ steps.deploy.outputs.url }}
steps:
- uses: actions/checkout@v4
- name: Deploy ephemeral preview environment
id: deploy
run: echo "url=https://pr-${{ github.event.number }}.preview.example.com" >> "$GITHUB_OUTPUT"
# in practice: deploy via your platform (Vercel, ECS, k8s namespace-per-PR, etc.)
dast-scan:
needs: deploy-preview
runs-on: ubuntu-latest
steps:
- name: OWASP ZAP Baseline Scan
uses: zaproxy/action-baseline@v0.12.0
with:
target: ${{ needs.deploy-preview.outputs.preview_url }}
rules_file_name: '.zap/rules.tsv'
cmd_options: '-a'
The baseline scan is passive (spiders the site, checks headers/cookies, doesn't send attack payloads) - fast enough to run on every PR against an ephemeral preview environment. A full active scan (which does send attack payloads - SQLi/XSS attempts, etc.) is slower and riskier to run against shared staging, so it typically runs on a schedule (nightly) or gated to pre-release only:
full-scan-nightly:
runs-on: ubuntu-latest
steps:
- name: OWASP ZAP Full Scan
uses: zaproxy/action-full-scan@v0.10.0
with:
target: 'https://staging.example.com'
Authenticated Scans
Most real applications require login before the interesting attack surface is even reachable. ZAP (and commercial tools like Burp Suite Enterprise) support authenticated scanning via:
- Scripted login - ZAP replays a login sequence (username/password form submission) before spidering.
- Session token injection - supply a valid session cookie/JWT directly (common for API-heavy apps), often generated by a dedicated CI test-account login step before the scan runs.
- HAR-based auth - record an authenticated browser session and replay it.
Without authenticated scanning, DAST only ever tests the public, unauthenticated surface of the app - which for most apps is a small fraction of the actual attack surface.
How DAST Complements SAST, Not Duplicates It
| SAST | DAST | |
|---|---|---|
| Sees | Source code | HTTP requests/responses |
| Catches | Business-logic-blind code patterns (injection sinks, weak crypto) | Runtime misconfig (missing security headers, verbose errors, broken auth flows) |
| Blind to | Deployment/runtime config, environment-specific issues | Code it can't reach without a valid input/auth path, dead code |
| False positive profile | Higher (no runtime context) | Lower for confirmed findings (it actually triggered the behavior), but slower and narrower coverage |
A vulnerable SQL query might be flagged by SAST as a data-flow risk and separately confirmed by DAST actually triggering a database error via a crafted request - the two together give you both "this pattern is dangerous" and "this pattern is exploitable in the deployed app," which is a stronger signal than either alone.
Best Practices
- Baseline (passive) scans on every PR, full (active) scans on a schedule or pre-release - matches scan cost to how often it's worth paying it.
- Always scan an authenticated session, not just the public login page - most of the real attack surface is behind auth.
- Never run an active/full scan against production - it sends real attack payloads and can cause outages or data corruption; use staging or a dedicated DAST target only.
- Feed DAST findings into the same tracker as SAST/SCA findings - see Vulnerability Management for unifying triage across sources.