Skip to content

Add fetchZAPResults.sh script to download ZAP reports from a URL#450

Open
TheAuditorTool wants to merge 2 commits intoOWASP-Benchmark:masterfrom
TheAuditorTool:feat/fetch-zap-results-from-url-21
Open

Add fetchZAPResults.sh script to download ZAP reports from a URL#450
TheAuditorTool wants to merge 2 commits intoOWASP-Benchmark:masterfrom
TheAuditorTool:feat/fetch-zap-results-from-url-21

Conversation

@TheAuditorTool
Copy link
Copy Markdown

Summary

Closes #21

Adds a shell script (scripts/fetchZAPResults.sh) that downloads a ZAP XML report from a remote ZAP instance via its REST API and saves it to the results/ directory. This enables scorecard generation when ZAP and Benchmark run in separate Docker containers without a shared filesystem.

Motivation

As described in #21, when ZAP runs in one Docker container and the Benchmark app runs in another, there is no shared filesystem to place a ZAP XML report into the results/ directory. This script bridges that gap by fetching the report over HTTP from ZAP's REST API.

Usage

# Download ZAP XML report from a running ZAP instance
scripts/fetchZAPResults.sh http://172.17.0.3:8090/OTHER/core/other/xmlreport/

# With ZAP API key
scripts/fetchZAPResults.sh "http://zap:8090/OTHER/core/other/xmlreport/?apikey=abc123"

# With custom output filename
scripts/fetchZAPResults.sh http://zap:8090/OTHER/core/other/xmlreport/ my-zap-results.xml

# Then generate the scorecard as usual
./createScorecards.sh

The script auto-generates the output filename using the Benchmark version from pom.xml and the current date (e.g., Benchmark_1.2-ZAP-20260413.xml), matching the existing naming convention in results/.

What it does

  1. Validates that curl is available (via existing requireCommand.sh)
  2. Downloads the ZAP XML report from the provided URL
  3. Validates the response is actually a ZAP report (checks for <OWASPZAPReport marker)
  4. Saves to results/ with a properly formatted filename
  5. Cleans up on failure (HTTP errors or invalid content) so results/ stays clean

Design decisions

  • Follows existing patterns: Uses curl (like runSonarQube.sh), requireCommand.sh (like runBearer.sh, runSemgrep.sh), and getBenchmarkVersion.sh (like runBearer.sh, runSemgrep.sh, runCodeQL.sh)
  • Separation of concerns: Downloads results only; scorecard generation remains a separate step via createScorecards.sh, matching how every other tool in the project works
  • Content validation: Verifies the download is a ZAP XML report before saving, preventing 404 pages or HTML errors from landing in results/ and confusing the scorecard generator

What is NOT changed

  • No existing files modified
  • No pom.xml / dependency changes
  • No changes to src/main/java/org/owasp/benchmark/testcode/
  • No BenchmarkUtils changes needed (existing ZapReader already handles the downloaded XML)

Test plan

  • Run scripts/fetchZAPResults.sh with no arguments -- should print usage and exit 1
  • Run against a ZAP instance URL -- should download the XML and save to results/
  • Run against a bad URL -- should report HTTP error and clean up
  • Run ./createScorecards.sh after downloading -- scorecard should include the new ZAP results

Adds a shell script that downloads a ZAP XML report from a remote ZAP
instance via its REST API and saves it to the results/ directory. This
enables scorecard generation when ZAP and Benchmark run in separate
Docker containers without a shared filesystem.

Closes OWASP-Benchmark#21
Copy link
Copy Markdown

@utafrali utafrali left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The script is well-structured and follows existing project conventions, but has one functional bug (missing mkdir -p results/ that will cause a confusing curl failure), a security concern around API key exposure in the process list, and minor best-practice gaps with error output going to stdout.

output="results/${filename}"

echo "Downloading ZAP report from: ${zap_url}"
http_code=$(curl -sS -o "${output}" -w '%{http_code}' --connect-timeout 10 --max-time 120 "${zap_url}")
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The results/ directory is never created before curl writes to it. If the directory doesn't exist, curl will fail with Failed writing body and then the HTTP status check on line 45 may not behave as expected (the file won't exist for the head -2 check either). Add mkdir -p results/ between lines 40 and 42:

output="results/${filename}"
mkdir -p results/
echo "Downloading ZAP report from: ${zap_url}"

#
# Examples:
# scripts/fetchZAPResults.sh http://172.17.0.3:8090/OTHER/core/other/xmlreport/
# scripts/fetchZAPResults.sh "http://zap:8090/OTHER/core/other/xmlreport/?apikey=abc123"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Passing ?apikey=abc123 as part of the URL argument exposes the API key in the process list (ps aux or /proc/$PID/cmdline). Consider accepting the key as a separate argument and passing it via curl's -H flag instead:

# scripts/fetchZAPResults.sh <ZAP_REPORT_URL> [OUTPUT_FILENAME] [API_KEY]
if [ -n "${api_key:-}" ]; then
  curl_args=(-H "X-ZAP-API-Key: ${api_key}")
fi
curl -sS -o "${output}" -w '%{http_code}' "${curl_args[@]}" ...

This keeps the key out of the argument list. The existing ?apikey= query-param form can still be documented as an alternative for ZAP versions that require it in the URL.

http_code=$(curl -sS -o "${output}" -w '%{http_code}' --connect-timeout 10 --max-time 120 "${zap_url}")

if [ "${http_code}" -ne 200 ]; then
echo "ERROR: Download failed with HTTP status ${http_code}"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error messages on lines 46 and 52-54 are written to stdout instead of stderr. Tools and callers typically check stderr for diagnostics. Redirect them:

echo "ERROR: Download failed with HTTP status ${http_code}" >&2

and

echo "ERROR: Downloaded file does not appear to be a ZAP XML report." >&2
echo "First 3 lines of downloaded content:" >&2
head -3 "${output}" >&2

- Add mkdir -p results/ before curl writes to it (fixes failure on fresh clone)
- Pass API key via X-ZAP-API-Key header instead of URL query param (keeps
  key out of process list and shell history)
- Redirect all error/usage output to stderr
- Validate getBenchmarkVersion.sh output is non-empty before building filename
@TheAuditorTool
Copy link
Copy Markdown
Author

TheAuditorTool commented Apr 13, 2026

The script is well-structured and follows existing project conventions, but has one functional bug (missing mkdir -p results/ that will cause a confusing curl failure), a security concern around API key exposure in the process list, and minor best-practice gaps with error output going to stdout.

Thank you for the review.
I have made a new commit to resolve your findings.
Can you confirm or deny if that solves it to your satisfaction?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature request: generate a ZAP scorecard from a URL

2 participants