Dynamic Application Security Testing
The developer CLI runs OWASP ZAP 2.17.0, pinned by its multi-architecture OCI digest, in Docker or
Podman. By default, it sequentially builds and scans HTTP and HTTPS variants of a separate full
OpAMP server deployment containing the provider, Config Editor, Config Catalog, Client Config
Generator, and Server Credentials plugins.
The ZAP image contains the scanner; no host-side Java or ZAP installation is required.
The command is intentionally separate from build secure: static checks can start from source,
whereas DAST needs a reachable runtime and a full scan sends attack payloads.
Prerequisites
- Install Docker Engine, Docker Desktop, or Podman.
- Use only a disposable deployment for a
fullscan. - Keep the ZAP API and target service away from untrusted networks.
The CLI selects OPAMP_CONTAINER_RUNTIME first, then Docker, then Podman. Use --runtime docker
or --runtime podman to make the selection explicit.
Scan The Isolated Full Application
Run a passive baseline from either PowerShell or a POSIX shell:
opamp-dev-cli build dast baseline
The command first builds and scans opamp-dast-full-app:local over HTTP. After that scan completes
successfully, it builds and scans opamp-dast-full-app-https:local over HTTPS. Each target uses the
locked server dependency set and installs only runtime dependencies. For each pass, the CLI creates
a unique private container network, starts the application without publishing a host port, waits
for its health check, runs ZAP on the same network, and then removes the application container and
network even when the scan fails. An HTTP failure stops the sequence before HTTPS starts.
ZAP uses http://opamp-dast-target:8080 for the first pass and
https://opamp-dast-target:8443 for the second. Host processes and host ports are not reachable
through this private alias, so an unrelated development server cannot become the scan target. The
runtime images do not contain source-checkout test tools, node_modules, coverage output,
/docs, or /dev-notes. The root .dockerignore also prevents those directories from entering
the build context.
The HTTPS image generates a short-lived, self-signed RSA test certificate during its Docker build.
Its subject alternative names cover opamp-dast-target, localhost, and 127.0.0.1. The private
key exists only inside the disposable image and is not stored in the repository or build context.
The HTTPS provider configuration references /app/tls/server.crt and /app/tls/server.key.
The scan hook seeds the provider UI and the Config Editor, Config Catalog, Client Config Generator, and Server Credentials pages before spidering. This ensures JavaScript-populated menu entries do not prevent the traditional spider from inspecting installed plugin surfaces.
Scan A Separately Managed Deployment
Use --external-target only when intentionally testing a deployment managed outside the DAST
command:
opamp-dev-cli build dast baseline \
--external-target \
--target http://host.docker.internal:8080 \
--scope host-provider
For Docker, the CLI adds host.docker.internal:host-gateway when that host alias is selected,
allowing the same external-target command to work on Windows and Linux. Ensure the selected port
belongs to the application and never point DAST at a repository-root static file server.
For a provider started directly on the host, bind it to a container-reachable interface before running the external scan:
python -m opamp_provider.server --host 0.0.0.0 --port 8080
Binding to 0.0.0.0 may expose the test service beyond the local machine. Retain an appropriate
host firewall and stop the service after testing.
Scan A Compose Deployment
When ZAP joins an existing container network, use the target service name and network-specific container options outside the CLI, or publish the service port to the host and use the default host gateway. The current CLI deliberately does not guess or mutate an existing Compose network. For the published-port approach:
opamp-dev-cli build dast baseline \
--external-target \
--target http://host.docker.internal:18083 \
--scope st004
The --scope value controls report placement and accepts letters, numbers, dots, underscores,
and hyphens. It cannot contain a path separator.
Rule Triage And Blocking Policy
Initial baseline scans do not fail on warning-only findings. Generate ZAP’s complete default rule file during a scan:
opamp-dev-cli build dast baseline --generate-rules
The generated policy is written to:
dev-tools/runtime/security-reports/zap/provider/baseline/zap_generated_rules.conf
After reviewing every rule, copy it to a source-controlled file beneath security/zap/. On
PowerShell:
Copy-Item `
dev-tools/runtime/security-reports/zap/provider/baseline/zap_generated_rules.conf `
security/zap/provider_rules.conf
On Linux or another POSIX shell:
cp dev-tools/runtime/security-reports/zap/provider/baseline/zap_generated_rules.conf \
security/zap/provider_rules.conf
Use the reviewed file in subsequent scans:
opamp-dev-cli build dast baseline --rules-file security/zap/provider_rules.conf
The packaged ZAP format classifies rules as FAIL, WARN, INFO, or IGNORE. Prefer FAIL
for reviewed security requirements, retain WARN while a finding is being evaluated, and add an
explanation alongside every IGNORE. Add --fail-on-warning only after the warning baseline is
stable:
opamp-dev-cli build dast baseline \
--rules-file security/zap/provider_rules.conf \
--fail-on-warning
Reviewed External Documentation Redirects
Every baseline and full scan loads the packaged zap_scan_hooks.py hook from its retained report
directory. The hook removes only Big Redirect Detected rule 10044 alerts whose ZAP
Other Info field identifies https://htmlpreview.github.io as the redirect destination. This
covers expected redirects from unknown local routes, including /robots.txt and /sitemap.xml,
to the externally rendered project documentation.
The local response is still requested and passively scanned. Rule 10044 remains enabled for
redirects to every other destination, and every other alert raised on the same local response is
retained. The hook deletes a matching reviewed alert from the live ZAP session before packaged
scan counts and HTML, JSON, XML, and Markdown reports are generated; it does not globally ignore
the redirect rule or exclude either local route from the spider.
Active Full Scan
A full scan spiders the application and sends active attack payloads. It requires an explicit acknowledgement so it cannot be selected accidentally:
opamp-dev-cli build dast full \
--rules-file security/zap/provider_rules.conf \
--allow-active-scan
Do not aim this command at a production service, shared development data, or a deployment whose state cannot be discarded. Authentication and multi-user workflows should move to a reviewed ZAP Automation Framework plan rather than placing bearer tokens in shell history.
Verify Browser Security Response Headers
The provider and standalone browser services apply the following deny-by-default response headers globally, including successful pages, redirects, authentication failures, and error responses:
Content-Security-Policy: frame-ancestors 'none'; form-action 'self'
Content-Security-Policy-Report-Only: default-src 'self'; base-uri 'none'; object-src 'none'; frame-ancestors 'none'; form-action 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-src 'none'; manifest-src 'self'; worker-src 'none'
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
From PowerShell, inspect a running provider with:
(Invoke-WebRequest -Uri http://localhost:8080/ui -UseBasicParsing).Headers |
Format-List Content-Security-Policy, Content-Security-Policy-Report-Only, X-Frame-Options, X-Content-Type-Options
From Linux or another POSIX shell:
curl --silent --show-error --head http://localhost:8080/ui \
| grep --extended-regexp --ignore-case \
'^(content-security-policy|content-security-policy-report-only|x-frame-options|x-content-type-options):'
ZAP should no longer report Missing Anti-clickjacking Header, a missing form-action directive,
or an X-Content-Type-Options header that is absent or not set to nosniff for protected
responses. The strict report-only header intentionally does not suppress ZAP findings against the
less restrictive enforced policy. Packaged UI templates now load scripts and styles from
same-origin assets, avoid HTML event-handler and style attributes, and use system font stacks
instead of Google Fonts. Use browser console or reporting-endpoint violations to check runtime
DOM changes and deployment-specific overrides before enforcing the strict policy. Retain the
header and HTML compatibility assertions in component tests as the primary regression checks;
use DAST to verify the deployed target and any gateway in front of it.
Reports And Exit Behavior
Each run replaces the stable files below:
dev-tools/runtime/security-reports/zap/<scope>/<mode>/zap_report.html
dev-tools/runtime/security-reports/zap/<scope>/<mode>/zap_report.json
dev-tools/runtime/security-reports/zap/<scope>/<mode>/zap_report.xml
dev-tools/runtime/security-reports/zap/<scope>/<mode>/zap_report.md
Those paths contain the HTTP result. The sequential HTTPS pass writes the equivalent files without overwriting HTTP evidence:
dev-tools/runtime/security-reports/zap/<scope>/<mode>/https/zap_report.html
dev-tools/runtime/security-reports/zap/<scope>/<mode>/https/zap_report.json
dev-tools/runtime/security-reports/zap/<scope>/<mode>/https/zap_report.xml
dev-tools/runtime/security-reports/zap/<scope>/<mode>/https/zap_report.md
Image build failures, application health-check failures, unreachable targets, invalid
configuration, and findings classified as FAIL fail the command. Warning-only results are
non-blocking unless --fail-on-warning is set. Use --spider-minutes and
--startup-timeout-minutes to adjust the default two-minute spider and five-minute ZAP
startup/passive-scan wait.
The source for this workflow is dev-tools/src/opamp_dev_tools/dast.py, and its unit tests are in
dev-tools/tests/test_dast.py. The reviewed redirect filter is implemented in
dev-tools/src/opamp_dev_tools/dast_scan_hooks.py. The HTTP and HTTPS image targets are defined by
dev-tools/docker/dast/Dockerfile, using dev-tools/docker/dast/opamp.json and
dev-tools/docker/dast/opamp-https.json respectively. ZAP’s upstream references are the
Docker scan documentation and
Automation Framework documentation.
OpAMP