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
Phase 1 / 11ZAP 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.
| Capability | OWASP ZAP 2.17 | Burp Suite Community |
|---|---|---|
| Cost / license | Free, Apache 2.0, open source | Free, closed source |
| Automated active scanner | Full, unrestricted | Not included (Pro only) |
| Headless / CLI automation | Automation Framework + packaged scans | Limited |
| CI/CD ready | Official Docker + GitHub Actions | Manual |
| API-driven control | Full REST + gRPC API | Extension only |
| Add-on marketplace | ZAP Marketplace | BApp Store |
- 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 / 11ZAP 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.
| Component | Minimum | Recommended |
|---|---|---|
| CPU | 2 cores | 4+ cores rec |
| RAM | 4 GB | 8–16 GB rec |
| Disk | 1 GB free | 5 GB (sessions + reports grow) |
| Java | OpenJDK / JRE 17 min | OpenJDK 17 or 21 LTS |
| OS | Win 10, macOS 11, any modern Linux | Kali/Ubuntu 24.04, Win 11 |
| Browser | Firefox or Chromium | Firefox ESR for a clean proxy profile |
| Target | An app you own / are authorised to test | OWASP Juice Shop or DVWA in a VM |
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.
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.
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.
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 / 11The 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.
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.
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.
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.
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.
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.
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.
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.
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.
Regardless of method, confirm ZAP runs and reports its version. The -version flag prints the build and exits — the quickest smoke test for scripts.
- The GUI launches and shows the session-persistence dialog
zap.sh -versionprints 2.17.0 (or your repo's build)- Java errors are absent from the console on launch
04 · Method 2 — Docker
Phase 4 / 11Docker 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).
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.
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.
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.
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.
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.
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.
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.
05 · Method 3 — Headless Server / VM
Phase 5 / 11For 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.
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.
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.
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.
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 / 11The 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.
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.
- 1Yes, persist with name based on current timestamp — recommended default; auto-names the session file.
- 2Yes, persist to a specific location — pick this to keep client engagements in separate, clearly named files.
- 3No, do not persist — memory only; everything is lost on exit.
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.
| Mode | Behaviour |
|---|---|
| Safe | No attacks possible at all — passive scanning only. Good for recon on prod. |
| Protected | Attacks allowed only against URLs inside a defined scope. The safe default for real work. |
| Standard | Attacks allowed against anything. Convenient in a lab, dangerous on shared networks. |
| ATTACK | Automatically 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.
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.
Import the exported .cer into the trust store the browser actually uses. Firefox has its own store; Chrome and Edge use the OS store.
- FFFirefox: Settings → Privacy & Security → Certificates → View Certificates → Authorities → Import → tick "Trust this CA to identify websites".
- CRChrome/Edge: imports into the OS store — see the CLI below for Linux, or Keychain Access (macOS) / certmgr.msc (Windows).
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 / 11With 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).
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.
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.
- 1Click the Firefox/Chrome browser button in the ZAP toolbar (top).
- 2Browse the target normally — the HUD shows alerts, scan controls and site info as on-page overlays.
- 3Use the HUD's spider and attack buttons directly, or drive everything from the main ZAP window.
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.
- 1Right-click the target node in the Sites tree and add it to a new Context.
- 2Refine the include/exclude regex so only the app's own URLs are in scope.
- 3Toggle the target-scope button so the display filters to in-scope traffic only.
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.
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.
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.
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.
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.
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 / 11A 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.
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.
- 1Choose the method (Form-based for classic apps, JSON for SPA/API logins).
- 2Set the login URL, and the username/password field names from the login request.
- 3Define Logged-in / Logged-out indicators — a regex ZAP uses to know if its session is still valid.
- 4Add a User with real credentials, then set the scan to run "as user".
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.
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.
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.
Beyond HTML, ZAP exports SARIF, JSON, XML and Markdown. SARIF uploads straight into GitHub code-scanning; JSON feeds dashboards and ticketing.
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.
09 · Advanced — Automation Framework & API
Phase 9 / 11The 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.
Each YAML job runs in order: define the environment/context, spider, wait for passive scan, active-scan, then report. Save this as zap.yaml.
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.
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.
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.
| Setting | Effect |
|---|---|
| Threshold: Low | Raises more alerts, more false positives — thorough audits. |
| Threshold: High | Only high-confidence alerts — noise-free CI gates. |
| Strength: Insane | Sends the most payloads per rule — deepest, slowest. |
| Rule: disabled | Skip rules irrelevant to the stack (e.g. no SQLi rule on a static site). |
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.
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).
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 / 11Keeping 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.
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.
Large sites and long scans exhaust the default heap and ZAP slows or crashes with OutOfMemory. Raise the maximum heap with a JVM flag.
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.
| Symptom | Cause | Fix |
|---|---|---|
| "Failed to start" / no window | Java < 17 or none | Install OpenJDK 17+; verify with java -version |
| Browser: certificate error on HTTPS | ZAP root CA not trusted | Export the CA and import into the browser/OS trust store |
| No traffic shows in ZAP | Browser not proxied / wrong port | Set proxy to 127.0.0.1:8080 or use ZAP's built-in browser |
| API returns "Bad API key" | Missing/incorrect apikey | Append ?apikey=KEY; check -config api.key |
| Active scan finds nothing | App never crawled / auth failed | Run spider + AJAX spider; verify logged-in indicator |
| SPA links missing | Traditional spider can't read JS | Run the AJAX Spider (browser-driven) |
| OutOfMemoryError mid-scan | Default heap too small | Launch with -Xmx4g (or more) |
| Docker report file not written | Working dir not mounted | Add -v $(pwd):/zap/wrk/:rw and write to /zap/wrk |
| CI job always fails | WARN/FAIL exit codes | Add rules.tsv thresholds or -I to not fail on warnings |
- 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 / 11Primary documentation and release information used in this guide. Always confirm version-specific behaviour against the official docs for the build you install.
◈ 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.
"They can't exploit you if you are the Exploit."