OWASP ZAP Tutorial 2026: Install, Configure & Scan the Free Web App Security Scanner

·

OWASP ZAP (the Zed Attack Proxy) is the most widely used free, open-source web application scanner. It sits between your browser and the target as an intercepting proxy, passively flags issues in every request it sees, and actively attacks the app on demand. Version 2.17.0 shipped in December 2025, raised the Java floor to 17, added first-pass JWT support, and has been re-mapping its scan rules to the OWASP Top 10:2025 categories through 2026.

This guide takes you from zero to an automated pipeline: install ZAP four different ways, trust its root CA so HTTPS traffic is readable, drive spider and active scans from the desktop, then convert that into headless Automation Framework runs wired into CI/CD. Every command is copy-pasteable. Only ever point ZAP at applications you own or are explicitly authorised to test.

◈ Table of Contents

01 What ZAP Is & Why It Matters 02 Prerequisites & Requirements 03 Method 1 — Native Install 04 Method 2 — Docker 05 Method 3 — Headless Server / VM 06 Initial Configuration 07 Core Config — Proxy & Scans 08 Integration — Auth, API, CI/CD 09 Advanced — Automation & API 10 Maintenance & Troubleshooting 11 Sources & References
🛰

01 · What ZAP Is & Why It Matters

Phase 1 / 11

ZAP is a DAST tool — Dynamic Application Security Testing. Unlike a SAST scanner that reads source code, ZAP tests the running application from the outside, exactly the way an attacker sees it. It works as a man-in-the-middle proxy: your browser (or an API client, or a CI job) sends traffic through ZAP, ZAP records and inspects every request and response, and it can replay, mutate, and fuzz those requests to surface vulnerabilities. Because it is stewarded under the OWASP umbrella and licensed Apache 2.0, it costs nothing and has no seat limits — which is why it dominates the free scanner space alongside Burp Suite Community.

Two scanning modes run in parallel. Passive scanning never sends anything of its own — it inspects the traffic that already passes through and raises alerts (missing security headers, cookie flags, information disclosure). Active scanning is intrusive: it injects payloads to test for SQL injection, cross-site scripting, path traversal, command injection and more. Passive is safe to run against anything you can browse; active scanning is an attack and must only be run against authorised targets.

🕷

DAST On A Budget

Full-featured dynamic scanning with zero licensing cost — the entry point for solo testers, students, and teams that cannot justify commercial tooling.

⚙

CI/CD Gate

The headless baseline and full scans plug into GitHub Actions, GitLab CI and Jenkins so every build gets a security pass before it ships.

🔌

API Security Testing

Import an OpenAPI, SOAP or GraphQL definition and ZAP scans every endpoint — no manual browsing of the API required.

🛡

Blue-Team Validation

Defenders use ZAP to confirm WAF rules fire, headers are enforced, and detections trigger — running the attack so the SOC can watch it land.

A defender should care because ZAP lets you see your own attack surface before someone else does. Point it at a staging deployment and it enumerates every reachable endpoint, flags weak TLS and header configuration, and generates payload traffic you can use to validate that your Sentinel or Splunk detections actually alert. The scan report doubles as a hunt list.

ZAP vs. the other free option
CapabilityOWASP ZAP 2.17Burp Suite Community
Cost / licenseFree, Apache 2.0, open sourceFree, closed source
Automated active scannerFull, unrestrictedNot included (Pro only)
Headless / CLI automationAutomation Framework + packaged scansLimited
CI/CD readyOfficial Docker + GitHub ActionsManual
API-driven controlFull REST + gRPC APIExtension only
Add-on marketplaceZAP MarketplaceBApp Store
What you will have by the end
  • ZAP installed and updated on your platform of choice
  • HTTPS traffic decrypted and readable through a trusted CA cert
  • A spidered, passively- and actively-scanned target with an HTML report
  • A repeatable headless scan running in Docker and in CI/CD
📋

02 · Prerequisites & Requirements

Phase 2 / 11

ZAP is a Java application, so the single hard dependency is a Java 17+ runtime. The Windows and macOS installers bundle their own JRE, so you only need to install Java separately when you use the cross-platform installer, the Linux package, or run in daemon mode from a shell. Everything below assumes a lab you control.

ComponentMinimumRecommended
CPU2 cores4+ cores rec
RAM4 GB8–16 GB rec
Disk1 GB free5 GB (sessions + reports grow)
JavaOpenJDK / JRE 17 minOpenJDK 17 or 21 LTS
OSWin 10, macOS 11, any modern LinuxKali/Ubuntu 24.04, Win 11
BrowserFirefox or ChromiumFirefox ESR for a clean proxy profile
TargetAn app you own / are authorised to testOWASP Juice Shop or DVWA in a VM
01
Confirm Java 17+ Is Present
Pre-flight

Before installing the cross-platform or Linux build, verify the runtime. If java -version reports 17 or higher you are set; anything lower (or "command not found") means you install a JDK first.

# Check the installed Java version (all platforms) $ java -version # Expected: openjdk version "17.0.x" or higher # Debian / Ubuntu / Kali — install OpenJDK 17 if missing $ sudo apt update && sudo apt install -y openjdk-17-jre # macOS via Homebrew $ brew install openjdk@17

The bundled installers ship a private JRE. Do not assume that JRE is on your PATH — daemon-mode and packaged-scan commands call the system Java, so a missing or old system JDK will break automation even when the GUI works.

02
Stand Up A Legal Practice Target
Lab

Never scan a site you do not control. The fastest deliberately-vulnerable target is OWASP Juice Shop — one container, ready in seconds — which every command in this guide can point at safely.

# Deliberately vulnerable target for practice — OWASP Juice Shop $ docker run --rm -d --name juice -p 3000:3000 bkimminich/juice-shop # Now reachable at http://localhost:3000

Active scanning sends real attack payloads. Running it against a system you are not authorised to test is illegal in most jurisdictions. Keep practice targets on an isolated host-only network.

💾

03 · Method 1 — Native / Bare-Metal Install

Phase 3 / 11

The native desktop app is the right choice for interactive testing — the full GUI, the Heads Up Display, manual request editing. Pick the path that matches your OS. All builds are signed and checksummed on the official download page; verify the checksum on anything you pull outside a package manager.

01
Windows — Installer & Package Managers
Windows

Download the Windows installer from zaproxy.org (it bundles Java), or install headlessly with winget, Chocolatey or Scoop. The package-manager route is best for scripted or repeated builds.

# Windows Package Manager (built into Windows 10/11) PS> winget install --id ZAP.ZAP # Chocolatey PS> choco install zap -y # Scoop (needs the extras bucket) PS> scoop bucket add extras; scoop install zap

The GUI installer also drops zap.bat in the install folder. Add that folder to PATH so you can launch daemon mode and packaged scans from any PowerShell prompt.

02
macOS — DMG & Homebrew Cask
macOS

Grab the Intel or Apple-Silicon DMG (Java is bundled), or install the Homebrew cask. On first launch macOS Gatekeeper may block the app; approve it once under System Settings.

# Homebrew cask — installs the ZAP.app bundle $ brew install --cask zap # If Gatekeeper blocks first launch, clear the quarantine attribute $ xattr -dr com.apple.quarantine /Applications/ZAP.app # Launch from CLI $ open -a ZAP
03
Linux — Cross-Platform Installer Script
Linux

The distro-agnostic route: download the Linux installer .sh, make it executable, and run it. This works on Ubuntu, Debian, Fedora, Arch — anything with Java 17. Use the headless flag -q for an unattended install.

# Download, verify, and run the cross-platform installer $ cd ~/Downloads $ chmod +x ZAP_2_17_0_unix.sh $ ./ZAP_2_17_0_unix.sh # interactive GUI installer $ ./ZAP_2_17_0_unix.sh -q -dir ~/zap # unattended into ~/zap # Launch the GUI $ ~/zap/zap.sh

Always validate the SHA-256 against the value on the release page before running an installer you downloaded from a browser: sha256sum ZAP_2_17_0_unix.sh.

04
Kali Linux — apt Repository
Kali

On Kali (and other pentest distros) ZAP is packaged as zaproxy in the default repos. This is the least-effort path if you are already on Kali, though the repo version can trail the official release by a point or two.

# Install from the Kali repositories $ sudo apt update && sudo apt install -y zaproxy # Launch from menu or terminal $ zaproxy

Distro packages often lag the upstream release. If you need the newest scan rules or the current Automation Framework schema, use the cross-platform installer or the Docker image instead.

05
Universal Linux — Flatpak & Snap
Sandboxed

For a sandboxed desktop install that auto-updates, use Flatpak or Snap. Note the sandbox restricts filesystem access, so reports save inside the sandboxed home — grant extra paths if you need reports elsewhere.

# Flatpak (from Flathub) $ flatpak install -y flathub org.zaproxy.ZAP $ flatpak run org.zaproxy.ZAP # Snap (classic confinement) $ sudo snap install zaproxy --classic
06
Verify The Install
Check

Regardless of method, confirm ZAP runs and reports its version. The -version flag prints the build and exits — the quickest smoke test for scripts.

# Print version and exit (path varies by install method) $ zap.sh -version # Expected output: 2.17.0 # On Kali $ zaproxy -version
Install complete when
  • The GUI launches and shows the session-persistence dialog
  • zap.sh -version prints 2.17.0 (or your repo's build)
  • Java errors are absent from the console on launch
🐳

04 · Method 2 — Docker

Phase 4 / 11

Docker is the correct way to run ZAP for automation, CI/CD, and clean repeatable scans — no Java to manage, and the image ships the packaged scan scripts and Automation Framework ready to go. The official images live on GitHub Container Registry (ghcr.io/zaproxy/zaproxy) and Docker Hub (zaproxy/zap-stable). Tags: stable (full release), weekly (latest features), bare (no add-ons, smallest).

01
Pull The Official Image
Pull

Pull the stable image once. It is regenerated on the first Monday of each month with the latest base OS and updated add-ons, so re-pull periodically to stay current.

# From GitHub Container Registry (primary) $ docker pull ghcr.io/zaproxy/zaproxy:stable # Or from Docker Hub $ docker pull zaproxy/zap-stable
02
Run The Full GUI In A Browser (Webswing)
GUI

The image can serve the complete desktop GUI over the web via Webswing — useful on a headless server. Port 8080 serves the UI; 8090 exposes the API.

# Serve the GUI over the browser, then open http://localhost:8080/zap $ docker run -u zap -p 8080:8080 -p 8090:8090 -i \ ghcr.io/zaproxy/zaproxy:stable zap-webswing.sh
03
Run Headless Daemon Mode
Daemon

Daemon mode runs ZAP as an API-only service — the backbone of scripted scanning. Bind the API to all interfaces inside the container and set an API key you will reuse from your client.

# Headless daemon exposing the API on 8090 with a fixed key $ docker run -u zap -p 8090:8090 -i ghcr.io/zaproxy/zaproxy:stable \ zap.sh -daemon -host 0.0.0.0 -port 8090 \ -config api.addrs.addr.name=.* \ -config api.addrs.addr.regex=true \ -config api.key=changeme-strong-key # Smoke-test the API from the host $ curl "http://localhost:8090/JSON/core/view/version/?apikey=changeme-strong-key"

Never expose the ZAP API to an untrusted network. The API can proxy and attack arbitrary hosts — treat an exposed, unauthenticated daemon as remote code execution against anything it can reach.

04
Packaged Scans — Baseline, Full, API
One-shot

The image ships three turnkey scan scripts. Baseline spiders and passive-scans only (safe, fast, CI-friendly). Full adds active scanning. API imports an OpenAPI/SOAP/GraphQL definition and scans the endpoints. Mount a working directory so reports land on the host.

# Baseline: passive-only, HTML report to the mounted dir $ docker run --rm -v $(pwd):/zap/wrk/:rw -t ghcr.io/zaproxy/zaproxy:stable \ zap-baseline.py -t http://localhost:3000 -r baseline-report.html # Full scan: baseline PLUS active attack payloads $ docker run --rm -v $(pwd):/zap/wrk/:rw -t ghcr.io/zaproxy/zaproxy:stable \ zap-full-scan.py -t http://localhost:3000 -r full-report.html # API scan against an OpenAPI definition $ docker run --rm -v $(pwd):/zap/wrk/:rw -t ghcr.io/zaproxy/zaproxy:stable \ zap-api-scan.py -t http://localhost:3000/api-docs/swagger.json -f openapi

The scripts exit non-zero when they find issues (WARN = 2, FAIL = 1). In CI, add -I to make informational/warn results non-blocking, or tune thresholds with a -c config file to gate the pipeline exactly how you want.

05
Docker Compose — ZAP + Target On One Network
Compose

A compose file wires the ZAP daemon and a target on a shared network so ZAP can reach the app by service name. Save this as docker-compose.yml and bring it up with docker compose up.

# docker-compose.yml — ZAP daemon + Juice Shop on a shared network services: zap: image: ghcr.io/zaproxy/zaproxy:stable container_name: zap user: zap command: > zap.sh -daemon -host 0.0.0.0 -port 8090 -config api.key=changeme-strong-key -config api.addrs.addr.name=.* -config api.addrs.addr.regex=true ports: - "8090:8090" volumes: - ./wrk:/zap/wrk:rw networks: [ appnet ] juice: image: bkimminich/juice-shop container_name: juice ports: - "3000:3000" networks: [ appnet ] networks: appnet: driver: bridge
# Bring the stack up, then scan via the internal service name $ docker compose up -d $ curl "http://localhost:8090/JSON/spider/action/scan/?apikey=changeme-strong-key&url=http://juice:3000" $ docker compose down
🖥

05 · Method 3 — Headless Server / VM

Phase 5 / 11

For a persistent shared scanner — a lab jump box, a scheduled scanning host, or a runner that other tools drive over the API — install ZAP on a Linux VM and run it as a long-lived daemon. You then connect the desktop GUI or CI jobs to that remote instance.

01
Provision The VM & Install
Ubuntu VM

On a fresh Ubuntu 24.04 VM, install Java and ZAP via the cross-platform script, then create a low-privilege user to run it. Never run the daemon as root.

# On the VM: Java + unattended ZAP install $ sudo apt update && sudo apt install -y openjdk-17-jre wget $ wget https://github.com/zaproxy/zaproxy/releases/download/v2.17.0/ZAP_2_17_0_unix.sh $ chmod +x ZAP_2_17_0_unix.sh && sudo ./ZAP_2_17_0_unix.sh -q -dir /opt/zap $ sudo useradd -r -s /usr/sbin/nologin zapsvc
02
Run As A systemd Service
Persistent

Wrap the daemon in a systemd unit so it survives reboots and restarts on failure. Bind the API to the VM's LAN interface only, behind a firewall rule that permits your workstation.

# /etc/systemd/system/zap.service [Unit] Description=OWASP ZAP daemon After=network.target [Service] User=zapsvc ExecStart=/opt/zap/zap.sh -daemon -host 0.0.0.0 -port 8090 \ -config api.key=changeme-strong-key \ -config api.addrs.addr.name=.* -config api.addrs.addr.regex=true Restart=on-failure [Install] WantedBy=multi-user.target
# Enable and start; restrict the API port to your subnet $ sudo systemctl daemon-reload && sudo systemctl enable --now zap $ sudo ufw allow from 192.168.56.0/24 to any port 8090 proto tcp
03
Drive The Remote Daemon
Remote

From your workstation, point curl or the ZAP client library at the VM's API. This is also how a remote GitHub/GitLab runner can share one scanning engine across jobs.

# Verify reachability, then run a spider from your laptop $ curl "http://192.168.56.20:8090/JSON/core/view/version/?apikey=changeme-strong-key" $ curl "http://192.168.56.20:8090/JSON/spider/action/scan/?apikey=changeme-strong-key&url=http://target.lab"

A daemon bound to 0.0.0.0 with a weak or default API key is a network-wide liability. Always pair it with a firewall allowlist and a long random api.key, and rotate the key if it leaks into CI logs.

⚙

06 · Initial Configuration — First Run

Phase 6 / 11

The first launch decides how ZAP stores your work and how aggressively it can attack. Get session persistence and scanning mode right before you touch a target, then trust the root certificate so HTTPS is readable.

01
Choose Session Persistence
First dialog

On launch ZAP asks whether to persist the session. For any real engagement, choose to persist so requests, alerts and history survive a crash. Ephemeral sessions are fine only for a throwaway look.

  • 1
    Yes, persist with name based on current timestamp — recommended default; auto-names the session file.
  • 2
    Yes, persist to a specific location — pick this to keep client engagements in separate, clearly named files.
  • 3
    No, do not persist — memory only; everything is lost on exit.
02
Set The Scanning Mode
Safety gate

The mode dropdown (top-left of the toolbar) is your safety switch. It governs what ZAP is permitted to do, regardless of what you click.

ModeBehaviour
SafeNo attacks possible at all — passive scanning only. Good for recon on prod.
ProtectedAttacks allowed only against URLs inside a defined scope. The safe default for real work.
StandardAttacks allowed against anything. Convenient in a lab, dangerous on shared networks.
ATTACKAutomatically active-scans new nodes as they are discovered. Aggressive; lab only.

Run in Protected mode with a defined scope for every authorised engagement. It makes it structurally impossible to accidentally attack an out-of-scope host you happened to browse through the proxy.

03
Generate & Export The Root CA Certificate
HTTPS

To read HTTPS traffic, ZAP presents its own dynamically-generated certificate for each site, signed by its root CA. Your browser must trust that root CA or every page throws a certificate error. Generate a fresh CA and export it.

GUI: Tools → Options → Network → Server Certificates → Generate → Save
# Export the root CA from the command line instead of the GUI $ zap.sh -cmd -certload ~/owasp_zap_root_ca.cer # load existing $ zap.sh -cmd -certpubdump ~/owasp_zap_root_ca.cer # dump the public cert
04
Trust The CA In Your Browser / OS
Trust

Import the exported .cer into the trust store the browser actually uses. Firefox has its own store; Chrome and Edge use the OS store.

  • FF
    Firefox: Settings → Privacy & Security → Certificates → View Certificates → Authorities → Import → tick "Trust this CA to identify websites".
  • CR
    Chrome/Edge: imports into the OS store — see the CLI below for Linux, or Keychain Access (macOS) / certmgr.msc (Windows).
# Linux system trust store (Debian/Ubuntu) $ sudo cp ~/owasp_zap_root_ca.cer /usr/local/share/ca-certificates/owasp_zap.crt $ sudo update-ca-certificates # macOS system keychain $ sudo security add-trusted-cert -d -r trustRoot \ -k /Library/Keychains/System.keychain ~/owasp_zap_root_ca.cer

Trusting the ZAP CA means anything holding its private key can silently decrypt your HTTPS. Only import it into a dedicated testing profile or browser, and remove it when you are done — never trust it in your day-to-day browser.

🎯

07 · Core Config — Proxy, Context & Scans

Phase 7 / 11

With the CA trusted, route traffic through ZAP, tell it what is in scope, then run the three-stage workflow every scan follows: discover (spider) → observe (passive) → attack (active).

01
Point A Browser At The Proxy
Proxy

ZAP listens on 127.0.0.1:8080 by default. Configure the browser to use it as an HTTP proxy — manually, or with a proxy-switcher extension so you can toggle it quickly.

# Launch Firefox with a dedicated proxied profile (no global change) $ firefox -no-remote -P zap-test # In that profile: Settings → Network Settings → Manual proxy # HTTP Proxy: 127.0.0.1 Port: 8080 [x] Also use for HTTPS # Change ZAP's own listen port if 8080 is taken: $ zap.sh -port 8081
02
Or Use ZAP's Built-In Browser & HUD
HUD

The simplest path for beginners: ZAP launches a pre-configured browser with the CA already trusted and the Heads Up Display overlaid on the page. No proxy config, no cert import.

  • 1
    Click the Firefox/Chrome browser button in the ZAP toolbar (top).
  • 2
    Browse the target normally — the HUD shows alerts, scan controls and site info as on-page overlays.
  • 3
    Use the HUD's spider and attack buttons directly, or drive everything from the main ZAP window.
03
Define A Context & Scope
Scope

A Context is ZAP's model of your target: which URLs belong to it, how to authenticate, which parameters to fuzz. Setting scope keeps active scanning surgical and prevents it wandering onto third-party domains.

GUI: Sites tree → right-click the target → Include in Context → New Context
  • 1
    Right-click the target node in the Sites tree and add it to a new Context.
  • 2
    Refine the include/exclude regex so only the app's own URLs are in scope.
  • 3
    Toggle the target-scope button so the display filters to in-scope traffic only.
04
Discover With The Spider
Spider

The traditional spider parses HTML and follows links to map the site. Run it first so the scanner knows what endpoints exist. Drive it from the GUI or the API.

# Kick off a traditional spider via the API and read progress $ curl "http://localhost:8090/JSON/spider/action/scan/?apikey=KEY&url=http://localhost:3000&recurse=true" # Returns {"scan":"0"} — poll status by scan id $ curl "http://localhost:8090/JSON/spider/view/status/?apikey=KEY&scanId=0"
05
Crawl JS Apps With The AJAX Spider
SPA

Single-page apps built on React, Angular or Vue render links in JavaScript that the traditional spider never sees. The AJAX Spider drives a real headless browser to click through the app and capture those routes.

# AJAX spider (browser-driven) for JavaScript-heavy targets $ curl "http://localhost:8090/JSON/ajaxSpider/action/scan/?apikey=KEY&url=http://localhost:3000&inScope=true" $ curl "http://localhost:8090/JSON/ajaxSpider/view/status/?apikey=KEY"

Always run the AJAX Spider on modern web apps before the active scan. If the endpoints are never discovered, they are never tested — and a "clean" report on an un-crawled SPA is dangerously misleading.

06
Read The Passive Scan Alerts
Passive

Passive scanning ran automatically on everything the spiders touched — no action needed. Review the Alerts tab: it flags missing headers (CSP, HSTS, X-Content-Type-Options), insecure cookie flags, and information leakage, colour-coded by risk.

# Pull the current alerts as JSON, grouped by risk $ curl "http://localhost:8090/JSON/core/view/alerts/?apikey=KEY&baseurl=http://localhost:3000" $ curl "http://localhost:8090/JSON/alert/view/alertsSummary/?apikey=KEY&baseurl=http://localhost:3000"
07
Launch The Active Scan
Active

The active scan is the attack phase — it injects payloads to test the discovered endpoints for injection, XSS, traversal and more. Run it only against in-scope, authorised targets. Then export a report.

# Start the active scan and export an HTML report when done $ curl "http://localhost:8090/JSON/ascan/action/scan/?apikey=KEY&url=http://localhost:3000&recurse=true&inScopeOnly=true" $ curl "http://localhost:8090/JSON/ascan/view/status/?apikey=KEY&scanId=0" $ curl "http://localhost:8090/OTHER/core/other/htmlreport/?apikey=KEY" -o zap-report.html

Active scanning can create, modify or delete data through the forms it fuzzes, and can knock fragile apps offline. Never run it against production, and snapshot lab databases before a full scan so you can roll back.

🔗

08 · Integration — Auth, API & CI/CD

Phase 8 / 11

A scan that only sees the login page finds nothing. Real value comes from authenticating ZAP into the app, scanning APIs directly, and running the whole thing automatically on every build.

01
Configure Authentication
Auth

In the Context, set an authentication method so ZAP can log in and hold a session while it scans. ZAP supports form-based, JSON, HTTP/NTLM, script-based, and (new in 2.17) improved token handling for JWT-bearing apps.

GUI: Context → Authentication → pick method → Users → add credentials
  • 1
    Choose the method (Form-based for classic apps, JSON for SPA/API logins).
  • 2
    Set the login URL, and the username/password field names from the login request.
  • 3
    Define Logged-in / Logged-out indicators — a regex ZAP uses to know if its session is still valid.
  • 4
    Add a User with real credentials, then set the scan to run "as user".
02
Scan An API From Its Definition
OpenAPI

You do not browse an API — you import its contract. ZAP's OpenAPI, SOAP and GraphQL add-ons read the definition and populate the Sites tree with every endpoint, ready to scan.

# Import an OpenAPI/Swagger definition via the API, then active-scan $ curl "http://localhost:8090/JSON/openapi/action/importUrl/?apikey=KEY&url=http://localhost:3000/api-docs/swagger.json" $ curl "http://localhost:8090/JSON/ascan/action/scan/?apikey=KEY&url=http://localhost:3000/api/&recurse=true"
03
Wire It Into GitHub Actions
CI/CD

The official ZAP GitHub Actions run a baseline or full scan on every push and open issues for findings. Drop this workflow into .github/workflows/zap.yml.

# .github/workflows/zap.yml — baseline DAST on every push name: ZAP Baseline on: [ push ] jobs: zap: runs-on: ubuntu-latest steps: - name: ZAP Baseline Scan uses: zaproxy/[email protected] with: target: 'https://staging.example.com' cmd_options: '-a' # include alpha passive rules

Commit a .zap/rules.tsv file to your repo to set per-rule thresholds (IGNORE / WARN / FAIL). It is how you suppress known false positives so the pipeline gate stays meaningful instead of being switched off.

04
Emit Machine-Readable Reports
Reports

Beyond HTML, ZAP exports SARIF, JSON, XML and Markdown. SARIF uploads straight into GitHub code-scanning; JSON feeds dashboards and ticketing.

# Generate a SARIF report through the report add-on API $ curl "http://localhost:8090/JSON/reports/action/generate/?apikey=KEY&template=sarif-json&reportFileName=zap.sarif&reportDir=/zap/wrk"
05
Feed Findings To The SIEM
Blue team

For defenders, the value loop is: run a controlled scan, then confirm the SOC saw it. ZAP's traffic should light up your WAF and detection rules — the JSON report gives you the exact timestamps and payloads to pivot on.

# Sentinel KQL — did the WAF/app log the scan traffic? (what this finds: ZAP UA + high 4xx rate) AppServiceHTTPLogs | where TimeGenerated > ago(1h) | where UserAgent has "ZAP" or UserAgent has "OWASP" | summarize hits=count(), errs=countif(ScStatus >= 400) by CsUriStem, CIp | order by hits desc
# Splunk SPL equivalent — surface the scanner's request burst index=web sourcetype=access_combined (useragent="*ZAP*" OR useragent="*OWASP*") | stats count AS hits, count(eval(status>=400)) AS errors by uri_path, clientip | sort - hits
🧪

09 · Advanced — Automation Framework & API

Phase 9 / 11

The Automation Framework is the modern way to codify a scan: one YAML file describes the target, the crawl, the scan policy and the reports, and ZAP runs it end-to-end headlessly. This is what you should version-control and hand to CI.

01
Write An Automation Framework Plan
YAML

Each YAML job runs in order: define the environment/context, spider, wait for passive scan, active-scan, then report. Save this as zap.yaml.

# zap.yaml — full spider → passive → active → report plan env: contexts: - name: target urls: [ "http://juice:3000" ] includePaths: [ "http://juice:3000.*" ] jobs: - type: spider parameters: { context: target, maxDuration: 5 } - type: spiderAjax parameters: { context: target, maxDuration: 5 } - type: passiveScan-wait parameters: { maxDuration: 5 } - type: activeScan parameters: { context: target, policy: "Default Policy" } - type: report parameters: template: traditional-html reportDir: /zap/wrk reportFile: af-report.html
02
Run The Plan Headlessly
Autorun

Execute the plan with -autorun. In Docker, mount the directory holding the YAML so ZAP can read the plan and write the report back to the host.

# Run the plan in Docker, reports land in ./ on the host $ docker run --rm -v $(pwd):/zap/wrk/:rw -t ghcr.io/zaproxy/zaproxy:stable \ zap.sh -cmd -autorun /zap/wrk/zap.yaml # Native install $ zap.sh -cmd -autorun ./zap.yaml

Generate a starter plan from your current GUI session — right-click the top of the Automation panel and export — then trim it. Hand-writing the YAML from scratch is the slow way.

03
Tune The Scan Policy
Policy

A scan policy decides which attack rules fire and how hard. Dialling threshold and strength trades speed against coverage — a targeted policy that skips irrelevant rules finishes far faster.

SettingEffect
Threshold: LowRaises more alerts, more false positives — thorough audits.
Threshold: HighOnly high-confidence alerts — noise-free CI gates.
Strength: InsaneSends the most payloads per rule — deepest, slowest.
Rule: disabledSkip rules irrelevant to the stack (e.g. no SQLi rule on a static site).
04
Extend With Marketplace Add-Ons
Add-ons

Nearly all ZAP capability ships as add-ons from the Marketplace — OpenAPI import, GraphQL, the report engine, extra active rules. Manage them from the GUI or the command line for reproducible images.

# List, install and update add-ons headlessly $ zap.sh -cmd -addoninstall openapi -addoninstall graphql $ zap.sh -cmd -addonupdate # update all installed add-ons $ zap.sh -cmd -addoninstallall # install every available add-on
05
Drive Everything Over The REST API
API

Every GUI action has an API equivalent, so you can build custom orchestration in any language. The API is browsable at http://localhost:8090 once the daemon is up. Endpoints come in JSON (actions/views) and OTHER (binary output like reports).

# A minimal end-to-end scan loop over the API $ KEY=changeme-strong-key; T=http://localhost:3000 $ curl -s "http://localhost:8090/JSON/spider/action/scan/?apikey=$KEY&url=$T" $ curl -s "http://localhost:8090/JSON/ascan/action/scan/?apikey=$KEY&url=$T" $ curl -s "http://localhost:8090/OTHER/core/other/jsonreport/?apikey=$KEY" -o result.json

The python-owasp-zap-v2.4 library (installed via pip install zaproxy) wraps this API cleanly, so orchestration scripts read like zap.spider.scan(target) instead of raw URLs.

🛠

10 · Maintenance & Troubleshooting

Phase 10 / 11

Keeping ZAP effective is mostly about staying current, giving it enough memory, and controlling false positives. Here is the maintenance rhythm and a fix table for the errors that stall first-time users.

01
Keep ZAP & Its Rules Current
Update

Scan rules ship in add-ons that update independently of the core. A monthly update keeps detection current; re-pull the Docker image monthly for the same reason.

# Update all add-ons (new scan rules, fixes) without a full reinstall $ zap.sh -cmd -addonupdate # Docker: pull the freshly-regenerated monthly image $ docker pull ghcr.io/zaproxy/zaproxy:stable
02
Give The JVM Enough Heap
Memory

Large sites and long scans exhaust the default heap and ZAP slows or crashes with OutOfMemory. Raise the maximum heap with a JVM flag.

# Allocate 4 GB max heap to ZAP $ zap.sh -Xmx4g # Docker: pass JVM options through the env var $ docker run -e ZAP_JVM_OPTS="-Xmx4g" -t ghcr.io/zaproxy/zaproxy:stable zap.sh -daemon
03
Control False Positives
Tuning

Every DAST tool produces false positives. Mark them once and ZAP remembers: right-click an alert → Mark as False Positive, or raise the rule threshold to High. In CI, encode these in the rules file so the gate stays honest.

Do not respond to noise by disabling the active scanner or lowering the whole policy — you will hide real findings with the false ones. Tune per-rule, not globally.

Common errors & fixes
SymptomCauseFix
"Failed to start" / no windowJava < 17 or noneInstall OpenJDK 17+; verify with java -version
Browser: certificate error on HTTPSZAP root CA not trustedExport the CA and import into the browser/OS trust store
No traffic shows in ZAPBrowser not proxied / wrong portSet proxy to 127.0.0.1:8080 or use ZAP's built-in browser
API returns "Bad API key"Missing/incorrect apikeyAppend ?apikey=KEY; check -config api.key
Active scan finds nothingApp never crawled / auth failedRun spider + AJAX spider; verify logged-in indicator
SPA links missingTraditional spider can't read JSRun the AJAX Spider (browser-driven)
OutOfMemoryError mid-scanDefault heap too smallLaunch with -Xmx4g (or more)
Docker report file not writtenWorking dir not mountedAdd -v $(pwd):/zap/wrk/:rw and write to /zap/wrk
CI job always failsWARN/FAIL exit codesAdd rules.tsv thresholds or -I to not fail on warnings
You have mastered ZAP when
  • You can install it on any platform and trust the CA in under five minutes
  • You crawl, passive- and active-scan an authenticated app end-to-end
  • The same scan runs unattended from a versioned Automation Framework YAML
  • It gates your CI pipeline and its traffic is visible in your SIEM
📚

11 · Sources & References

Phase 11 / 11

Primary documentation and release information used in this guide. Always confirm version-specific behaviour against the official docs for the build you install.

ZAP — Official Downloads & Checksums (zaproxy.org) ZAP — Getting Started Guide ZAP — Docker User Guide (baseline, full & API scans) ZAP — Automation Framework Documentation ZAP — Release Notes (v2.17.0, December 2025) Kali Linux — zaproxy Package OWASP — Zed Attack Proxy Project Page
🔗
Full ZAP Documentation Portal
zaproxy.org/docs — desktop UI, add-ons, API and automation reference
↗

◈ Put ZAP To Work

You now have a scanner that costs nothing and runs everywhere from your laptop to your build pipeline. Point it at your own staging apps, feed the findings into your detection stack, and validate that your SOC sees the attack. For more hands-on tooling walkthroughs and live threat intelligence, explore the CyberHawk Blog, browse the Live Tools, or run an artifact through the IOC Scanner. Only ever test systems you are authorised to assess.

◈ Stay Connected

Follow CyberHawk Threat Intel for threat intelligence, deployment guides and hands-on SOC tooling content.

🌐 Website ▶️ YouTube ▶️ YouTube (2) 𝕏 Twitter / X ♪ TikTok ✈️ Telegram
🔍 IOC Scanner 🛠️ Live Tools 📚 Courses 🚨 Threat Intel 📝 Blog 📋 SOPs

"They can't exploit you if you are the Exploit."