Introduction
Docker image with Zed Attack Proxy preinstalled.
Please note that ZAP Docker images are available on Docker Hub as well as GitHub Container Registry (GHCR).
While the docker run
commands on this page use the Docker Hub images, either can be used interchangeably.
Details
Install Instructions
Stable
The stable image is updated whenever there is a ZAP full release. It is also regenerated monthly, typically on the first Monday of the month. The monthly updates pull in the latest base Docker image and also any updated ZAP add-ons - no ZAP ‘core’ changes are included.
docker pull ghcr.io/zaproxy/zaproxy:stable
docker pull zaproxy/zap-stable
Weekly
The weekly image is typically updated every Monday, and includes the very latest changes to the ZAP core and add-ons. It is the same as the Cross Platform Weekly Release.
docker pull ghcr.io/zaproxy/zaproxy:weekly
docker pull zaproxy/zap-weekly
Nightly
The nightly image is updated at least once a day, and includes the very latest changes to the ZAP core and add-ons.
docker pull ghcr.io/zaproxy/zaproxy:nightly
docker pull zaproxy/zap-nightly
Bare
The bare image is a very small Docker image and contains only the necessary required dependencies to run ZAP, ideal for CI environments. It is updated on the same schedule as the stable image.
docker pull ghcr.io/zaproxy/zaproxy:bare
docker pull zaproxy/zap-bare
The Dockerfiles can be found here.
Healthcheck
All of the images support the healthcheck.
If you are running ZAP with port other than the default 8080
, you need to set the ZAP_PORT
environment variable. Otherwise, the healthcheck will fail.
Usage Instructions
Mounting the Current Directory
Many of the examples require that you mount the /zap/wrk
directory, and these examples show how you can mount your current working directory (CWD).
One can get the CWD using various forms of printing the (current) working directory (PWD).
# ...linux / MacOS / PowerShell
# The $(pwd) command substitution will get the current directory as a variable
# The classic form `pwd` must be used for csh and tsch / is still supported in bash/zsh/etc.
docker run -v $(pwd):/zap/wrk/:rw -t zaproxy/zap-stable zap.sh ...
# ...linux / MacOS / PowerShell
# The ${PWD} _environment variable_ is your current directory
docker run -v ${PWD}:/zap/wrk/:rw -t zaproxy/zap-stable zap.sh ...
# ...windows CMD
# The %cd% Windows CMD environment variable is your current directory
docker run -v %cd%:/zap/wrk/:rw -t zaproxy/zap-stable zap.sh ...
The examples use $(pwd)
command substitution, which runs the pwd
command, substituting the result.
Command substitution, and the pwd
command works in most Linux and MacOS shells (bash, zsh, fish(>3.4.0), etc), and in Windows PowerShell.
Many environments also support the $PWD / ${PWD} environment variable.
Finding working solutions for all environments is outside the scope of this document.
Packaged Scans
All of the docker images (apart from the ‘bare’ one) provide a set of packaged scan scripts:
- Baseline Scan which runs the ZAP spider against the target for (by default) 1 minute followed by an optional ajax spider scan before reporting the results of the passive scanning.
- Full Scan which runs the ZAP spider against the target (by default with no time limit) followed by an optional ajax spider scan and then a full active scan before reporting the results.
- API Scan which performs an active scan against APIs defined by OpenAPI, or GraphQL (post 2.9.0) via either a local file or a URL.
The packaged scans are the simplest way to automate ZAP in docker, but also see the GitHub actions if you already use GitHub.
In all cases the scans are tuned by:
- Disabling the Db recovery log
- Disabling all tags
- Reporting a maximum of 10 passive scan alert instances
The zap_tuned()
Scan Hook is called after these changes have been made so you can undo them or apply other changes at this point if you want.
GitHub Actions
The following GitHub Actions wrap the above packaged scans and also support raising GitHub issues for potential vulnerabilities found:
For more details see the blog posts:
- Automate Security Testing with ZAP and GitHub Actions
- Dynamic Application Security Testing with ZAP and GitHub Actions
These GitHub actions are a simple way to run the packaged scans, especially if you already use GitHub.
Automation Framework
The Automation Framework allows you to control ZAP via a single YAML file. It is under active development and will in time exceed the capabilities of the packaged scans and become the recommended option for people who want more control over ZAP. The packaged scans will not be removed but are being migrated to use the Automation Framework.
You can run the Automation Framework in docker using the zap.yaml file in the current directory using:
docker run -v $(pwd):/zap/wrk/:rw -t zaproxy/zap-stable zap.sh -cmd -autorun /zap/wrk/zap.yaml
Note that $(pwd)
is supported on Linux, MacOS and PowerShell.
See Docker About - Mounting the current directory for Windows, etc.
Remaining examples use the Linux approach.
If you want to make sure that ZAP is up to date before running the yaml file then the recommended approach is:
docker run -v $(pwd):/zap/wrk/:rw -t zaproxy/zap-stable bash -c "zap.sh -cmd -addonupdate; zap.sh -cmd -autorun /zap/wrk/zap.yaml"
The latest version of the Automation Framework will set the ZAP exit value based on the result of the plan, in order to have access to this you need to use a command like:
docker container run -v $(pwd):/zap/wrk/:rw -t zaproxy/zap-weekly zap.sh -cmd -autorun /zap/wrk/zap.yaml
ZAP GUI in a Browser
Yes, you can run the ZAP Desktop GUI in a browser. You can use it in just the same way as the Swing UI and can even proxy via it. See the Webswing page for details.
ZAP Headless
You can also start the ZAP in headless mode with following command:
docker run -u zap -p 8080:8080 -i zaproxy/zap-stable zap.sh -daemon -host 0.0.0.0 -port 8080 -config api.addrs.addr.name=.* -config api.addrs.addr.regex=true -config api.key=<api-key>
Note: -config api.addrs.addr.name=.*
opens the API up for connections from any other host, it is prudent to configure this more specifically for your network/setup.
ZAP Headless with xvfb
You can start the ZAP in headless mode with xvfb following command:
docker run -u zap -p 8080:8080 -i zaproxy/zap-stable zap-x.sh -daemon -host 0.0.0.0 -port 8080 -config api.addrs.addr.name=.* -config api.addrs.addr.regex=true
Note: -config api.addrs.addr.name=.*
opens the API up for connections from any other host, it is prudent to configure this more specifically for your network/setup.
This first starts xvfb (X virtual frame buffer) which allows add-ons that use Selenium (like the Ajax Spider and DOM XSS scanner) to run in a headless environment. Firefox is also installed so can be used with these add-ons. Note that by default add-ons which use Selenium will default to using headless browsers when running in docker so this option is not usually required.
Accessing the API from outside of the Docker container
Docker appears to assign ‘random’ IP addresses, so an approach that appears to work is:
Run ZAP as a daemon listening on “0.0.0.0”:
docker run -p 8090:8090 -i zaproxy/zap-stable zap.sh -daemon -port 8090 -host 0.0.0.0
Find out the container id:
docker ps
Find out which address has been assigned to it:
docker inspect <CONTAINER ID> | grep IPAddress
You should be then able to point your browser at the specified host/port and access the ZAP API, eg http://172.17.0.8:8090/
Note that on Macs the IP will be the IP of the Docker VM host. This is accessible with:
docker-machine ip <host>
Scanning an app running on the host OS
IP addresses like localhost and 127.0.0.1 cannot be used to access an app running on the host OS from within a docker container. To get around this you can use the following code to get an IP address that will work:
$(ip -f inet -o addr show docker0 | awk '{print $4}' | cut -d '/' -f 1)
For example:
docker run -t zaproxy/zap-weekly zap-baseline.py -t http://$(ip -f inet -o addr show docker0 | awk '{print $4}' | cut -d '/' -f 1):10080
Scanning an app running in another Docker container
By default Docker does not allow apps running in one container to access an app running in another container. To get around this restriction create a Docker network using:
docker network create zapnet
And then include the Docker option --net zapnet
when starting both your target app and the ZAP packaged scan.