Skip to main content

Free 30-min security demo Book Now

Offensive360 Offensive360
Tools & Comparisons

OWASP ZAP DAST Scanner: Setup & Limits

OWASP ZAP setup guide, CI/CD integration, scan configuration for authenticated apps, and when ZAP's limitations mean you need a commercial DAST scanner.

Offensive360 Security Research Team — min read
OWASP ZAP DAST scanner owasp dast scanner dynamic application security testing ZAP scanner web application security testing automated security testing DAST tools OWASP ZAP alternatives DAST CI/CD authenticated scanning web vulnerability scanner application security testing DAST setup guide

OWASP ZAP (Zed Attack Proxy) is the most widely used open-source DAST scanner in the world. Maintained by the OWASP Foundation, ZAP is free, extensible, and runs on every operating system — making it the default starting point for any team beginning with Dynamic Application Security Testing.

This guide covers everything you need to know about ZAP: how to set it up, how to run authenticated scans, how to integrate it into CI/CD pipelines, what it finds and what it misses, and when the limitations of an open-source DAST scanner mean it’s time to evaluate a commercial alternative.


What Is OWASP ZAP?

OWASP ZAP (Zed Attack Proxy) is a free, open-source Dynamic Application Security Testing (DAST) tool. Unlike Static Application Security Testing (SAST) tools that analyze source code, DAST tools test a running web application by sending real HTTP requests and observing how the application responds — exactly the way an attacker would probe it.

ZAP operates as an intercepting proxy, sitting between your browser (or automated scanner) and the web application. It records every request and response, scans for injection vulnerabilities, tests authentication controls, and checks security headers — all without needing access to source code.

ZAP was originally developed as a fork of Paros Proxy in 2010 and has been the flagship OWASP security testing tool ever since. The project is maintained by a community of contributors with oversight from the OWASP Foundation.


What DAST Scanners Actually Test

Before diving into ZAP specifically, it’s worth understanding what dynamic testing finds — and what it doesn’t.

A DAST scanner tests your application from the outside, making it complementary to SAST (which tests source code from the inside). DAST finds:

  • Runtime vulnerabilities — issues that only appear when the application is running: authentication weaknesses, session management flaws, server configuration issues
  • Injection vulnerabilities — SQL injection, command injection, XSS, XXE, template injection (detected by observing the application’s response to attack payloads)
  • Access control failures — IDOR, horizontal/vertical privilege escalation (requires authenticated scanning across multiple user roles)
  • Security misconfiguration — missing security headers, verbose error messages, directory listing, exposed debug endpoints
  • Business logic flaws — price tampering, workflow bypass, race conditions (partial — requires custom scan sequences)

DAST does not find:

  • Hardcoded credentials or secrets in source code
  • Complex taint-flow injection chains that don’t produce observable responses
  • Vulnerabilities in code that is never executed during the scan crawl
  • Second-order injection where the payload is stored and triggered by a different user’s action

For complete application security coverage, DAST must be combined with SAST.


Installing and Starting OWASP ZAP

The ZAP Docker image is the recommended approach for automated scanning and CI/CD integration:

# Pull the ZAP stable image
docker pull ghcr.io/zaproxy/zaproxy:stable

# Run a baseline scan (unauthenticated, passive + active rules)
docker run --rm ghcr.io/zaproxy/zaproxy:stable \
  zap-baseline.py \
  -t https://target-app.example.com \
  -r zap-report.html

# Run a full scan with the ZAP automation framework
docker run --rm \
  -v $(pwd):/zap/wrk/:rw \
  ghcr.io/zaproxy/zaproxy:stable \
  zap-full-scan.py \
  -t https://target-app.example.com \
  -r /zap/wrk/report.html \
  -J /zap/wrk/report.json

Method 2: Desktop Application

Download the ZAP desktop application from zaproxy.org. The GUI version is suitable for manual security testing — it gives you a visual interface for intercepting requests, running scans, and reviewing findings.

Method 3: Package Manager

# macOS (Homebrew)
brew install --cask owasp-zap

# Linux (snap)
sudo snap install zaproxy --classic

ZAP Scanning Modes Explained

ZAP has several scanning modes, each suited for a different use case:

Passive Scan

ZAP’s passive scanner analyzes HTTP traffic without making additional requests. It identifies:

  • Missing security headers (Content-Security-Policy, X-Content-Type-Options, HSTS)
  • Information disclosure in responses (server version, stack traces)
  • Insecure cookie attributes (missing HttpOnly, Secure, SameSite flags)
  • Basic content patterns (forms without CSRF tokens, links to HTTP resources)

Passive scanning is safe to run on production applications — it only analyzes traffic the browser generates, not injecting any additional payloads.

Active Scan

ZAP’s active scanner injects attack payloads into every parameter to test for exploitable vulnerabilities:

  • SQL injection (error-based and time-based)
  • Cross-site scripting (reflected and stored)
  • Path traversal
  • Command injection
  • XML/XXE injection
  • LDAP injection
  • Remote file inclusion

Important: Active scanning generates high traffic volume and submits attack payloads. Always run active scans against a non-production environment (staging, local Docker instance), and ensure you have explicit authorization to test.

AJAX Spider

Modern single-page applications (SPAs) built with Angular, React, or Vue.js don’t work well with traditional HTML-crawling spiders. ZAP’s AJAX Spider uses a browser driver (Selenium, Firefox headless) to crawl JavaScript-rendered applications:

# Run AJAX Spider
docker run --rm ghcr.io/zaproxy/zaproxy:stable \
  zap-full-scan.py \
  -t https://target-app.example.com \
  --ajax \
  -r report.html

Setting Up Authenticated Scanning with ZAP

The most important configuration for meaningful security testing is authentication. Unauthenticated scans only test the public surface of your application — the login page, public API endpoints, and marketing content. The vast majority of security-sensitive functionality is behind authentication.

ZAP supports several authentication mechanisms:

Form-Based Authentication

# ZAP Automation Framework: form-based auth
env:
  contexts:
    - name: "MyApp"
      urls:
        - "https://target-app.example.com"
      authentication:
        method: "form"
        parameters:
          loginPageUrl: "https://target-app.example.com/login"
          loginRequestData: "username={%username%}&password={%password%}"
          usernameParameter: "username"
          passwordParameter: "password"
        verification:
          method: "response"
          loggedInRegex: "\\QWelcome, testuser\\E"
          loggedOutRegex: "\\QSign in\\E"
      users:
        - name: "Test User"
          credentials:
            username: "[email protected]"
            password: "${ZAP_TEST_PASSWORD}"

Bearer Token Authentication

For APIs that use JWT or OAuth bearer tokens:

# ZAP Automation Framework: Bearer token auth
env:
  contexts:
    - name: "API Context"
      urls:
        - "https://api.example.com"
      authentication:
        method: "http"
        parameters:
          headerValue: "Bearer ${ZAP_API_TOKEN}"

Session Token Handling

For applications that issue session tokens after login, ZAP needs to identify the session token parameter and include it in subsequent requests:

sessionManagement:
  method: "cookie"
  parameters:
    cookieName: "session_id"

CI/CD Integration with ZAP

ZAP’s Automation Framework is designed for CI/CD integration. Here are configuration examples for the most common platforms:

GitHub Actions

name: DAST Security Scan

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  dast-scan:
    runs-on: ubuntu-latest
    services:
      app:
        image: your-app-image:latest
        ports:
          - 8080:8080

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Wait for app to start
        run: sleep 10

      - name: ZAP Baseline Scan
        uses: zaproxy/[email protected]
        with:
          target: 'http://localhost:8080'
          rules_file_name: '.zap/rules.tsv'
          cmd_options: '-a'
        env:
          ZAP_TEST_PASSWORD: ${{ secrets.ZAP_TEST_PASSWORD }}

      - name: Upload ZAP Report
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: zap-report
          path: report_html.html

GitLab CI

dast-scan:
  image: ghcr.io/zaproxy/zaproxy:stable
  stage: security
  script:
    - zap-baseline.py
        -t https://staging.yourapp.com
        -r report.html
        -z "-config scanner.attackStrength=HIGH"
  artifacts:
    paths:
      - report.html
    expire_in: 7 days
  only:
    - main
    - merge_requests

Jenkins Pipeline

stage('DAST Scan') {
    steps {
        script {
            sh """
                docker run --rm \
                  -v ${WORKSPACE}:/zap/wrk/:rw \
                  ghcr.io/zaproxy/zaproxy:stable \
                  zap-full-scan.py \
                    -t https://staging.yourapp.com \
                    -r /zap/wrk/zap-report.html \
                    -J /zap/wrk/zap-report.json \
                    -z "-config api.key=${ZAP_API_KEY}"
            """
        }
    }
    post {
        always {
            publishHTML(target: [
                allowMissing: false,
                alwaysLinkToLastBuild: true,
                keepAll: true,
                reportDir: '.',
                reportFiles: 'zap-report.html',
                reportName: 'ZAP Security Report'
            ])
        }
    }
}

ZAP Configuration for API Testing

Modern web applications are increasingly API-first. ZAP can scan REST APIs defined with an OpenAPI/Swagger specification:

# ZAP Automation Framework: API scanning via OpenAPI spec
jobs:
  - type: openapi
    parameters:
      apiFile: "https://api.example.com/openapi.json"
      # Or local file:
      apiFile: "/zap/wrk/openapi.json"
      targetUrl: "https://api.example.com"

For GraphQL APIs, use ZAP’s GraphQL add-on:

jobs:
  - type: graphql
    parameters:
      endpoint: "https://api.example.com/graphql"
      schemaUrl: "https://api.example.com/graphql/schema"
      # ZAP will query introspection and scan all operations

ZAP Scan Rule Configuration

ZAP’s rules can be tuned to reduce false positives and focus on high-severity findings:

# .zap/rules.tsv — override scan rule thresholds
# ID	THRESHOLD	STRENGTH
10202	HIGH	MEDIUM	# Absence of Anti-CSRF Tokens — raise threshold
10016	HIGH	HIGH	# Web Browser XSS Protection
90022	HIGH	MEDIUM	# Application Error Disclosure
10098	OFF	DEFAULT	# Cross-Domain Misconfiguration (reduce noise for CDN origins)

To see all available rules and their IDs:

docker run --rm ghcr.io/zaproxy/zaproxy:stable zap.sh -cmd -quickurl http://example.com -quickout /tmp/report.html
# Or browse the ZAP rule documentation at: https://www.zaproxy.org/docs/alerts/

What ZAP Finds Well

ZAP’s active scanner reliably detects:

  • Reflected XSS — ZAP’s XSS scanner is comprehensive, covering all input contexts (HTML, attribute, JavaScript, URL)
  • Missing security headers — passive scan catches every missing header (CSP, HSTS, X-Content-Type-Options, etc.)
  • Information disclosure — server version headers, verbose error pages, stack traces
  • Directory listing — accessible directory indexes
  • Basic SQL injection — error-based SQLi in form parameters and URL query strings
  • Insecure cookie attributes — missing HttpOnly, Secure, SameSite flags
  • Basic authentication issues — missing brute-force protection, insecure session token exposure
  • CORS misconfiguration — wildcard Access-Control-Allow-Origin, origin reflection

ZAP’s Limitations

Despite being the most popular open-source DAST scanner, ZAP has significant limitations that matter for enterprise security programs:

1. Weak Blind SQL Injection Detection

ZAP’s time-based and boolean-based blind SQLi detection — where no error message appears but the database query still executes — is inconsistent and often misses injections that well-tuned commercial scanners detect reliably.

2. Limited Modern Authentication Support

Complex OAuth flows, multi-step login sequences with CSRF tokens, and dynamic JWT token refresh require custom ZAP scripts. This works, but requires ongoing maintenance as authentication flows change — something a commercial scanner handles automatically.

3. SPA/JavaScript-Heavy Application Crawling

ZAP’s AJAX Spider (browser-based crawling for JavaScript applications) is functional but significantly slower and less complete than commercial crawlers that model application state machines. Large SPAs with complex routing are frequently under-crawled.

4. False Positive Rate

ZAP’s scan rules produce a relatively high false-positive rate for some vulnerability classes — particularly around CORS, cross-domain references, and application error detection — requiring significant manual triage time.

5. No SAST Correlation

ZAP findings cannot be correlated with source code findings from a SAST tool. For organizations that want to see both runtime vulnerabilities (DAST) and code-level vulnerabilities (SAST) in a unified dashboard, ZAP must be supplemented with a separate tool and custom integration work.

6. Authenticated Scan Complexity

Configuring reliable authenticated scans — particularly for applications with multi-step authentication, OAuth 2.0, or MFA — requires ZAP scripting expertise. A misconfigured auth setup means the scanner silently falls back to an unauthenticated scan without clear indication, giving false confidence.


OWASP ZAP vs Commercial DAST Scanners

Here’s how ZAP compares to commercial alternatives on the factors that matter most for enterprise use:

FeatureOWASP ZAPCommercial DAST (e.g., Offensive360)
CostFreePaid (flat rate or per-scan)
SQLi detection depthBasic (error-based reliable; blind inconsistent)Deep (error-based + time-based + boolean-based)
Authenticated scan setupManual scripting requiredGUI-driven, auto-detects session management
SPA/JavaScript crawlingAJAX Spider (functional, slow)Headless browser with state modeling
SAST + DAST in one platformNo (separate tools)Yes (unified findings)
On-premise deploymentDocker anywhereDedicated OVA/appliance
CI/CD integrationVia Docker + Automation FrameworkNative plugins (GitHub, GitLab, Jenkins, Azure DevOps)
False positive rateMedium-highLow (tuned rulesets)
API specification importOpenAPI/Swagger + GraphQLOpenAPI/Swagger + GraphQL + Postman
SupportCommunity forumsVendor support SLA

For teams starting out with DAST, ZAP is an excellent beginning. For organizations where:

  • The majority of the application is behind authentication
  • The application is a JavaScript SPA
  • SAST and DAST findings need to be unified
  • The security team cannot dedicate hours to ZAP scripting and maintenance

— a commercial DAST scanner significantly reduces both false negatives and operational overhead.


ZAP Baseline Scan: What It Reports

The ZAP baseline scan (the most common CI/CD integration) runs passive rules plus a limited active scan. Here’s what a typical baseline scan report includes for a well-configured application:

Common baseline scan findings (Medium/Low severity):

AlertRiskDescription
Missing Content-Security-PolicyMediumCSP header not present or set to unsafe
Missing HSTSLowStrict-Transport-Security not present
X-Content-Type-Options not setLownosniff directive missing
Cookies without SameSiteLowSession cookie lacks SameSite attribute
Server version disclosureLowServer: nginx/1.24.0 reveals version
Redirect via user-supplied URLLowPotential open redirect

Common findings requiring active scan (High/Critical severity):

AlertRiskDescription
SQL InjectionHighError-based injection in query parameter
Reflected XSSHighScript injection in form field
Application Error DisclosureMediumStack trace in 500 error response
CORS MisconfigurationHighOrigin reflection without allowlist

Benchmarking ZAP Against OWASP Juice Shop

The standard way to validate a DAST scanner is to run it against OWASP Juice Shop — a deliberately vulnerable Node.js application with 100+ known vulnerabilities.

# Start Juice Shop
docker run -d -p 3000:3000 bkimminich/juice-shop
sleep 10

# Run ZAP full scan against Juice Shop
docker run --rm \
  -v $(pwd):/zap/wrk/:rw \
  ghcr.io/zaproxy/zaproxy:stable \
  zap-full-scan.py \
  -t http://host.docker.internal:3000 \
  -r /zap/wrk/juice-shop-zap-report.html \
  -J /zap/wrk/juice-shop-zap-report.json

A well-configured ZAP scan of Juice Shop should find:

  • Reflected XSS in the search parameter
  • Missing security headers
  • CORS misconfiguration
  • Information disclosure in error responses
  • Basic SQL injection in the search endpoint

What ZAP typically misses in Juice Shop:

  • Time-based blind SQL injection in the login form
  • JWT algorithm confusion (requires specialized JWT scanning)
  • IDOR in the basket API (requires multi-account authenticated testing)
  • Stored XSS in product reviews (requires authenticated posting + separate session viewing)
  • Business logic vulnerabilities (negative quantities, coupon manipulation)

This benchmark is instructive for understanding ZAP’s true detection rate on a real-world application architecture.


When to Move Beyond ZAP

ZAP is the right tool when:

  • You’re just starting with DAST and want zero cost
  • Your application is simple, server-rendered HTML
  • You have the engineering time to maintain ZAP scripts for authentication
  • You only need a basic security header and XSS check in CI

Consider a commercial DAST scanner when:

  • Your application is a modern SPA (React/Angular/Vue) with a REST or GraphQL API
  • Authenticated scanning keeps failing or producing incomplete results
  • DAST false positives consume too much security team time
  • You need unified SAST + DAST findings in one platform
  • You’re preparing for compliance audit (PCI-DSS, SOC 2, ISO 27001) and need audit-grade reporting
  • You need on-premise deployment with no traffic leaving your network

Running Your First OWASP ZAP Scan

Here’s a minimal working configuration to get your first authenticated scan running:

# 1. Create a ZAP automation plan file
cat > zap-plan.yaml << 'EOF'
env:
  contexts:
    - name: "MyApp"
      urls:
        - "https://staging.yourapp.com"
      authentication:
        method: "form"
        parameters:
          loginPageUrl: "https://staging.yourapp.com/login"
          loginRequestData: "email={%username%}&password={%password%}"
        verification:
          method: "response"
          loggedInRegex: "\\Qdashboard\\E"
          loggedOutRegex: "\\QSign in\\E"
      users:
        - name: "Test User"
          credentials:
            username: "[email protected]"
            password: "TestPassword123!"
jobs:
  - type: spider
    parameters:
      context: "MyApp"
      user: "Test User"
      maxDuration: 5
  - type: activeScan
    parameters:
      context: "MyApp"
      user: "Test User"
  - type: report
    parameters:
      template: "traditional-html"
      reportFile: "/zap/wrk/report.html"
EOF

# 2. Run ZAP with the automation plan
docker run --rm \
  -v $(pwd):/zap/wrk/:rw \
  ghcr.io/zaproxy/zaproxy:stable \
  zap.sh -cmd -autorun /zap/wrk/zap-plan.yaml

Review the generated report.html for findings. Focus on High severity findings first — these are the vulnerability classes most likely to be exploitable in a real attack.


Frequently Asked Questions

Is OWASP ZAP free to use in production environments?

Yes. ZAP is licensed under the Apache 2.0 license. It is free for all uses — commercial, production, CI/CD automation. There are no usage fees, scan limits, or commercial restrictions.

Does ZAP work with HTTPS / TLS?

Yes. ZAP acts as a proxy and handles TLS termination. For automated scanning, you may need to add ZAP’s CA certificate to your browser’s trust store for manual testing, or configure the acceptSslCertificate option for automated scans.

Can OWASP ZAP scan mobile app APIs?

Yes. ZAP can scan any HTTP/HTTPS API, regardless of whether the client is a browser or a mobile application. Configure your mobile app to proxy through ZAP during testing, then export the recorded traffic to drive an active scan of the API endpoints.

What’s the difference between ZAP baseline scan and full scan?

The baseline scan runs passive rules (no attack payloads — safe for production) plus a limited set of active rules. It’s suitable for CI/CD gates where you want fast results without risk of disrupting the application. The full scan runs all active scan rules with full attack payload injection — suitable for staging environments, not production.

How do I fix ZAP’s “out of scope” warnings in CI/CD?

If ZAP reports warnings about out-of-scope URLs, configure the context scope explicitly in the Automation Framework plan to include only your application’s domain and exclude third-party CDN and analytics domains.


Summary

OWASP ZAP is the starting point for any DAST program — it’s free, well-documented, and detects the most common web application vulnerabilities reliably. For straightforward applications and teams beginning with automated security testing, it delivers significant value at zero cost.

As applications grow in complexity — JavaScript SPAs, authenticated API surfaces, multi-role access control — ZAP’s limitations in authenticated crawling, blind injection detection, and false positive rate become increasingly significant. At that point, integrating a purpose-built commercial DAST scanner alongside or instead of ZAP produces better coverage with lower operational overhead.

The right approach: start with ZAP, benchmark it against OWASP Juice Shop to understand its real detection rate, and evaluate commercial alternatives when ZAP’s limitations consume more engineering time than they save.


Offensive360 DAST extends beyond ZAP with deep authenticated scanning, unified SAST + DAST reporting, and on-premise deployment. Run a one-time DAST scan for your web application — authenticated, full coverage, results within 48 hours. Or book a demo to see it in action against OWASP Juice Shop.

Offensive360 Security Research Team

Application Security Research

Find vulnerabilities before attackers do

Run Offensive360 SAST and DAST against your applications and get a full vulnerability report in minutes.