OWASP Zed Attack Proxy (ZAP) is a free, open-source web application security scanner maintained under the OWASP (Open Web Application Security Project) umbrella, now stewarded by the Zaproxy team. It functions similarly to Burp Suite — as an intercepting proxy — but is fully open source, making it a popular choice for organizations that cannot license Burp Professional. ZAP supports both a full desktop GUI and a headless/daemon mode with a REST API, making it well suited for CI/CD pipeline integration. Core capabilities include automated spidering, AJAX spidering (for JavaScript-heavy apps), active and passive scanning, fuzzing, and a scripting console supporting multiple languages.
How to Install
# Kali Linux - preinstalled, but to install/update:
sudo apt update
sudo apt install zaproxy -y
# Verify installation
zaproxy -version
Alternative: install via the official cross-platform installer or Docker:
# Docker (stable release)
docker pull zaproxy/zap-stable
docker run -it zaproxy/zap-stable zap-baseline.py -t https://example.com
Snap package (Ubuntu/Debian derivatives):
sudo snap install zaproxy --classic
Syntax
zap.sh [options]
zap-baseline.py -t <target_url> [options]
zap-full-scan.py -t <target_url> [options]
zap-api-scan.py -t <api_definition_url> [options]
All Command-Line Options
GUI/daemon launcher (zap.sh):
| Option | Description |
|---|---|
-daemon | Run ZAP as a background daemon (no GUI) |
-port <port> | Set the proxy/API port (default 8080) |
-host <host> | Bind ZAP to a specific host/interface |
-config <key=value> | Set a configuration parameter (e.g., API key) |
-dir <path> | Set the ZAP home directory |
-cmd | Run in command-line mode |
-quickurl <url> | Quickly scan a single URL |
-quickout <path> | Output path for quick scan report |
Docker automation scripts:
| Script | Purpose |
|---|---|
zap-baseline.py | Passive scan only, spiders briefly, safe for production |
zap-full-scan.py | Full active + passive scan, more intrusive |
zap-api-scan.py | Scans REST/SOAP/GraphQL APIs from a definition file |
Common flags for automation scripts:
| Flag | Description |
|---|---|
-t <url> | Target URL |
-r <file> | Output HTML report filename |
-J <file> | Output JSON report filename |
-x <file> | Output XML report filename |
-m <minutes> | Max spider time in minutes |
-T <minutes> | Max overall scan time |
-a | Include the ajax spider |
-d | Show debug messages |
-I | Do not return failure on warnings |
-j | Use ajax spider instead of traditional spider |
-z <options> | Pass raw ZAP options string |
Basic Usage (Expected Output in Bash)
$ zap.sh -daemon -port 8090 -config api.disablekey=true
Output:
[main] INFO org.zaproxy.zap.ZAP - Loading configuration...
[main] INFO org.zaproxy.zap.ZAP - ZAP is now listening on 0.0.0.0:8090
OWASP ZAP 2.15.0 started as daemon
Practical Examples with Output
Example 1 — Baseline passive scan via Docker
$ docker run --rm -t zaproxy/zap-stable zap-baseline.py -t https://example.com
Output:
PASS: Absence of Anti-CSRF Tokens (10202)
WARN: X-Content-Type-Options Header Missing (10021) x 3
WARN: Server Leaks Version Information (10036) x 1
FAIL-NEW: 0 FAIL-INPROG: 0 WARN-NEW: 2 WARN-INPROG: 0
Example 2 — Full active scan with HTML report
$ zap-full-scan.py -t https://testphp.vulnweb.com -r zap-full-report.html
Output:
Total of 47 URLs
PASS: SQL Injection (40018)
FAIL-NEW: 1 Cross Site Scripting (Reflected) (40012)
Report saved to zap-full-report.html
Example 3 — Start daemon and access via REST API
$ zap.sh -daemon -port 8090 -config api.key=abc123 &
$ curl "http://localhost:8090/JSON/core/view/version/?apikey=abc123"
Output:
{"version":"2.15.0"}
Example 4 — Trigger a spider scan via API
$ curl "http://localhost:8090/JSON/spider/action/scan/?apikey=abc123&url=https://example.com"
Output:
{"scan":"0"}
Example 5 — Check spider scan progress
$ curl "http://localhost:8090/JSON/spider/view/status/?apikey=abc123&scanId=0"
Output:
{"status":"45"}
Example 6 — Retrieve discovered URLs
$ curl "http://localhost:8090/JSON/spider/view/results/?apikey=abc123&scanId=0" | jq .
Output:
{"results":["https://example.com/","https://example.com/login","https://example.com/about"]}
Example 7 — Run active scan via API
$ curl "http://localhost:8090/JSON/ascan/action/scan/?apikey=abc123&url=https://example.com&recurse=true"
Output:
{"scan":"1"}
Example 8 — Generate JSON report from CLI
$ zap-baseline.py -t https://example.com -J zap-report.json
$ cat zap-report.json | jq '.site[0].alerts | length'
Output:
7
Example 9 — Scan an OpenAPI/Swagger definition
$ zap-api-scan.py -t https://api.example.com/openapi.json -f openapi -r api-report.html
Output:
Importing OpenAPI definition from https://api.example.com/openapi.json
PASS: Format String Error (90020)
WARN-NEW: 1 Missing Anti-clickjacking Header (10020)
Report saved to api-report.html
7. Common Use Cases
- CI/CD pipeline DAST scanning of staging environments using
zap-baseline.py. - Full manual and automated web application penetration testing via the ZAP desktop GUI.
- REST/SOAP/GraphQL API security testing with
zap-api-scan.py. - Ad-hoc quick scanning of a single URL for a fast risk snapshot.
- Scripted regression security testing integrated into Jenkins/GitLab CI pipelines.
Automation with Bash
#!/bin/bash
# zap-ci-scan.sh — run a ZAP baseline scan in CI and fail the build on high-risk findings
TARGET="$1"
REPORT="zap-report-$(date +%Y%m%d-%H%M%S).html"
if [ -z "$TARGET" ]; then
echo "Usage: $0 <target_url>"
exit 1
fi
docker run --rm -v "$(pwd):/zap/wrk/:rw" -t zaproxy/zap-stable \
zap-baseline.py -t "$TARGET" -r "$REPORT" -I
EXIT_CODE=$?
if [ $EXIT_CODE -eq 0 ]; then
echo "[+] No blocking issues found. Report: $REPORT"
else
echo "[!] ZAP found issues. Review $REPORT before deploying."
fi
exit $EXIT_CODE
9. Tips and Best Practices
- Use
zap-baseline.pyfor production/staging environments (non-intrusive); reservezap-full-scan.pyfor isolated test environments. - Always set an API key (
api.key=...) when exposing the daemon’s REST API beyond localhost. - Use the AJAX Spider (
-j) for Single Page Applications (React/Angular/Vue) since the traditional spider cannot execute JavaScript. - Authenticate ZAP sessions (via Context + Authentication scripts) before scanning pages behind login to get meaningful coverage.
- Exclude logout URLs from scope to avoid the scanner invalidating its own session mid-scan.
Troubleshooting
| Issue | Cause | Fix |
|---|---|---|
Unauthorized API responses | Missing/incorrect API key | Pass apikey= param matching -config api.key= |
| Spider finds 0 URLs on SPA | JavaScript-rendered content not crawled | Use AJAX Spider (-j flag or ajaxSpider API) |
| Docker scan can’t reach target on localhost | Container network isolation | Use --network=host or the target’s routable IP, not localhost |
| Scan takes extremely long | No time limit set | Use -m and -T flags to cap spider/scan duration |
| Report file not created | Volume not mounted in Docker | Mount working dir with -v $(pwd):/zap/wrk/:rw |
References
- Official site: https://www.zaproxy.org/
- Documentation: https://www.zaproxy.org/docs/
- Docker automation guide: https://www.zaproxy.org/docs/docker/
- Kali tool page: https://www.kali.org/tools/zaproxy/