View all services
Talk to QA Advisor
Browse the Knowledge Hub211 resources
/Tools Library/OWASP ZAP
Tools Library · Review and guide

OWASP ZAP review: what it is, tutorial and alternatives

ZAP (Zed Attack Proxy) is an open-source intercepting proxy and dynamic application security scanner for web applications and APIs. It passively inspects traffic, crawls with three spiders, actively attacks discovered endpoints, and automates through Docker scans, a YAML Automation Framework and an API. Formerly an OWASP project, it is now independent, controlled by its core team and supported by Checkmarx, under the Apache 2.0 licence.

QAble has evaluated this tool and works alongside it. The factual sections are complete; our view is bounded to what we have actually seen rather than a long-term verdict.

last reviewed
13 October 2026
version covered
ZAP 2.17
licence
Open source

Reviewed by Viral Patel

Co-Founder, QAbleLast reviewed 13 October 2026

At a glance

OWASP ZAP at a glance

Official site
Vendor
ZAP Core Team / Checkmarx
Category
Security testing
Licence
Open source (Apache 2.0)
Platforms
Windows, Linux, macOS, Docker
Integrates with
GitHub Actions, Docker, OpenAPI, GraphQL, Postman
First released
2010
Version reviewed
ZAP 2.17

Verdict

Our verdict on OWASP ZAP

Strengths

  • Free under Apache 2.0, with the scanner, fuzzer, API and automation all included
  • The baseline scan sends no attacks, so it can run on every build within a few minutes
  • One YAML Automation Framework plan covers authentication, spidering, scanning, reports and exit codes
  • Official Docker images and GitHub Actions wrap the packaged scans with rules files for triage
  • Imports OpenAPI, GraphQL, SOAP and Postman definitions so APIs are scanned without a crawler
  • The Client spider drives real browsers, which finds routes in JavaScript-heavy single page apps

Weaknesses

  • Authenticated scanning takes real configuration effort, and an unauthenticated scan mostly tests the login page
  • Active scans are slow on large applications and can damage data, so they need a disposable target
  • Findings need triage: expect false positives and repeated header alerts before tuning
  • Many tutorials still use the retired owasp/zap2docker images and Nashorn scripts

Our take

ZAP is the sensible first step for a team adding dynamic security testing to a delivery pipeline. A passive baseline scan costs nothing, needs no attack traffic and catches the configuration classes, such as missing security headers and insecure cookies, that slip through code review. The Automation Framework then takes a team as far as authenticated active scans of a staging environment. QAble has evaluated it rather than maintained a long-running suite on it, so treat this as a bounded take. Two limits matter. A clean ZAP report is not evidence that an application is secure: business logic, access control between users and chained flaws need a human tester. And active scans are real attacks, so run them only against systems you are authorised to test, ideally a disposable staging copy.

We have evaluated this tool rather than maintained a long-running suite on it, so this is a bounded view rather than a long-term verdict. The rest of this page is factual.

How it works

What is OWASP ZAP and how does it work?

A proxy in the middle of the traffic

ZAP sits between a browser, or any HTTP client, and the application. It generates its own root certificate so it can decrypt HTTPS, and browsers launched from ZAP are preconfigured to trust it and proxy through it. Every request and response that passes through is recorded in the Sites tree, which becomes the map of what ZAP knows about the application. Everything else builds on that map: passive rules read it, spiders extend it, and the active scanner attacks the nodes in it. This is why exploring an application by hand through ZAP improves an automated scan, and why anything ZAP never sees, such as a page behind a login it cannot perform, is never tested.

Passive rules read, active rules attack

Passive scan rules inspect traffic without sending anything new: missing or weak security headers, cookies without Secure or HttpOnly flags, information leaks in error pages and comments. They run in the background and are safe against any system you are allowed to browse. Active scan rules send crafted requests, for example SQL injection, cross-site scripting and path traversal payloads, against every parameter of every node in scope, and judge the responses. That is a real attack: it can create records, send emails and corrupt data. Rules carry a quality status, release, beta or alpha, and the packaged baseline scan leaves alpha passive rules out unless you pass -a, since less mature rules produce more false positives.

Three spiders for different applications

The traditional spider parses HTML responses for links and forms. It is fast but misses routes that only exist in JavaScript. The AJAX spider drives a real browser through Selenium and clicks through the user interface. The Client spider, included as standard since ZAP 2.16, also launches browsers but adds a ZAP browser extension that streams DOM events back, so it can find content the AJAX spider cannot. ZAP’s own getting started guide now recommends the Client spider for modern applications and says the AJAX spider is no longer recommended in most cases. Spiders only enter basic default data into forms, so a registration form that needs a valid email address may stop them; manual exploration fills those gaps.

A small core and many add-ons

Most of ZAP’s functionality ships as add-ons that update independently of the core: scan rule packs, the spiders, the fuzzer, reporting, the Automation Framework, authentication helpers, and in 2.16 even the passive scanner moved out of the core. Full releases are infrequent, 2.16.0 in January 2025 and 2.17.0 on 15 December 2025, while add-ons and a weekly build move faster. The practical consequence is that two installations of the same ZAP version can behave differently if their add-ons differ, so automated runs should pin a Docker image or update add-ons deliberately with -addonupdate, rather than drifting.

Strengths

What it does well

Packaged scans in Docker

The stable Docker image includes three scripts. zap-baseline.py spiders for a minute by default and reports passive findings without attacking. zap-full-scan.py spiders without a time limit and runs a full active scan. zap-api-scan.py imports an OpenAPI, SOAP or GraphQL definition and actively scans the endpoints. A tab-separated rules file sets each rule to IGNORE, INFO, WARN or FAIL, which is how a team turns a raw report into a build gate.

The Automation Framework

One YAML plan, run with zap.sh -cmd -autorun, defines contexts, authentication, users and an ordered list of jobs: spider, spiderClient, passiveScan-wait, activeScan, alertFilter, report and exitStatus among them. Plans read environment variables, so secrets stay outside the file, and -autogenmin generates a commented template to start from. The docs describe it as the route that will in time exceed the packaged scans, which are being migrated onto it.

Authentication and session handling

Contexts can log in with form, JSON, HTTP, script, browser-based or auto-detected authentication, verify the session with regular expressions or polling, and handle cookie, header or script-based session management. Browser-based authentication can complete TOTP second factors. For simple token APIs, the ZAP_AUTH_HEADER_VALUE environment variable adds a header to every request, which is often the quickest way to get past the login page.

API scanning from definitions

Import jobs for OpenAPI, GraphQL, SOAP and Postman load every documented endpoint into the Sites tree, so the active scanner reaches operations no spider would find. For teams whose main surface is an API rather than a web page, this is the most useful way to run ZAP, and it pairs naturally with an existing API definition kept in the repository.

Manual testing tools

Beyond scanning, ZAP is a capable manual testing proxy: breakpoints to intercept and edit requests, a fuzzer with payload sets and processors, encode and decode utilities, and scripts in JavaScript (Graal.js), Groovy or Kotlin through add-ons. The HUD overlays ZAP’s controls on the application in the browser. These tools make ZAP useful to testers exploring a feature, not only to pipelines.

Reports and triage aids

The report job writes HTML, JSON, Markdown and SARIF, the format GitHub code scanning reads. ZAP 2.17 added alert de-duplication aligned with the Sites tree, flags site-wide header problems as systemic so they are reported once with examples rather than per page, and adds Insights, which report on the application and on how effective the scan was, flag problems such as low disk space, and can stop a scan early.

Pricing

OWASP ZAP pricing and licensing

ZAP is free and open source under the Apache 2.0 licence, and the Checkmarx announcement in September 2024 said it would remain so. There are no paid tiers of ZAP itself and no features held back. The costs are the infrastructure to run it, CI minutes for scans that can take hours, and the engineering time to configure authentication and triage findings. Commercial products built on ZAP exist, including Checkmarx DAST, and ZAP’s third-party listing names other vendors; those are separate products with their own pricing.

  • Licence: Apache 2.0 for ZAP and its add-ons, confirmed in the September 2024 Checkmarx announcement on zaproxy.org.
  • No tiers: the desktop, Docker images, packaged scans, Automation Framework, API and GitHub Actions are all free, with no account.
  • Infrastructure: active and full scans take long enough on a large application that they are usually scheduled nightly on a dedicated runner rather than run on every pull request.
  • Hidden cost: authenticated scanning and alert triage. Expect to spend more time on login configuration and rules files than on running scans.
  • Commercial options: Checkmarx DAST is listed on zaproxy.org as a commercial service built on ZAP; it is priced by Checkmarx and is not required to use ZAP.

Checked against the vendor’s own pages on 13 October 2026. Pricing changes; confirm on the official site before buying.

Getting started

OWASP ZAP tutorial: getting started

Setup, step by step

  1. Confirm in writing that you are authorised to scan the target, and prefer a staging copy over production.
  2. Install Docker, or install ZAP 2.17 from zaproxy.org; the desktop needs Java 17 except on macOS, where it is bundled.
  3. Pull the stable image: docker pull ghcr.io/zaproxy/zaproxy:stable.
  4. Run a baseline scan against the target with -g to generate a rules file and -r to write an HTML report.
  5. Read the report, then edit the rules file to IGNORE, WARN or FAIL each rule for your application.
  6. Re-run with -c and the edited rules file so the exit code reflects what your team actually cares about.

Install

docker pull ghcr.io/zaproxy/zaproxy:stable
# or Docker Hub: docker pull zaproxy/zap-stable

A first example

# Passive baseline scan of an application you are authorised to test.
# Spiders for one minute, then reports passive findings; no attacks are sent.
docker run --rm -v $(pwd):/zap/wrk/:rw -t ghcr.io/zaproxy/zaproxy:stable \
  zap-baseline.py -t https://staging.example.com \
  -g rules.tsv \
  -r baseline-report.html

# Exit codes: 0 pass, 1 at least one FAIL, 2 WARNs but no FAILs, 3 other error.
# Edit rules.tsv (WARN to IGNORE or FAIL), then gate on it:
docker run --rm -v $(pwd):/zap/wrk/:rw -t ghcr.io/zaproxy/zaproxy:stable \
  zap-baseline.py -t https://staging.example.com -c rules.tsv -r baseline-report.html

What trips people up first

Scanning the login page. The first scan of a real application usually reports a handful of header alerts and nothing else, because the spider could not get past authentication and every interesting page went unseen. Check the Sites tree or the report’s URL list before trusting a result. The quickest fix for token-based APIs is the ZAP_AUTH_HEADER_VALUE environment variable, which adds an Authorization header to every request. For form or browser logins, define a context with an authentication method, a logged-in or logged-out indicator and a user, in an Automation Framework plan, and confirm that authenticated pages appear in the Sites tree before trusting the result.

In practice

Using OWASP ZAP in practice

Contexts, scope and permission

A context tells ZAP what belongs to the application: the top-level URLs, include and exclude path regexes, the authentication method, the users and the technology in use. Define one per application and keep it in the plan file, not in someone’s desktop session. Exclude logout links so the spider does not end its own session, exclude anything that sends real emails, payments or messages, and exclude third-party domains you are not authorised to test, such as payment providers and analytics. Scope is also a safety control: the active scanner attacks what is in scope, so a careless include pattern can aim attacks at a system you have no permission to touch. Record the written authorisation for each target alongside the plan.

An Automation Framework plan for staging

A plan runs its jobs top to bottom. The usual order is: spider the context, wait for passive scanning to finish, actively scan, write reports, then set the exit status. The exitStatus job turns alert risk levels into exit codes, here a warning for Medium and an error for High, which is what makes the plan usable as a gate. maxDuration and maxScanDurationInMins keep a nightly run bounded. Variables written as ${NAME} read operating system environment variables, so the target and credentials come from CI secrets. Run it with zap.sh -cmd -autorun zap.yaml, or in Docker with the working directory mounted at /zap/wrk.

# zap.yaml: an active scan, for a staging app you are authorised to attack
env:
  contexts:
    - name: staging
      urls:
        - ${TARGET_URL}
      excludePaths:
        - '.*/logout.*'
  parameters:
    failOnError: true
    progressToStdout: true
jobs:
  - type: spider
    parameters:
      maxDuration: 5            # minutes
  - type: passiveScan-wait
    parameters:
      maxDuration: 10
  - type: activeScan            # sends real attack payloads
    parameters:
      maxScanDurationInMins: 60
  - type: report
    parameters:
      template: traditional-html
      reportDir: /zap/wrk
      reportFile: zap-report
  - type: exitStatus            # Medium alerts warn, High alerts fail
    parameters:
      warnLevel: Medium
      errorLevel: High

Gating pull requests in GitHub Actions

Split the work by cost. On pull requests, run the passive baseline against a preview or staging deployment: it takes minutes and sends no attacks. Nightly, run the Automation Framework plan with the active scan against a disposable environment. The official zaproxy/action-baseline (v0.15.0) wraps the baseline script and by default opens or updates a GitHub issue with the findings and does not fail the job. Set fail_action to true to make it a gate, point rules_file_name at your tuned rules file, and set allow_issue_writing to false if you would rather read the uploaded report. zaproxy/action-af (v0.3.0) runs a plan file the same way and exits with the plan’s exit code.

# .github/workflows/zap.yml
name: zap
on:
  pull_request:
  schedule:
    - cron: '0 1 * * *'
jobs:
  baseline:
    if: github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: zaproxy/[email protected]
        with:
          target: ${{ vars.STAGING_URL }}
          rules_file_name: '.zap/rules.tsv'
          fail_action: true           # off by default: the job would pass
          allow_issue_writing: false
  nightly:
    if: github.event_name == 'schedule'
    runs-on: ubuntu-latest
    env:
      TARGET_URL: ${{ vars.STAGING_URL }}
    steps:
      - uses: actions/checkout@v7
      - uses: zaproxy/[email protected]
        with:
          plan: '.zap/zap.yaml'
          docker_env_vars: |
            TARGET_URL

Scanning an API from its definition

For a JSON API, skip the spider and give ZAP the definition. zap-api-scan.py imports an OpenAPI, SOAP or GraphQL definition from a file or URL and actively scans every operation, which reaches endpoints a crawler would never find. Because it is an active scan, point it only at an environment you are authorised to attack, and seed that environment with data that can be damaged. Supply authentication with ZAP_AUTH_HEADER_VALUE, or ZAP_AUTH_HEADER for a custom header name, and limit it to the API host with ZAP_AUTH_HEADER_SITE so the token is not sent elsewhere. Keep the definition in the repository so the scan follows the API as it changes.

# Active scan of every operation in an OpenAPI definition.
# Only run against an API you are authorised to attack.
docker run --rm -v $(pwd):/zap/wrk/:rw \
  -e ZAP_AUTH_HEADER_VALUE="Bearer $API_TOKEN" \
  -e ZAP_AUTH_HEADER_SITE="api.staging.example.com" \
  -t ghcr.io/zaproxy/zaproxy:stable \
  zap-api-scan.py -t https://api.staging.example.com/openapi.json \
  -f openapi -c rules.tsv -r api-report.html

Triage, false positives and keeping it useful

A scan nobody reads is worse than none, because it creates the impression of coverage. Review the first reports with a developer, and record each decision where the scan can use it: IGNORE or FAIL in the packaged-scan rules file, or an alertFilter job in a plan that marks a specific rule and URL as a false positive or changes its risk. Prefer narrow filters, a rule plus a URL pattern, over ignoring a rule everywhere. Use ZAP 2.17’s systemic alerts and de-duplication to keep header findings to one line each. Read the Insights section for signs that a scan ran into trouble, and compare URL counts between runs: a sudden drop usually means the spider or authentication broke, not that the application shrank.

Pitfalls

Common pitfalls

Active scanning a system you are not authorised to test

Why it happens: Full scans, API scans and the active scan job send real attack payloads. Pointed at production or a third-party service, they can corrupt data, trigger alerts and breach contracts or law.

The fix: Get written authorisation for every target, scan a disposable staging copy, exclude third-party domains from the context, and keep production to the passive baseline only if its owner agrees.

Unauthenticated scans reported as full coverage

Why it happens: Without working authentication the spider sees the public pages and the login form, so most of the application is never tested while the report still looks complete.

The fix: Configure authentication in the context or with ZAP_AUTH_HEADER_VALUE, check the Sites tree and Insights for authenticated pages, and add a job test or URL check that fails when they are missing.

A baseline action that never fails the build

Why it happens: zaproxy/action-baseline defaults fail_action to false and reports findings as a GitHub issue, so the workflow stays green whatever ZAP finds.

The fix: Set fail_action to true and supply a tuned rules file so only rules marked FAIL, or unhandled WARNs, break the build.

Following tutorials written for older ZAP

Why it happens: Older guides use the owasp/zap2docker-stable image, which stopped receiving updates in 2024, or the softwaresecurityproject Docker organisation, dropped from 2.16. Nashorn scripts no longer run since ZAP 2.16 requires Java 17, and the Automation Framework addOns job is deprecated.

The fix: Use ghcr.io/zaproxy/zaproxy:stable or zaproxy/zap-stable, migrate scripts to Graal.js, and update add-ons with -addonupdate on the command line instead of the addOns job.

The traditional spider missing a single page app

Why it happens: It only follows links found in HTML, and a JavaScript-rendered application exposes few of them, so whole sections never enter the Sites tree.

The fix: Use the Client spider, which ZAP now recommends for modern applications, import an API definition, or explore the app manually through ZAP before scanning.

Treating a clean report as proof of security

Why it happens: Automated scanning finds known patterns. It cannot judge business logic, whether one user can read another’s data, or multi-step attacks, which are among the most serious findings in practice.

The fix: Position ZAP as a regression net for known classes, and keep periodic manual security testing by specialists for access control, logic and design flaws.

Compared

OWASP ZAP alternatives compared

ToolApproachLicence and costAutomated scannerManual testing toolsCI automation
OWASP ZAPDynamic, against a running applicationApache 2.0, freePassive and active, freeProxy, breakpoints, fuzzer, HUDDocker scans, YAML plans, GitHub Actions
Burp SuiteDynamic, against a running applicationPaid per user; free Community editionProfessional edition onlyProxy, Repeater, Intruder, CollaboratorSeparate Burp Suite DAST product
SonarQubeStatic analysis of source codeFree Community Build; paid editions by LOCCode analysis, not attack trafficNoneScanner in CI with quality gates

FAQ

Frequently asked questions

What is OWASP ZAP?

ZAP (Zed Attack Proxy) is an open-source intercepting proxy and dynamic application security scanner for web applications and APIs. It passively inspects traffic, crawls with three spiders, actively attacks discovered endpoints, and automates through Docker scans, a YAML Automation Framework and an API. Formerly an OWASP project, it is now independent, controlled by its core team and supported by Checkmarx, under the Apache 2.0 licence.

What are the best OWASP ZAP alternatives?

The alternatives most often weighed against OWASP ZAP are Burp Suite and SonarQube. The comparison on this page sets them side by side on approach, licence and cost, automated scanner, manual testing tools and ci automation, and the verdict above says where OWASP ZAP is the wrong choice and which of them to pick instead.

Is ZAP free?

Yes. ZAP is open source under the Apache 2.0 licence, with no paid edition or locked features: the desktop, scanners, fuzzer, API, Docker images, Automation Framework and GitHub Actions are all free. Checkmarx, which employs three of the core team, said in 2024 that ZAP would remain open source under Apache 2.0. Your costs are infrastructure, CI time and the effort of configuration and triage.

Is ZAP still an OWASP project?

No. ZAP left OWASP in 2023 and joined the Software Security Project, a then-new Linux Foundation initiative, at which point “OWASP ZAP” became simply “ZAP”. In September 2024 the core team joined forces with Checkmarx, and the tool is now branded “ZAP by Checkmarx”. ZAP’s ownership page describes it as an independent open-source project controlled by the ZAP Core Team and not part of any foundation.

Should I use ZAP or Burp Suite?

They overlap but suit different people. ZAP is free, scriptable and designed to run unattended, so it is the usual choice for automated scanning in CI. Burp Suite Professional is the more common choice for manual penetration testing, with Repeater, Intruder and Collaborator as its strengths, and its automated scanner is a paid feature. Many organisations run ZAP in the pipeline and use Burp for periodic manual testing.

Is it safe to run ZAP against production?

The passive baseline scan sends no attacks and its documentation describes it as suitable for CI, even against production sites, provided you have permission. Active scans, full scans and API scans are real attacks that can modify or delete data and trigger security alerts, so run them only against systems you are authorised to attack, preferably a disposable staging copy with test data.

Can ZAP scan authenticated pages?

Yes, with configuration. Contexts support form, JSON, HTTP, script, browser-based and auto-detected authentication, with session verification and multiple users, and browser-based authentication can handle TOTP. For APIs that accept a bearer token, setting ZAP_AUTH_HEADER_VALUE before ZAP starts adds the header to every request. Always confirm authentication worked by checking which URLs were reached.

What changed in ZAP 2.17?

ZAP 2.17.0, released on 15 December 2025, reduces duplicate alerts by aligning them with the Sites tree, flags site-wide issues as systemic, adds an Insights tab and report section, handles disk and memory problems more gracefully, and stops keeping temporary active scan messages by default when headless. JSON and XML reports gained an ISO 8601 created field; the older generatedString field is due to be removed, so update any report parsers.

How do I reduce false positives in ZAP?

Tune rather than ignore wholesale. In the packaged scans, generate a rules file with -g and set individual rules to IGNORE, INFO, WARN or FAIL, with OUTOFSCOPE patterns for specific URLs. In Automation Framework plans, use the alertFilter job to mark a rule on a URL or parameter as a false positive or change its risk. Leave alpha rules off unless you are prepared to review their output.

Alternatives

OWASP ZAP alternatives worth weighing

Resources

Where to go next

Keep going

Prepare, or get it done

Ready

Picking the wrong tool costs more than picking late.

QAble advises on toolchain decisions and then implements them, with engineers who have run these tools on real delivery. Start with a free QA audit.

Talk to QA Advisor