- ⚠️ Zed Attack Proxy JSON report failures often come from missing volume mounts or improperly translated Windows paths.
- 🧠 Installing the "reporting" add-on is needed for JSON output in ZAP.
- 📝 Python scripts must wait for the container to finish and handle output using subprocess tools.
- 📁 Podman on Windows expects paths in WSL/Linux format like
/mnt/c/for volume mounts to work. - 🔍 Parsing and using JSON reports with Python makes it possible to fully integrate into DevSecOps pipelines.
If you’ve tried automating your Zed Attack Proxy (ZAP) scans using a Python script within Podman on a Windows machine—only to be confused by a failed JSON report or a missing output—you’re not alone. This guide looks at all the important technical details, from container volume mounts to Python subprocess handling and ZAP command structure. It helps you get dependable JSON report generation for your DevSecOps work.
Zed Attack Proxy in Dev Automation
Zed Attack Proxy (ZAP), developed and maintained by the OWASP Foundation, is one of the most powerful and popular open-source web application security scanners available today. It finds security vulnerabilities in active development. ZAP is a key tool in any DevSecOps pipeline. Teams across the globe use ZAP both interactively and in automated CI/CD environments to always check how secure web applications are.
For automation, ZAP supports several interfaces:
- Command-Line Interface (CLI): For quick scans and scripted automation.
- Daemon/API Mode: For programmatic interaction using supported clients including Python and Java.
- Web UI: Mainly for manual scanning and manual testing.
Among various output formats, the JSON report is very useful for putting results into existing monitoring systems, custom dashboards, data pipelines, and incident management tools.
Automating scans and processing output using a Python script is common. But when you use Podman as your container runtime—and Windows as your host OS—things get tricky quickly. This happens because of path translation issues, permissions, and the need for correct ways to map output from the container to the host.
The Dev Scenario: ZAP + Python + Podman on Windows
Let's look at a common developer task: you're on a Windows 10 or 11 workstation. You're writing a Python script to automate a ZAP scan against your staging application. The ZAP image runs in a container with Podman. Your plan is to run things this way:
- Launch a Podman container running OWASP ZAP.
- Point ZAP to a target URL.
- Trigger a quick scan.
- Save a report in JSON format to a known output directory on the Windows host.
- Exit the container.
Money in the bank—until this shows up:
"Job report failed to generate report"
Or worse:
- No report at all.
- The container exits with success but writes… nothing.
- The Python script shows no error, but your output folder is empty.
This is the mix of odd path mapping and command order problems in container scans on non-Linux systems.
How ZAP Generates Reports
ZAP can generate reports using its internal way of making reports. You can start it with:
- The CLI using
zap.sh - The ZAP API via JSON-RPC or RESTful endpoints
For CLI-based use, the ZAP image has simple flags like:
zap.sh -cmd -quickurl http://app-under-test.com \
-addoninstall reporting \
-quickout /zap/wrk/output.json \
-quickprogress
Breaking it down:
-cmd: Run in command-line mode (headless).-quickurl: The target URL to scan.-addoninstall: Adds needed plugins like “reporting” when needed.-quickout: Path where the report (JSON, in this case) is written.-quickprogress: Shows progress feedback.
The /zap/wrk directory inside the container is where output files, session data, and logs are usually written. Unless mapped to a directory on your Windows host using a correct volume mount, anything written there stays only inside the container while it is running—and is deleted when --rm is used.
Python Script: Launching ZAP from Code
A Python script using subprocess.run (or subprocess.Popen) gives you a way to start and manage container processes from your automation code. When doing this with ZAP’s CLI inside Podman, you might write:
import subprocess
subprocess.run([
"podman", "run", "--rm",
"owasp/zap2docker-stable",
"zap.sh", "-cmd",
"-quickurl", "http://target-site.com",
"-addoninstall", "reporting",
"-quickout", "/zap/wrk/report.json"
])
While this seems right, it fails silently or outputs unclear error logs under several wrong setups:
- Missing a volume mount, so
/zap/wrkcannot be reached from the host. - Windows-native paths like
C:\Users\MyNamearen’t translated into mounts that containers can use. - The
"reporting"addon is not yet installed, so ZAP can't make a JSON report. - The Python script exits before the scan completes because
subprocess.run()isn’t set up to show stdout/stderr messages. - Not enough write permissions to the mounted output path.
Why the JSON Report Fails
Let’s go deeper into the main reasons it fails:
-
❌ No Volume Mount Defined
Without-vor--volume, the output stays within the container and is lost when the container exits. -
❌ Improper Windows Path Format
Podman on Windows expects paths using Linux notation (e.g.,/mnt/c/Users/...) instead ofC:\Users\.... -
❌ Missing Required Add-ons
The JSON report function needs the"reporting"plugin. Not specifying-addoninstall reportingresults in an unsupported command error or empty response. -
❌ Permissions
Even if the directory appears to exist, Podman may not have write access unless it’s clearly given or mounted using the correct permissions. -
❌ Scan Not Done on Time
If the Python script doesn’t monitor or wait for scan completion and immediately tries to access an unfinished or not there output file, the report will appear missing.
Fixing the Setup Step-by-Step
Let’s walk through a good way to set things up and find problems:
1. Add Verbose Logging
Add flags to see more:
-quickprogress -config api.disablekey=true
This helps debug internal steps and find scan or report errors.
2. Install Required Add-ons
ZAP needs the reporting add-on:
-addonupdate -addoninstall reporting
3. Proper Volume Mounts
Map local directory using:
-v /mnt/c/dev/zap-output:/zap/wrk
✅ Path must:
- Exist before running the command.
- Be writeable by the container.
- Be expressed in WSL-compatible syntax.
4. Normalize Windows Paths
Do NOT use C:\Users\xyz in -v; instead translate to:
/mnt/c/Users/xyz/folder
You can find WSL paths by running wsl and navigating to your Windows folders from there.
5. Use Subprocess Properly
Collect all process outputs:
result = subprocess.run([...], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
print(result.stdout.decode())
print(result.stderr.decode())
This output can show plugin load errors, permissions issues, or scan interruptions.
Paths and Volumes with Podman on Windows
Podman is a rootless container engine not linked to the Docker daemon. This adds more ways to do things, especially in business settings. But it makes path translation harder when running under Windows environments.
📍 Key notes:
- Always use Linux-style paths (
/mnt/c/...). - Paths must exist before mapping, or Podman may silently fail.
- Use the
--mountor-vflags for two-way persistence. - Consider testing volume mappings with dummy containers like
alpine ls /zap/wrk.
Incorrect volume mounts are the number one cause for “JSON files that seem to appear but are not there.”
Proper Python Script for ZAP Execution
Here’s a better and working Python script for running a ZAP scan and making a dependable JSON report:
import subprocess
import shlex
import os
output_dir = "/mnt/c/dev/zap-results"
os.makedirs(output_dir, exist_ok=True) # Ensure output directory exists
cmd = f"""
podman run --rm
-v {output_dir}:/zap/wrk
owasp/zap2docker-stable
zap.sh -cmd
-addonupdate
-addoninstall reporting
-quickurl http://example.com
-quickout /zap/wrk/report.json
-quickprogress
"""
# Use shlex to properly parse the command
proc = subprocess.run(shlex.split(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# Output logs for debugging
print("STDOUT:\n", proc.stdout.decode())
print("STDERR:\n", proc.stderr.decode())
# Check existence of the report
report_path = os.path.join("C:/dev/zap-results", "report.json")
if os.path.exists(report_path):
print("✅ Report generated:", report_path)
else:
print("❌ Report not found. Check container logs.")
Make sure:
- Podman is installed and integrated with WSL.
- The target folder is not locked by another process.
- Port conflicts or proxy software on Windows aren’t interfering with container networking.
Confirming and Parsing JSON Output in Python
Here’s how you can easily check and use the ZAP output:
import json
with open("C:/dev/zap-results/report.json") as f:
zap_report = json.load(f)
# Print summaries
for site in zap_report.get("site", []):
print("Scanned Site:", site.get("name"))
for alert in site.get("alerts", []):
print(f"- [{alert['risk']}]: {alert['alert']}")
This level of automation lets you:
- Integrate findings into Slack or email alerts
- Trigger ticket creation
- Display web dashboards or CI job summaries
Best Practices for Reliable Automation
- ✅ Use tagged container images like
zap2docker-stable:2.12.0for builds you can repeat. - ✅ Keep output directories clean and checked before each scan.
- ✅ Use
-addonupdateto make sure it works with the reporting plugin. - ✅ Log all scan results (stdout/stderr) using Python so you have a record.
- ✅ Avoid running sensitive reports without encryption on exposed volumes.
ZAP API as an Alternative Option
For more complex tasks, the official ZAP Python API client (python-owasp-zap-v2) offers much more control:
Benefits:
- Connect to a running daemon
- Queue scans and monitor progress
- Fetch structured results directly via JSON
- Avoid filesystem write issues altogether
Example:
from zapv2 import ZAPv2
zap = ZAPv2(apikey='', proxies={'http': 'http://localhost:8080'})
zap.urlopen('http://example.com')
scan_id = zap.ascan.scan('http://example.com')
print('Scan started. ID:', scan_id)
But for single scans or CI environments, a CLI-based subprocess model as shown above is often simpler, faster, and good enough for many dev teams.
When It's More Than Just the Report
More complex problems may require more detailed debugging:
- JVM errors: Use
-daemonmode to check for logs. - DNS/network: Check if it can connect inside the container (
ping,curl). - Container corruption: Rebuild local images or re-pull from source.
You can also:
- Check
/zap/zap.loginside the container. - Manually step through a scan interactively to see what happens.
- Join the OWASP ZAP community forums for help or to report bugs.
Wrapping It All Up
JSON report failures when using Zed Attack Proxy with Python and Podman on Windows are usually because of mount path issues, missing plugins, or scan interruptions. But with correctly mapped Linux-style paths, needed add-ons installed, and careful subprocess handling, you can fully automate dependable ZAP scans. Whether in local scripts or CI/CD pipelines, structured ZAP reports can help teams use real-time security information—efficiently and again and again.
References
OWASP. (2023). ZAP User Manual. Retrieved from https://owasp.org/www-project-zap
Podman.io. (2023). Windows Support: Path Mapping and Volume Mounts. Retrieved from https://podman.io/getting-started/windows
Python.org. (n.d.). subprocess — Subprocess management in Python. Retrieved from https://docs.python.org/3/library/subprocess.html