Welcome to the second lesson of our DAST course. In the previous lesson, we discussed the theory behind Dynamic Application Security Testing (DAST) and how it differs from static code analysis. Now, we are moving from theory to practice. In this lesson, we will use the OWASP Zed Attack Proxy (ZAP), one of the world's most popular security tools, to scan a vulnerable application.
While ZAP has a graphical user interface (GUI) that looks like a standard desktop program, security engineers often run it from the command line. This is crucial for automation. When you integrate security testing into a CI/CD pipeline (Continuous Integration/Continuous Deployment), you cannot manually click buttons. You need a script that can start the scanner, run the tests, and report the results automatically. Today, you will learn how to control ZAP entirely through its API using terminal commands.
OWASP ZAP is designed to run as a daemon (a background process) that exposes a powerful REST API. This means you can control every aspect of the scanner — from spidering a website to generating reports — by sending simple HTTP requests. This architecture allows developers to write scripts in Python, Bash, or JavaScript to trigger security scans without ever opening the ZAP application window.
Starting ZAP in Daemon Mode on Your Own Device
If you are following along on your own machine, you need to launch ZAP in daemon mode before issuing any API commands. Daemon mode starts ZAP as a headless background process with no GUI. Locate the ZAP startup script in your installation directory and run the appropriate command for your operating system:
The -daemon flag tells ZAP to run without a user interface, and -port 8080 sets the port its API server will listen on. Once this process is running, you can drive it entirely through curl commands exactly as shown throughout this lesson.
Note: In the
CodeSignalenvironment,ZAPis already running in daemon mode in the background, so you do not need to start it yourself.
Anatomy of a ZAP API URL
To interact with the API, we will use curl, a command-line tool for transferring data with URLs. Every ZAP API request follows a consistent URL pattern. Before we make our first call, it is worth understanding what each segment of the URL means:
| Segment | Example | Meaning |
|---|---|---|
| ① Host & Port | http://127.0.0.1:8080 | The address of the locally running ZAP API server |
| ② Format | JSON | The response format — can be JSON, XML, or HTML |
| ③ Component | core | The ZAP module being addressed (e.g., spider, ascan, core) |
| ④ Operation type | view | view reads information without changing state; action triggers a change in ZAP |
| ⑤ Endpoint name | version | The specific operation to invoke within that component |
Since the ZAP API returns data in JSON format (JavaScript Object Notation), we will often pipe the output into Python's JSON tool (python3 -m json.tool) to make it readable.
First, let's verify that the ZAP server is running and reachable:
Output:
This command uses the view operation type on the core component to call the version endpoint — a read-only query that changes nothing. If you receive a version number in response, the scanner is active and ready to receive instructions.
Before ZAP can scan an application, it needs to know that the application exists. ZAP organizes its data in a Sites Tree, which is essentially a map of all the websites and URLs it has interacted with. If ZAP has never visited your target application, the Sites Tree will be empty, and subsequent scan commands might fail or target the wrong domain.
To fix this, we force ZAP to "visit" the target URL once. We do this using the accessUrl endpoint. For this lesson, our target is a vulnerable "Pastebin" application running on http://localhost:3001.
Notice this URL uses the action operation type (not view), because we are telling ZAP to do something — make an outbound HTTP request to the target. The accessUrl endpoint is the specific action being triggered within the core component.
Output:
By sending this request, ZAP makes a simple HTTP connection to the target. This places localhost:3001 into ZAP's memory, making it available for the more complex scanning actions we are about to perform.
Now that ZAP is aware of the target, we need to discover the application's structure. A web application is made up of many pages, forms, and API endpoints. We cannot manually list them all, so we use a Spider. A Spider (or Crawler) visits the main URL, looks for all the links on that page, visits those links, and repeats the process until it has mapped out the entire application.
This step is generally "passive," meaning it does not launch attacks. It simply explores the site to build a map. We trigger the Spider using the spider/action/scan endpoint.
Output:
The output gives us a Scan ID (in this case, "0"). Scanning takes time, so the API does not wait for it to finish. Instead, it starts the process in the background and gives you a Scan ID so you can check on it later. You must poll the status endpoint until the progress reaches 100%.
Output:
Once the status reaches 100%, ZAP has a complete blueprint of the application's structure. This map is essential because the scanner can only test the vulnerabilities of pages and endpoints it has successfully discovered during this phase.
Once the Spider has finished mapping the application, we can begin the Active Scan. This is the core of DAST. During an Active Scan, ZAP takes the URLs discovered by the Spider and launches simulated attacks against them. It attempts to inject malicious data, such as SQL commands or script tags, into input fields and URL parameters to see how the server responds.
This process is aggressive. Unlike spidering, active scanning can modify data or trigger errors on the server. We start it using the ascan (Active Scan) endpoint.
Output:
Just like the Spider, this returns a Scan ID. Active scans take much longer than spidering because ZAP is trying thousands of different attack patterns. You monitor the progress using the ascan/view/status endpoint.
Output:
When the Active Scan reaches 100%, the testing is complete. ZAP stores its findings as Alerts. An alert represents a specific vulnerability found at a specific URL. It includes details such as the risk level (High, Medium, Low), the parameter that was exploited, and evidence (like an error message returned by the server).
To view these results, we query the core/view/alerts endpoint.
Output:
In the output above, ZAP found two high-risk issues. It detected a SQL Injection vulnerability in the search parameter, likely because the application crashed or returned a database error. It also found a Cross-Site Scripting (XSS) vulnerability, meaning it successfully injected a script that the browser would execute. These details provide the exact location a developer needs to fix the code.
While JSON output is great for automated parsers, humans often prefer a readable document. If you are running these scans as part of a job, you will likely need to share the results with a manager or a development team. ZAP can generate HTML reports that summarize the findings in a clean, professional format.
We can trigger this report generation using the core/other/htmlreport endpoint. Instead of piping this to a JSON tool, we redirect the output > to a file.
This command creates a file named zap-report.html in your current directory. You can open this file in any web browser to see charts, risk summaries, and detailed descriptions of every vulnerability found during the scan. This is a standard artifact to include in build pipelines to prove that security testing was performed.
In this lesson, you performed a complete DAST workflow using nothing but the command line. You learned how to verify the ZAP API status, register a target application, and use a Spider to map out the website's structure. You then launched an Active Scan to identify vulnerabilities and reviewed the JSON Alerts to understand the security risks. Finally, you exported a human-readable HTML report.
This process — Map, Scan, Report — is the foundation of automated security testing. In the upcoming practice exercises, you will run these commands yourself against a live application to reinforce these concepts. Good luck!
