ZAP security testing gives you a free, scriptable DAST stage: run the baseline scan on every merge for fast passive checks, run the full active scan nightly against staging, and gate builds only on rules you have tuned — that split is the difference between a scanner teams keep and one they disable within a month. ZAP has been the default open-source web scanner for over a decade; what changed recently is governance, not capability. The project left OWASP in 2023 for the Linux Foundation's Software Security Project, and in September 2024 the core team joined Checkmarx, rebranding as ZAP by Checkmarx. It remains open source and free, and the old owasp/zap2docker-* images are superseded by ghcr.io/zaproxy/zaproxy.
The three packaged scans
ZAP ships ready-made scan scripts inside its Docker image, and picking the right one per pipeline stage matters more than any other configuration choice.
Baseline scan — spiders the target and runs passive rules only. No attack payloads, so it is safe against fragile environments and fast (typically a few minutes):
docker run -v $(pwd):/zap/wrk:rw -t ghcr.io/zaproxy/zaproxy:stable \
zap-baseline.py -t https://staging.example.com \
-r baseline.html -J baseline.json
It catches missing security headers, cookie flag problems, information leakage, and mixed content. Run this on every merge.
Full scan — spider plus active attack rules: XSS payloads, SQL injection probes, path traversal, remote file inclusion attempts. Slower (twenty minutes to hours) and noisy against production, so aim it at staging on a schedule:
docker run -v $(pwd):/zap/wrk:rw -t ghcr.io/zaproxy/zaproxy:stable \
zap-full-scan.py -t https://staging.example.com -r full.html
API scan — imports an OpenAPI, GraphQL, or SOAP definition and attacks each operation directly, which beats crawling for API coverage:
docker run -v $(pwd):/zap/wrk:rw -t ghcr.io/zaproxy/zaproxy:stable \
zap-api-scan.py -t https://staging.example.com/openapi.json \
-f openapi -r api.html
For GitHub users, the official actions (zaproxy/action-baseline, zaproxy/action-full-scan) wrap these with artifact upload and issue creation.
Authentication: where most ZAP setups silently fail
An unauthenticated scan of an app that lives behind a login tests your login page and little else. Empty reports from such scans are routinely misread as "secure."
ZAP's Automation Framework (the YAML plan the packaged scans now build on) supports several authentication methods; the two that cover most real apps:
- Browser-based authentication: ZAP drives a headless browser through your actual login form, then captures the session. This survives most modern login implementations including JavaScript-heavy ones.
- Header/token injection: for APIs, mint a token in a pipeline step and pass it in:
env:
contexts:
- name: app
urls: ["https://staging.example.com"]
authentication:
method: "browser"
parameters:
loginPageUrl: "https://staging.example.com/login"
users:
- name: scanner
credentials:
username: "scanner@example.com"
password: "${SCAN_USER_PASSWORD}"
Two operational notes. First, create a dedicated scan user with realistic permissions; scanning as an admin both overstates and understates different risks. Second, add a verification URL ZAP can poll to confirm the session is still valid, because active scans commonly log themselves out mid-run (they submit every form they find, including the logout link) and then "pass" the rest of the scan unauthenticated.
Tuning: alert filters and rule configs
Untuned scanner output kills adoption. ZAP gives you two levers.
Rule configuration files let the packaged scans downgrade or ignore rules wholesale. Generate a starter with -g gen.conf, then edit:
10038 IGNORE (Content Security Policy header not set - tracked separately)
40018 FAIL (SQL Injection)
40012 FAIL (Cross Site Scripting - Reflected)
Alert filters (in the automation plan) work per-context and can match by URL pattern, so you can suppress a known-accepted finding on one endpoint without blinding the rule everywhere.
A sane maturity path: week one, everything WARN and nothing fails the build; week two onward, promote high-confidence injection and XSS rules to FAIL; keep configuration-hygiene rules as warnings feeding a backlog. Gating on everything from day one guarantees the stage gets bypassed.
Wiring results into work
A scan that ends in an HTML artifact nobody opens is theater. The JSON output (-J) is the integration point: parse it, deduplicate by rule-plus-root-cause, and route new findings into your tracker. Key fields are alerts[].pluginid, riskcode, and instances. Diff against the previous run so the team sees only deltas; re-announcing 40 known warnings every build trains everyone to ignore the stage.
This findings-lifecycle work — dedupe, regression detection, ownership, trend reporting — is precisely the layer where teams either invest scripting time or adopt a managed DAST platform that does it natively. Either is fine; having neither is how scanners die. For a comparison of ZAP against the alternatives at each tier, see our web application scanning tools guide.
Limits worth knowing
Honest expectations keep ZAP deployed:
- Logic flaws are out of scope. ZAP finds injectable parameters, not "user A can approve user A's own expense report."
- SPA crawling needs the AJAX spider and still benefits from an explicit URL seed list or API-spec-driven scanning.
- Active scans mutate state. They will submit forms, create records, and send emails if your staging can send email. Isolate the environment and stub outbound integrations.
- It only tests what is deployed. Pair it with dependency scanning; an SCA tool such as Safeguard catches the vulnerable library version before it is ever reachable over HTTP, which ZAP can only infer indirectly.
FAQ
Is ZAP still free after the Checkmarx move?
Yes. ZAP by Checkmarx remains open source and free to use; Checkmarx employs core maintainers but the project's licensing did not change.
Should ZAP security testing run against production?
Baseline (passive) scans: generally safe. Full active scans: avoid production — they submit forms, mutate data, and can trigger incident pages. Staging that mirrors production config is the right target.
How do I stop ZAP failing builds on trivia?
Use a rule configuration file to set noisy rules to WARN or IGNORE and reserve FAIL for tuned, high-confidence rules. Gate on the delta versus the last run, not on the absolute count.
Baseline scan or full scan for pull requests?
Baseline. It finishes in minutes and does not attack the environment. Full scans belong on a nightly or per-release schedule where a multi-hour runtime and state mutation are acceptable.