zap¶
Drives OWASP ZAP for web-application scanning: crawl a target, passively analyse what the crawl saw, then optionally run ZAP's intrusive active scan and collect the alerts.
Active scanning modifies target state
spider_start and active_scan_start send real traffic, and an active scan
submits forms, fuzzes parameters, and can change or destroy data. Run them
only against targets you are explicitly authorized to test.
Parameters¶
| Parameter | Type | Default | Applies to |
|---|---|---|---|
action |
see below | required | — |
target |
string | — | Required for spider_start and active_scan_start; an optional base-URL filter for alerts. Must be an absolute http(s) URL. |
scan_id |
string | — | Required for the *_status actions and scan_stop. Returned by a start action. |
scan_kind |
spider | active |
— | Required by scan_stop, to say which kind of scan the id belongs to. |
recurse |
boolean | true |
Crawl or scan child resources. |
subtree_only |
boolean | true |
spider_start. Keep crawling below the target path. |
max_children |
integer | — | spider_start. Cap children per node. |
in_scope_only |
boolean | false |
active_scan_start. Restrict to URLs already in ZAP's configured scope. Leave false unless you have configured a ZAP context. |
scan_policy |
string | — | active_scan_start. A named ZAP active-scan policy. |
start |
integer | 0 |
alerts. Zero-based result offset. |
count |
integer | 25 |
alerts. Maximum findings to return. |
Actions¶
| Action | What it does | Default approval |
|---|---|---|
status |
Validate the API and return the ZAP version. | Allowed |
spider_start |
Crawl the target, feeding responses through passive scanning. | Prompts |
spider_status |
Crawl progress, then wait for queued passive scanning. | Allowed |
active_scan_start |
Launch intrusive vulnerability tests against discovered resources. | Prompts |
active_scan_status |
Active-scan completion percentage. | Allowed |
alerts |
Retrieve normalized, bounded findings. | Allowed |
scan_stop |
Stop a spider or active scan by id. | Prompts |
The order matters. Spider first, wait for it to finish, then active-scan, so ZAP knows what resources exist before it starts testing them. An active scan against an uncrawled target tests almost nothing.
spider_status reports passive_scanning at 99% when crawling has reached 100%
but passive records are still queued, and reports completion only once the queue
drains. Treating 100% crawl as "done" collects alerts before passive analysis has
produced them.
Approval¶
An approval saved from a zap prompt widens to the action — starting a scan
is not the same grant as reading its status. The four read-only actions ship
auto-approved:
- allow: "zap({'action': 'status'})"
- allow: "zap({'action': 'spider_status'})"
- allow: "zap({'action': 'active_scan_status'})"
- allow: "zap({'action': 'alerts'})"
The three that send traffic — spider_start, active_scan_start, scan_stop —
are deliberately left to prompt.
The managed runtime¶
There is no setup command. The first approved spider_start or active_scan_start
starts ZAP for you: Kerkov generates a random API key, runs the official stable
ZAP Docker image, binds its API port to 127.0.0.1, waits for readiness, then
saves the key through the credential manager and the service URL to
~/.kerkov/settings.json. The next scan reuses that runtime.
Only those two actions auto-start. status against a ZAP that is not running
reports that it starts automatically with the first scan, rather than starting one
as a side effect of being asked a question.
How the key is handled:
- Streamed over stdin into a mode-
0600config file inside the container. It never appears in Docker argv, environment metadata, tool parameters, API URLs, ordinary logs, or user settings. - Sent in the
X-ZAP-API-Keyheader on every request.
How the container is isolated:
- Only ZAP's authenticated API listener is published. The unauthenticated forward proxy stays on container loopback.
- It runs on its own labeled bridge network with inter-container communication disabled.
- It carries an
org.kerkov.managed=zaplabel, and/zap stoprefuses to remove an unlabeled container that happens to share the name. - Docker's
--rmis deliberately not used, so a container that fails to start can have its logs captured before cleanup.
Stopping a Kerkov-managed runtime also removes its generated key, saved URL, and managed marker, so the next scan starts fresh. Credentials for an external ZAP are preserved.
Targets on loopback are rewritten to host.docker.internal — port, path and
query preserved — so ZAP does not scan its own container. On native Linux, a
target service must listen on an interface the Docker bridge can reach.
The Docker daemon must already be running. A failed start says which of the three things went wrong — the CLI is missing, the daemon is unreachable, or the user lacks daemon access — before any configuration is generated or saved.
EXECUTION_ENABLED=false blocks the managed start; an already-running external
ZAP still works.
Using an external ZAP¶
Point ZAP_API_URL at it and store its
key with /auth set zap. If that endpoint stops answering, Kerkov will only
replace it with a managed container when
ZAP_MANAGED=true and the URL is
loopback http://; otherwise the failure is reported rather than worked around,
so a scan never silently retargets from your ZAP to a fresh empty one.
Returns¶
Pretty-printed JSON as output — sorted keys, two-space indent — with
provider: "zap" and the action in metadata. Start actions return a scan_id; status actions return progress;
alerts returns normalized findings.
Alert fields and the total serialized response are both bounded. When the
response hits the budget, truncated is true and next_start gives the offset
for the next request — page with it rather than raising count.
Examples¶
Crawl, then watch it:
{ "action": "spider_start", "target": "http://10.10.10.5:8080/app/" }
{ "action": "spider_status", "scan_id": "0" }
Active-scan once the spider and its passive queue are done:
{ "action": "active_scan_start", "target": "http://10.10.10.5:8080/app/" }
{ "action": "active_scan_status", "scan_id": "1" }
Collect findings for one subtree:
{ "action": "alerts", "target": "http://10.10.10.5:8080/app/", "count": 25 }
Abandon a scan:
{ "action": "scan_stop", "scan_id": "1", "scan_kind": "active" }
Configuration¶
See OWASP ZAP for the full table:
ZAP_API_URL, ZAP_API_TIMEOUT_SECONDS, ZAP_API_VERIFY_TLS,
ZAP_API_ALLOW_REMOTE, ZAP_MANAGED, ZAP_STARTUP_TIMEOUT_SECONDS,
ZAP_DOCKER_IMAGE, ZAP_DOCKER_CONTAINER_NAME.
The /zap command shows runtime status and stops a
managed container.