Skip to content

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

  1. 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.
  2. Always scan an authenticated session, not just the public login page - most of the real attack surface is behind auth.
  3. 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.
  4. Feed DAST findings into the same tracker as SAST/SCA findings - see Vulnerability Management for unifying triage across sources.

Credits/References

  1. OWASP ZAP (Zed Attack Proxy)
  2. OWASP Web Security Testing Guide