Skip to content

feat(security): add OWASP ZAP automated security scan - #724

Open
muizbolaji4 wants to merge 2 commits into
ritik4ever:mainfrom
muizbolaji4:feat/add-owasp-zap-security-scan
Open

feat(security): add OWASP ZAP automated security scan#724
muizbolaji4 wants to merge 2 commits into
ritik4ever:mainfrom
muizbolaji4:feat/add-owasp-zap-security-scan

Conversation

@muizbolaji4

@muizbolaji4 muizbolaji4 commented Jul 29, 2026

Copy link
Copy Markdown

Overview

This PR adds an OWASP ZAP Baseline (Passive) Security Scan that automatically runs against the staging deployment. The scan detects common web vulnerabilities passively without sending malicious payloads, blocks the deployment if high-severity findings are discovered, and uploads the scan report as a downloadable CI artifact.

Related Issue

Closes #628

Changes

OWASP ZAP Security Scan Workflow

  • [ADD] .github/workflows/zap-security-scan.yml
    • Triggers on successful staging deployments (deployment_status event) or manually via workflow_dispatch.
    • Resolves the target URL from the deployment event, manual input, or the STAGING_URL repository secret.
    • Runs OWASP ZAP baseline (passive) scan — safe, no active attacks.
    • Fails the build (fail_action: true) if any alerts of any severity are detected.
    • Uploads the ZAP HTML report as a downloadable CI artifact (zap-html-report).
    • Summarizes scan findings (high/medium/low severity counts) in the job summary with a clear pass/fail status.
    • Additional manual trigger support with a custom target_url input parameter.

Acceptance Criteria

Criteria Status
Scan runs on staging deploy deployment_status trigger with state == 'success' filter
High severity blocks deploy fail_action: true + explicit jq-based check exits with code 1
Report downloadable from CI HTML report uploaded as zap-html-report artifact
Manual re-scan supported workflow_dispatch with optional target_url input
Scan results visible in PR Job summary with severity breakdown

Verification

The workflow can be verified by:

  1. Setting the STAGING_URL repository secret to the staging deployment URL.
  2. Deploying to staging (triggers automatic scan).
  3. Or manually dispatching the workflow with a target URL.
  4. Checking that the ZAP HTML report is available under the workflow run's Artifacts section.
  5. Confirming that the workflow fails if high-severity vulnerabilities are detected.

Summary by CodeRabbit

  • New Features

    • Added automated OWASP ZAP passive security scanning for deployments.
    • Security scan results are available in SARIF and HTML report formats.
    • Scan summaries include detected high- and medium-risk findings.
  • Bug Fixes

    • Deployment checks now fail when high- or medium-risk security vulnerabilities are detected.

muizbolaji4 and others added 2 commits July 29, 2026 13:31
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@vercel

vercel Bot commented Jul 29, 2026

Copy link
Copy Markdown

@muizbolaji4 is attempting to deploy a commit to the ritik4ever's projects Team on Vercel.

A member of the Team first needs to authorize it.

@drips-wave

drips-wave Bot commented Jul 29, 2026

Copy link
Copy Markdown

@muizbolaji4 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

OWASP ZAP security scanning

Layer / File(s) Summary
Scan triggers and target resolution
.github/workflows/zap-security-scan.yml
The workflow supports deployment-status and manual triggers, gates execution to successful deployments or dispatches, and resolves the target URL from input, deployment metadata, or the staging secret.
ZAP baseline scan
.github/workflows/zap-security-scan.yml
The job runs the OWASP ZAP baseline passive scan against the resolved target.
Report publication and severity enforcement
.github/workflows/zap-security-scan.yml
SARIF and HTML reports are uploaded, while JSON findings are summarized and medium or high alerts cause workflow failure.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related issues

  • ritik4ever/stellar-stream#774 — The workflow implements the requested staging OWASP ZAP scan, severity blocking, and downloadable reporting.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the change: an automated OWASP ZAP security scan workflow.
Linked Issues check ✅ Passed The workflow runs on deployment events, blocks on findings, and uploads reports as CI artifacts, matching issue #628.
Out of Scope Changes check ✅ Passed The changes stay within the security-scan workflow scope and do not introduce unrelated code.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Fix failing CI checks
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 9

🧹 Nitpick comments (1)
.github/workflows/zap-security-scan.yml (1)

26-27: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Disable persisted checkout credentials.

This workflow does not need authenticated Git operations after checkout. Set persist-credentials: false; checkout v4 persists the token by default. (github.com)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/zap-security-scan.yml around lines 26 - 27, Update the
“Checkout repository” step using actions/checkout@v4 to set persist-credentials
to false, while leaving the existing checkout behavior unchanged.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/zap-security-scan.yml:
- Around line 68-85: Update the ZAP report handling around the zap-report.json
existence check and jq count calculations to fail closed: require a non-empty
report, validate its JSON/schema before counting alerts, and treat every jq or
summary-publication failure as an error. Ensure malformed or missing reports and
failed writes to GITHUB_STEP_SUMMARY exit nonzero instead of reporting a
successful scan, while preserving the existing blocking behavior for high- or
medium-severity findings.
- Around line 32-37: Update the target-selection step to pass each external URL
through the step environment rather than interpolating it into the shell script,
then emit the selected value with quoted printf into GITHUB_OUTPUT. Also update
the summary output to consume the step output safely without directly embedding
unvalidated steps.target.outputs.url in shell source; validate or escape it
before use.
- Around line 12-16: The workflow permissions must support SARIF uploads without
enabling unintended issue creation. Update the top-level permissions block to
grant security-events: write instead of checks: write, and configure
zaproxy/action-baseline@v0.10.0 with allow_issue_writing: false while preserving
the existing scan and upload steps.
- Around line 21-23: Change the deployment and ZAP scan workflow coordination so
the scan completes before deployment reports success, rather than gating on
github.event.deployment_status.state == 'success' in the current workflow
condition. Implement the required pre-success protection gate or make the
deployment workflow wait for the scan result, ensuring failed scans prevent
deployment success.
- Around line 21-23: Update the workflow trigger condition to require a staging
deployment environment whenever github.event_name is deployment_status, while
preserving the existing workflow_dispatch path. Use the deployment status
environment field exposed by the event payload and ensure successful production
or other non-staging deployments cannot start the ZAP scan.
- Around line 43-49: Update the ZAP Baseline Passive Scan step identified by id
zap to set fail_action to false, allowing the scan to complete without failing
on its default alert handling. Preserve the later explicit report check as the
workflow-level gate based on parsed medium and high risk counts.
- Around line 43-49: The ZAP workflow references report filenames that the
baseline action does not generate. Update the JSON and HTML processing steps to
use report_json.json and report_html.html, and update Markdown handling to use
report_md.md; if SARIF remains required, add a separate conversion step that
produces the SARIF file before upload.
- Around line 34-35: Update the URL assignment in the workflow’s
deployment-status handling to use github.event.deployment_status.environment_url
instead of github.event.deployment_status.target_url. Preserve the existing
non-empty check and GITHUB_OUTPUT assignment so ZAP receives the deployed
environment URL.
- Line 45: Update the zaproxy/action-baseline reference in the workflow to the
latest supported release that declares runs.using node20, and verify that its
inputs and outputs remain compatible with the existing scan step before merging.

---

Nitpick comments:
In @.github/workflows/zap-security-scan.yml:
- Around line 26-27: Update the “Checkout repository” step using
actions/checkout@v4 to set persist-credentials to false, while leaving the
existing checkout behavior unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: fc62ccdf-3fca-4e43-a438-9720bb8243c4

📥 Commits

Reviewing files that changed from the base of the PR and between 10f827c and 75e611a.

📒 Files selected for processing (1)
  • .github/workflows/zap-security-scan.yml

Comment on lines +12 to +16
permissions:
contents: read
deployments: read
checks: write

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== workflow =="
if [ -f .github/workflows/zap-security-scan.yml ]; then
  nl -ba .github/workflows/zap-security-scan.yml | sed -n '1,120p'
else
  echo "missing .github/workflows/zap-security-scan.yml"
fi

echo
echo "== search for action calls =="
rg -n "github/codeql-action/upload-sarif|zaproxy/action-baseline|permissions:|allow_issue_writing" .github/workflows || true

echo
echo "== git diff summary =="
git diff --stat || true

Repository: ritik4ever/stellar-goal-vault

Length of output: 222


🌐 Web query:

github codeql-action upload-sarif permissions security-events write

💡 Result:

To use the github/codeql-action/upload-sarif action, your GitHub Actions workflow job must be granted specific permissions to interact with the repository's security features and metadata [1][2]. The mandatory permission is: - security-events: write In addition to this, if you are working in a private or internal repository, you must also grant: - actions: read - contents: read These additional permissions are required because the action queries workflow run metadata during the upload process [3][4]. Failing to provide these permissions—particularly actions: read in private repositories—often results in a "Resource not accessible by integration" error [5][3]. Example configuration: jobs: upload-analysis: runs-on: ubuntu-latest permissions: security-events: write actions: read contents: read steps: - name: Upload SARIF uses: github/codeql-action/upload-sarif@v4 with: sarif_file: results.sarif

Citations:


🌐 Web query:

zaproxy action-baseline v0.10.0 README allow_issue_writing default true

💡 Result:

In the zaproxy/action-baseline GitHub Action, specifically in version 0.10.0 and subsequent versions, the allow_issue_writing input defaults to true [1][2]. This input determines whether the action will automatically create or update a GitHub issue with the ZAP scan report using the title provided in the issue_title input [3][1]. Setting allow_issue_writing to false disables this behavior [3][4].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== workflow =="
if [ -f .github/workflows/zap-security-scan.yml ]; then
  awk '{ printf "%5d  %s\n", NR, $0 }' .github/workflows/zap-security-scan.yml | sed -n '1,120p'
else
  echo "missing .github/workflows/zap-security-scan.yml"
fi

echo
echo "== search for action calls and permissions =="
rg -n "github/codeql-action/upload-sarif|zaproxy/action-baseline|permissions:|allow_issue_writing|permissions:" .github/workflows || true

echo
echo "== git status/diff summary =="
git status --short || true
git diff --stat || true

Repository: ritik4ever/stellar-goal-vault

Length of output: 4595


Grant the permissions required by the SARIF upload action.

github/codeql-action/upload-sarif@v3 requires security-events: write; checks: write does not grant that permission, so the final SARIF upload step can fail with Resource not accessible by integration. Also set allow_issue_writing: false on zaproxy/action-baseline@v0.10.0 unless creating/updating ZAP issues is intentional; issue writing is enabled by default and can fail when issue permissions are not granted.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/zap-security-scan.yml around lines 12 - 16, The workflow
permissions must support SARIF uploads without enabling unintended issue
creation. Update the top-level permissions block to grant security-events: write
instead of checks: write, and configure zaproxy/action-baseline@v0.10.0 with
allow_issue_writing: false while preserving the existing scan and upload steps.

Comment on lines +21 to +23
if: >
github.event_name == 'workflow_dispatch' ||
github.event.deployment_status.state == 'success'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== files =="
git ls-files '.github/workflows/*' | sed -n '1,120p'

echo
echo "== target workflow =="
if [ -f .github/workflows/zap-security-scan.yml ]; then
  cat -n .github/workflows/zap-security-scan.yml
else
  echo "missing .github/workflows/zap-security-scan.yml"
fi

echo
echo "== related workflow references =="
rg -n "zap-security-scan|workflow_dispatch|deployment_status|deployment|deployment_status\.state|ref =|ZAP|zap" .github/workflows || true

echo
echo "== current branch/workflow files diff stat =="
git diff --stat -- .github/workflows || true

Repository: ritik4ever/stellar-goal-vault

Length of output: 7549


🌐 Web query:

GitHub Actions deployment_status event runs after status reports back deployment workflow cannot be blocked by downstream job after deployment_status success

💡 Result:

In GitHub Actions, a workflow configured with the deployment_status event trigger runs independently whenever an external service updates the deployment status (e.g., to success, failure, or pending) [1][2][3]. This workflow is not "blocked" or managed by the workflow that originally created the deployment; rather, it is a separate event-driven process [4][3]. Because the deployment_status event fires for every state change, your workflow will be triggered multiple times throughout the deployment lifecycle [4]. If you only want your workflow jobs to execute after a successful deployment, you must explicitly filter them using a conditional expression at the job level [4][5]: jobs: run-after-deploy: if: github.event.deployment_status.state == 'success' runs-on: ubuntu-latest steps: - run: echo "Deployment was successful!" Regarding your query about downstream blocking: 1. Independent Execution: The deployment_status workflow is triggered by the GitHub webhook event, not by the completion of another workflow [1][3]. There is no native mechanism for a "downstream job" to block the initiation of this event-driven workflow [4]. 2. State Dependency: Since you cannot prevent the workflow from triggering on non-success states (like pending or in_progress) without potentially missing the success event, the standard pattern is to allow the workflow to start and then use the if condition to skip unwanted jobs [4][6]. 3. Context Limitations: Be aware that the deployment_status event context often lacks certain information, such as the github.ref (branch or tag), because the event is tied to a specific deployment instance rather than a repository ref [7][8]. If you need to verify the branch, you may need to use the GitHub API to fetch the associated commit or deployment details [8]. In summary, you cannot block the deployment_status event from triggering, nor can you block the overall workflow run from starting via a downstream job. You should design your workflow to be idempotent and use job-level conditionals to ensure your logic only proceeds when the deployment state reaches success [4][5].

Citations:


Gate the scan before reporting deployment success.

This workflow is triggered by deployment_status, so it starts after the deployment status is already reported; if it fails after the state is success, the deployment cannot be rolled back by GitHub Actions alone. Satisfy Issue #628 by making this a required pre-success check/protection gate or having the deployment workflow wait for the scan result before reporting success.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/zap-security-scan.yml around lines 21 - 23, Change the
deployment and ZAP scan workflow coordination so the scan completes before
deployment reports success, rather than gating on
github.event.deployment_status.state == 'success' in the current workflow
condition. Implement the required pre-success protection gate or make the
deployment workflow wait for the scan result, ensuring failed scans prevent
deployment success.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Repository files matching zap-security-scan:"
fd -a 'zap-security-scan\.yml$|zap-security-scan\.yaml$' . || true

echo
echo "Workflow contents:"
if [ -f .github/workflows/zap-security-scan.yml ]; then
  cat -n .github/workflows/zap-security-scan.yml
fi

echo
echo "Event/trigger references in workflows:"
rg -n "ghcr.io|zap|security|on:|deployment_status|workflow_dispatch|environment" .github/workflows || true

echo
echo "Relevant GitHub Actions docs via local source absent; checking public docs with web query"

Repository: ritik4ever/stellar-goal-vault

Length of output: 11101


🌐 Web query:

GitHub Actions deployment_status object environment field event.deployment_status.environment

💡 Result:

In GitHub Actions workflows, the github.event.deployment_status.environment field contains the name of the target deployment environment (e.g., "production", "staging", "qa") associated with a deployment_status event [1][2][3]. Key details regarding this field include: * Data Source: The field is part of the deployment_status object within the webhook payload for the deployment_status event [4][2]. * Behavior: When a deployment status is created, this field identifies the specific environment being targeted [3][5]. If this field is not explicitly defined when the status is created, GitHub defaults to the environment of the previous status on the deployment, if one exists; otherwise, it defaults to the environment of the original deployment [6][3][7]. * Usage in Workflows: It is commonly used in GitHub Actions to filter jobs or trigger specific logic based on the environment being deployed to. For example, developers often use it in if conditions to ensure deployment-related workflows only execute for specific environments: on: deployment_status: jobs: deploy-check: runs-on: ubuntu-latest if: github.event.deployment_status.environment == 'production' steps: - run: echo "Deploying to production" * Security Warning: Because environment (along with other payload fields) is provided by the external service or tool that triggers the deployment, it should be treated as untrusted input [1]. When using this field to make security decisions or run tests, ensure your workflow is configured safely, as improper handling of deployment-related inputs can potentially be exploited [1].

Citations:


Restrict deployment-status scans to staging.

This workflow runs on every successful deployment-status event; gate that branch on the deployment environment so production or other environments cannot trigger the ZAP scan.

Proposed condition
 github.event_name == 'workflow_dispatch' ||
- github.event.deployment_status.state == 'success'
+ (github.event.deployment_status.state == 'success' &&
+  github.event.deployment_status.environment == 'staging')
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if: >
github.event_name == 'workflow_dispatch' ||
github.event.deployment_status.state == 'success'
if: >
github.event_name == 'workflow_dispatch' ||
(github.event.deployment_status.state == 'success' &&
github.event.deployment_status.environment == 'staging')
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/zap-security-scan.yml around lines 21 - 23, Update the
workflow trigger condition to require a staging deployment environment whenever
github.event_name is deployment_status, while preserving the existing
workflow_dispatch path. Use the deployment status environment field exposed by
the event payload and ensure successful production or other non-staging
deployments cannot start the ZAP scan.

Comment on lines +32 to +37
if [ -n "${{ github.event.inputs.target_url }}" ]; then
echo "url=${{ github.event.inputs.target_url }}" >> $GITHUB_OUTPUT
elif [ -n "${{ github.event.deployment_status.target_url }}" ]; then
echo "url=${{ github.event.deployment_status.target_url }}" >> $GITHUB_OUTPUT
elif [ -n "${{ secrets.STAGING_URL }}" ]; then
echo "url=${{ secrets.STAGING_URL }}" >> $GITHUB_OUTPUT

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== workflow file =="
cat -n .github/workflows/zap-security-scan.yml

echo
echo "== occurrences of github.event/secrets in workflow =="
rg -n '\$\{\{\s*(github\.event|secrets\.STAGING_URL)' .github/workflows/zap-security-scan.yml || true

Repository: ritik4ever/stellar-goal-vault

Length of output: 4642


Do not interpolate external values into shell source.

The target values on lines 32-37 are expanded directly into the run script, so inputs/secret values containing " and untrusted deployment URLs containing $() can alter the commands. Pass the target through env and use quoted printf for shell output; avoid interpolating steps.target.outputs.url into the summary line as well unless it is validated/escaped first.

🧰 Tools
🪛 zizmor (1.28.0)

[error] 32-32: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[error] 33-33: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[error] 34-34: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[error] 35-35: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/zap-security-scan.yml around lines 32 - 37, Update the
target-selection step to pass each external URL through the step environment
rather than interpolating it into the shell script, then emit the selected value
with quoted printf into GITHUB_OUTPUT. Also update the summary output to consume
the step output safely without directly embedding unvalidated
steps.target.outputs.url in shell source; validate or escape it before use.

Source: Linters/SAST tools

Comment on lines +34 to +35
elif [ -n "${{ github.event.deployment_status.target_url }}" ]; then
echo "url=${{ github.event.deployment_status.target_url }}" >> $GITHUB_OUTPUT

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== workflow occurrences =="
if [ -f .github/workflows/zap-security-scan.yml ]; then
  nl -ba .github/workflows/zap-security-scan.yml | sed -n '1,140p'
else
  echo "missing .github/workflows/zap-security-scan.yml"
fi

echo
echo "== deployment-status related references =="
rg -n "deployment_status|environment_url|target_url|url=|--url" .github/workflows || true

echo
echo "== docs/API behavior from installed GitHub REST docs? =="
python3 - <<'PY'
import json, urllib.request
url="https://docs.github.com/en/rest/deployments/statuses"
try:
    with urllib.request.urlopen(url, timeout=20) as r:
        text=r.read(500).decode()
    print(text)
except Exception as e:
    print(type(e).__name__, e)
PY

Repository: ritik4ever/stellar-goal-vault

Length of output: 234


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== workflow occurrences =="
if [ -f .github/workflows/zap-security-scan.yml ]; then
  awk '{print NR": "$0}' .github/workflows/zap-security-scan.yml | sed -n '1,140p'
else
  echo "missing .github/workflows/zap-security-scan.yml"
fi

echo
echo "== deployment-status related references =="
rg -n "deployment_status|environment_url|target_url|url=|--url" .github/workflows || true

echo
echo "== external doc/API fields for deployment statuses =="
python3 - <<'PY'
from urllib.request import urlopen
fields=[]
for url in [
  "https://docs.github.com/en/rest/deployments/deployments?apiVersion=2022-11-28",
  "https://docs.github.com/en/rest/deployments/statuses?apiVersion=2022-11-28",
  "https://rest.github-api.org/en/v1/rest/deployments/deployments?apiVersion=2022-11-28",
]:
    try:
        text=urlopen(url, timeout=20).read(5000).decode()
        print(f"--- {url!r} ---")
        print(text)
        print()
    except Exception as e:
        print(f"--- {url!r} ---")
        print(f"ERROR {type(e).__name__}: {e}")
        print()
PY

Repository: ritik4ever/stellar-goal-vault

Length of output: 5654


🌐 Web query:

GitHub REST Deployment Statuses fields target_url environment_url documentation

💡 Result:

In the GitHub REST API, both target_url and environment_url are fields used when creating or retrieving a deployment status [1][2]. 1. target_url: This is a string field intended to provide a link to the output of the deployment, which helps users monitor the task while it is running or access historical information about the deployment [1][3]. GitHub currently recommends using the log_url parameter instead of target_url [1][2]. While target_url is still accepted to support legacy integrations, log_url is the preferred field for providing the full URL of the deployment's output [1][4]. Notably, if you set log_url, GitHub automatically sets target_url to the same value [1][3]. 2. environment_url: This is a string field that specifies the URL for accessing the deployed environment (e.g., the live application URL) [1][2]. It is distinct from the target_url or log_url, which are typically used for deployment logs or task status tracking [1][3]. When interacting with the POST /repos/{owner}/{repo}/deployments/{deployment_id}/statuses endpoint, both target_url (or log_url) and environment_url are optional fields provided in the request body [1][4]. Both fields are also returned as part of the deployment status object when retrieving status information [1][2].

Citations:


Use environment_url as the scan target.

deployment_status.target_url is intended for deployment output/log links, not the deployed environment/app URL. Set url from github.event.deployment_status.environment_url so the ZAP scan does not target a deployment log.

🧰 Tools
🪛 zizmor (1.28.0)

[error] 34-34: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[error] 35-35: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/zap-security-scan.yml around lines 34 - 35, Update the URL
assignment in the workflow’s deployment-status handling to use
github.event.deployment_status.environment_url instead of
github.event.deployment_status.target_url. Preserve the existing non-empty check
and GITHUB_OUTPUT assignment so ZAP receives the deployed environment URL.

Comment on lines +43 to +49
- name: ZAP Baseline Passive Scan
id: zap
uses: zaproxy/action-baseline@v0.10.0
with:
target: ${{ steps.target.outputs.url }}
cmd_options: '-I -T 60'
fail_action: true

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== workflow excerpt =="
sed -n '1,140p' .github/workflows/zap-security-scan.yml

echo
echo "== zap-related files =="
rg -n "riskcode|fail_action|baseline|severity|counts|ZAP|zap" .github/workflows/zap-security-scan.yml .github 2>/dev/null || true

echo
echo "== action usage references =="
rg -n "zaproxy/action-baseline|fail_action|cmd_options" .github/workflows || true

Repository: ritik4ever/stellar-goal-vault

Length of output: 9179


🌐 Web query:

ZAP action baseline fail_action true WARN FAIL riskcode documentation

💡 Result:

In the context of the OWASP ZAP Baseline Scan GitHub Action, the fail_action parameter is used to control whether the GitHub workflow run status is marked as failed when ZAP identifies security alerts [1][2][3]. When set to true, the GitHub Action will fail if the underlying ZAP baseline scan identifies any alerts or fails to scan the target [2]. If set to false (the default), the action will report the results but will not fail the GitHub workflow status due to identified alerts [2][3]. Regarding the control of alert levels (WARN, FAIL, etc.), this is managed separately from the fail_action parameter. You can configure which rules trigger a failure using a ZAP configuration file [4][5]. In this file, you can change the alert level of specific rules to FAIL, which will cause the ZAP scan script itself to return a non-zero exit code, or IGNORE, which suppresses them [4][6][7]. The baseline scan script typically classifies alerts as WARN by default [5]. When running the ZAP Docker container, you can pass a configuration file using the -c command-line option to customize these rule levels [4][7]. In summary: - fail_action: true (in the GitHub Action) determines if the overall CI/CD job fails when any alerts are found [2]. - Configuration file (rules.tsv): Used to define which specific alert risk codes or rules should be treated as FAIL (causing the scan to exit with a failure code) or IGNORE (ignoring them entirely) [4][5]. Top results: [1], [2], [4], [5]

Citations:


Make the parsed medium/high alert count the gate.

fail_action: true makes this step fail when ZAP Baseline finds alerts, but Baseline rules default to WARN, and -I prevents warning rules from making the scan exit non-zero unless they are reconfigured as FAIL. The later explicit check counts riskcode == "2" and "3", so if the two paths disagree the summary can say deploy is blocked after the job already failed for unrelated warnings. Set fail_action: false and use the explicit report check as the workflow-level failure.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/zap-security-scan.yml around lines 43 - 49, Update the ZAP
Baseline Passive Scan step identified by id zap to set fail_action to false,
allowing the scan to complete without failing on its default alert handling.
Preserve the later explicit report check as the workflow-level gate based on
parsed medium and high risk counts.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== workflow excerpt =="
if [ -f .github/workflows/zap-security-scan.yml ]; then
  nl -ba .github/workflows/zap-security-scan.yml | sed -n '1,120p'
else
  echo "workflow not found"
fi

echo
echo "== zap/action references =="
rg -n "zaproxy/action-baseline|action-baseline|report_json|report_html|report_md|results\.sarif|zap-report|sarif|sarif|artifacts|upload-artifact" .github/workflows || true

Repository: ritik4ever/stellar-goal-vault

Length of output: 230


🌐 Web query:

zaproxy action-baseline v0.10.0 report_json.json report_html.html report_md.md sarif

💡 Result:

The zaproxy/action-baseline GitHub Action, including version 0.10.0 [1][2], facilitates ZAP baseline scans by wrapping the ZAP Docker baseline scan script [3][4]. Regarding the requested report files (report_json.json, report_html.html, report_md.md) and SARIF support: 1. JSON, HTML, and Markdown Reports: The underlying ZAP baseline scan script supports generating these reports via command-line flags (-J, -r, -w) [5][6]. To use these with the GitHub Action, you must pass the corresponding flags through the cmd_options input [3][7]. For example, you could include: cmd_options: '-J report_json.json -r report_html.html -w report_md.md' 2. SARIF Support: The official action does not natively support SARIF report generation as a direct input or output field [7]. While ZAP has a SARIF report generator add-on [8][9], users typically must configure the underlying ZAP container to generate it via cmd_options or use third-party methods to convert ZAP output to SARIF for GitHub Advanced Security integration [9]. 3. Artifact Handling: By default, the action uploads an artifact named zap_scan [7]. If you generate additional files (like the specific report files requested) within the Docker container during the scan, they will not be automatically uploaded as GitHub workflow artifacts unless you explicitly configure the action or add a subsequent step to upload them using the official actions/upload-artifact action. Version 0.10.0 introduced support for authentication environment variables (ZAP_AUTH_HEADER, ZAP_AUTH_HEADER_VALUE, ZAP_AUTH_HEADER_SITE) [1][2], but did not introduce native support for the specific report formats listed in your query [2].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

tool() {
  local name="$1"
  command -v "$name" >/dev/null 2>&1 && printf '%s\n' "$name"
}
for n in nl head sed grep awk find git; do
  echo "tool=$n"
  tool "$n"
done

echo "== workflow excerpt =="
if [ -f .github/workflows/zap-security-scan.yml ]; then
  awk '{printf "%5d\t%s\n", NR, $0}' .github/workflows/zap-security-scan.yml | sed -n '1,130p'
else
  echo "workflow not found"
fi

echo
echo "== zap/report references in workflows =="
grep -RInE "zaproxy/action-baseline|action-baseline|report_json|report_html|report_md|results\.sarif|zap-report|upload-artifact|sarif" .github/workflows .github 2>/dev/null || true

echo
echo "== fetch action metadata/release files =="
python3 - <<'PY'
import urllib.request
for url in [
    "https://raw.githubusercontent.com/zaproxy/action-baseline/v0.10.0/action.yml",
    "https://raw.githubusercontent.com/zaproxy/action-baseline/v0.10.0/dist/index.js",
    "https://raw.githubusercontent.com/zaproxy/action-baseline/v0.10.0/README.md",
]:
    print(f"\n--- {url} ---")
    try:
        data = urllib.request.urlopen(url, timeout=20).read().decode("utf-8", "replace")
    except Exception as e:
        print(f"ERROR: {e}")
        continue
    for term in ["report_json", "report_html", "report_md", "sarif", "commandOptions", "cmdOptions"]:
        if term in data:
            print(term)
    # print concise contexts around report paths
    for i, line in enumerate(data.splitlines(), 1):
        if "report_json" in line or "report_html" in line or "report_md" in line or "sarif" in line:
            start=max(1,i-3); end=min(len(data.splitlines()),i+3)
            lines=data.splitlines()
            for j in range(start,end+1):
                print(f"{j:5d}\t{lines[j-1]}")
PY

Repository: ritik4ever/stellar-goal-vault

Length of output: 175


Align the report paths with the baseline action output.

zaproxy/action-baseline@v0.10.0 emits report_json.json, report_html.html, and report_md.md; it does not create results.sarif or zap-report.*, so the SARIF upload and JSON enforcement steps will miss the generated reports. Use the emitted filenames for JSON/HTML processing, and add a separate SARIF-generation/conversion step if SARIF is required.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/zap-security-scan.yml around lines 43 - 49, The ZAP
workflow references report filenames that the baseline action does not generate.
Update the JSON and HTML processing steps to use report_json.json and
report_html.html, and update Markdown handling to use report_md.md; if SARIF
remains required, add a separate conversion step that produces the SARIF file
before upload.


- name: ZAP Baseline Passive Scan
id: zap
uses: zaproxy/action-baseline@v0.10.0

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== workflow excerpt =="
if [ -f .github/workflows/zap-security-scan.yml ]; then
  nl -ba .github/workflows/zap-security-scan.yml | sed -n '1,80p'
else
  echo "missing .github/workflows/zap-security-scan.yml"
fi

echo
echo "== current action files in GitHub =="
tmpdir="$(mktemp -d)"
curl -fsSL -o "$tmpdir/action-current.yml" https://raw.githubusercontent.com/zaproxy/action-baseline/main/action.yml 2>/dev/null || true
curl -fsSL -o "$tmpdir/action-v010.yml" https://raw.githubusercontent.com/zaproxy/action-baseline/v0.10.0/action.yml 2>/dev/null || true
if [ -s "$tmpdir/action-current.yml" ] || [ -s "$tmpdir/action-v010.yml" ]; then
  node - <<'JS'
const fs = require('fs');
const path = require('path');
const files = [
  'current-main',
  'v0.10.0'
].map(k => ({ k, v: path.join(process.env.HOME === undefined ? '/tmp' : process.env.HOME, 'NOTUSED')) });
console.log("not executed");
JS
fi
for f in "$tmpdir"/action-*.yml; do
  [ -s "$f" ] || continue
  echo "--- $f ---"
  nl -ba "$f" | sed -n '1,80p'
done

echo
echo "== github-hosted runner node version facts =="
python3 - <<'PY'
from datetime import datetime
print("GitHub Actions runner node support window context:")
print("- Node.js 16 was removed from hosted-runners on 2024-11-12.")
print("The current v0.10.0 release pin should be examined for runs.using value.")
PY

Repository: ritik4ever/stellar-goal-vault

Length of output: 230


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== workflow excerpt =="
if [ -f .github/workflows/zap-security-scan.yml ]; then
  nl -ba .github/workflows/zap-security-scan.yml | sed -n '1,80p'
else
  echo "missing .github/workflows/zap-security-scan.yml"
fi

echo
echo "== current action files in GitHub =="
tmpdir="$(mktemp -d)"
curl -fsSL -o "$tmpdir/action-current.yml" https://raw.githubusercontent.com/zaproxy/action-baseline/main/action.yml || true
curl -fsSL -o "$tmpdir/action-v010.yml" https://raw.githubusercontent.com/zaproxy/action-baseline/v0.10.0/action.yml || true

for f in "$tmpdir"/action-*.yml; do
  [ -s "$f" ] || continue
  echo "--- $f ($(basename "$f")) ---"
  nl -ba "$f" | sed -n '1,80p'
done

echo
echo "== Node version references in zaps baseline repository tags =="
python3 - <<'PY'
import subprocess, json, re
tags = []
try:
  tags = json.loads(subprocess.check_output(["git", "ls-remote", "--tags", "https://github.com/zaproxy/action-baseline.git"], text=True))
except Exception as e:
  print("git ls-remote failed:", e)
for ref, sha in sorted(tags.items()):
    if "refs/tags/v0.10.0" in ref:
        print(ref, sha)
PY

Repository: ritik4ever/stellar-goal-vault

Length of output: 230


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== workflow excerpt =="
if [ -f .github/workflows/zap-security-scan.yml ]; then
  awk '{printf "%6d\t%s\n", NR, $0}' .github/workflows/zap-security-scan.yml | sed -n '1,100p'
else
  echo "missing .github/workflows/zap-security-scan.yml"
fi

echo
echo "== action.yml files =="
tmpdir="$(mktemp -d)"
curl -fsSL -o "$tmpdir/action-current.yml" https://raw.githubusercontent.com/zaproxy/action-baseline/main/action.yml || true
curl -fsSL -o "$tmpdir/action-v010.yml" https://raw.githubusercontent.com/zaproxy/action-baseline/v0.10.0/action.yml || true
curl -fsSL -o "$tmpdir/action-v011.yml" https://raw.githubusercontent.com/zaproxy/action-baseline/v0.11.0/action.yml || true

for f in "$tmpdir"/action-*.yml; do
  [ -s "$f" ] || continue
  echo "--- $f ($(basename "$f")) ---"
  awk '/^(name|runs):|^[[:space:]]*using:|^[[:space:]]*main:|^  node-version:/' "$f" || sed -n '1,80p' "$f"
done

echo
echo "== package manifests mentioning node versions =="
for p in package.json package-lock.json pnpm-lock.yaml yarn.lock; do
  if [ -f "$p" ]; then
    echo "--- $p ---"
    grep -nEi '"(node|engines|packageManager)|engines:' "$p" || true
  fi
done

Repository: ritik4ever/stellar-goal-vault

Length of output: 12632


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== zaps action tags/branch references =="
python3 - <<'PY'
import subprocess, sys
for ref_pat in [
    ["git", "ls-remote", "--exit-code", "--heads", "https://github.com/zaproxy/action-baseline.git"],
    ["git", "ls-remote", "--exit-code", "--tags", "https://github.com/zaproxy/action-baseline.git"],
]:
    cmd = ref_pat[:]
    try:
        out = subprocess.check_output(cmd, stderr=subprocess.DEVNULL, text=True)
    except subprocess.CalledProcessError as exc:
        print(" ".join(cmd), "no_match", file=sys.stderr)
        continue
    for line in out.splitlines():
        if "node" in line.lower() or "main" in line.lower():
            print(line)
PY

echo
echo "== report inputs from action manifests =="
tmpdir="$(mktemp -d)"
url='https://raw.githubusercontent.com/zaproxy/action-baseline/${REF}/action.yml'
for ref in v0.11.0 main; do
  curl -fsSL -o "$tmpdir/action-$ref.yml" "${url/\${REF}/$ref}" || continue
  echo "--- $ref input/output scan summary ---"
  awk '
    /^inputs:/,/^(outputs:|env:|runs:|branding:|name:)/ {print}
    /^outputs:/,/^(env:|runs:|branding:|name:)/ {print}
  ' "$tmpdir/action-$ref.yml"
done

Repository: ritik4ever/stellar-goal-vault

Length of output: 648


Upgrade the pinned ZAP action off Node16.

zaproxy/action-baseline@v0.10.0 still uses runs.using: node16, and the scan runs on ubuntu-latest where Node16 is no longer supported on hosted runners. Switch to the latest supported release that declares node20 and verify its input/output contract before merging.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/zap-security-scan.yml at line 45, Update the
zaproxy/action-baseline reference in the workflow to the latest supported
release that declares runs.using node20, and verify that its inputs and outputs
remain compatible with the existing scan step before merging.

Comment on lines +68 to +85
if [ -f zap-report.json ]; then
HIGH_COUNT=$(jq '[.site[]?.alerts[]? | select(.riskcode == "3" or .riskcode == "2")] | length' zap-report.json 2>/dev/null || echo "0")
echo "## OWASP ZAP Scan Results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- **Target:** ${{ steps.target.outputs.url }}" >> $GITHUB_STEP_SUMMARY
echo "- **High-severity alerts:** $(jq '[.site[]?.alerts[]? | select(.riskcode == "3")] | length' zap-report.json 2>/dev/null || echo "0")" >> $GITHUB_STEP_SUMMARY
echo "- **Medium-severity alerts:** $(jq '[.site[]?.alerts[]? | select(.riskcode == "2")] | length' zap-report.json 2>/dev/null || echo "0")" >> $GITHUB_STEP_SUMMARY
echo "- **Low-severity alerts:** $(jq '[.site[]?.alerts[]? | select(.riskcode == "1")] | length' zap-report.json 2>/dev/null || echo "0")" >> $GITHUB_STEP_SUMMARY
if [ "$HIGH_COUNT" -gt 0 ]; then
echo "❌ **Deploy blocked:** $HIGH_COUNT high-severity or medium-severity findings detected." >> $GITHUB_STEP_SUMMARY
echo "Please review the ZAP report artifact for details."
exit 1
else
echo "✅ **No high-severity or medium-severity findings.** Scan passed." >> $GITHUB_STEP_SUMMARY
fi
else
echo "No ZAP JSON report found. Scan results may not be available."
fi

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Fail closed when the report is missing or invalid.

jq errors are converted to zero counts, and the missing-report branch exits successfully. A failed or malformed scan can therefore appear to pass with no findings. Require a non-empty, schema-valid JSON report and exit nonzero on any parsing or publication failure.

🧰 Tools
🪛 zizmor (1.28.0)

[info] 72-72: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/zap-security-scan.yml around lines 68 - 85, Update the ZAP
report handling around the zap-report.json existence check and jq count
calculations to fail closed: require a non-empty report, validate its
JSON/schema before counting alerts, and treat every jq or summary-publication
failure as an error. Ensure malformed or missing reports and failed writes to
GITHUB_STEP_SUMMARY exit nonzero instead of reporting a successful scan, while
preserving the existing blocking behavior for high- or medium-severity findings.

@ritik4ever

Copy link
Copy Markdown
Owner

Hi @muizbolaji4,

This PR could not be merged because it has merge conflicts with the target branch.

Please resolve the merge conflicts, push the updated changes, and the PR can be reviewed and merged.

Thank you!

1 similar comment
@ritik4ever

Copy link
Copy Markdown
Owner

Hi @muizbolaji4,

This PR could not be merged because it has merge conflicts with the target branch.

Please resolve the merge conflicts, push the updated changes, and the PR can be reviewed and merged.

Thank you!

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] Add OWASP ZAP automated security scan

2 participants