Visibility internal Owner _ Approver _ Created _ Updated _
scan-live.sh
| Field | Value |
|---|---|
| Type | Shell |
| Source | Forge/Skills/Security_Scan/scripts/scan-live.sh |
| Parent | Forge |
| GitHub | Forge/Skills/Security_Scan/scripts/scan-live.sh |
This page is auto-generated. Edit the source to change the content.
#!/usr/bin/env bash
# Runs DAST against a LIVE target. Refuses to run unless the host is listed
# in the scope file -- this is what stops a typo from scanning production or
# somebody else's server.
#
# Scope file: .security-scan/scope.txt (one hostname per line, # for comments)
#
# Usage: scan-live.sh --target https://staging.example.com [--out DIR] [--active]
#
# Default is a PASSIVE baseline: it crawls and inspects responses but does not
# send attack payloads. --active sends real payloads and can mutate data --
# only use it against a disposable environment with seeded data.
set -uo pipefail
TARGET=""
OUT=".security-scan/results"
SCOPE=".security-scan/scope.txt"
ACTIVE=0
while [[ $# -gt 0 ]]; do
case "$1" in
--target) TARGET="$2"; shift 2 ;;
--out) OUT="$2"; shift 2 ;;
--scope) SCOPE="$2"; shift 2 ;;
--active) ACTIVE=1; shift ;;
*) echo "unknown argument: $1" >&2; exit 2 ;;
esac
done
if [[ -z "$TARGET" ]]; then
echo "error: --target is required. This script will not guess a target." >&2
exit 2
fi
HOST="$(printf '%s' "$TARGET" | sed -E 's#^[a-zA-Z]+://##; s#[:/].*$##')"
if [[ ! -f "$SCOPE" ]]; then
cat >&2 <<EOF
error: no scope file at $SCOPE
Create it and list the hosts you are authorised to scan, one per line:
mkdir -p "$(dirname "$SCOPE")"
echo "staging.example.com" >> "$SCOPE"
Scanning a host you do not control is unlawful in most jurisdictions. The
scope file exists so that is a deliberate act rather than a typo.
EOF
exit 2
fi
if ! grep -qxF "$HOST" <(grep -vE '^\s*(#|$)' "$SCOPE"); then
echo "error: '$HOST' is not listed in $SCOPE -- refusing to scan." >&2
echo "In scope: $(grep -vE '^\s*(#|$)' "$SCOPE" | tr '\n' ' ')" >&2
exit 2
fi
mkdir -p "$OUT"
# Absolute path for report output (native ZAP cwd, or Docker volume mount).
OUT_ABS="$(cd "$OUT" && pwd)"
echo "target: $TARGET"
echo "host: $HOST (in scope)"
echo "mode: $([[ $ACTIVE == 1 ]] && echo 'ACTIVE -- sends payloads, may mutate data' || echo 'passive baseline')"
echo
if [[ $ACTIVE == 1 ]]; then
echo "!!! Active mode. Confirm this is a disposable environment with seeded"
echo "!!! data, not production. Ctrl-C within 10s to abort."
sleep 10
fi
ZAP_SCRIPT=$([[ $ACTIVE == 1 ]] && echo "zap-full-scan.py" || echo "zap-baseline.py")
if command -v "$ZAP_SCRIPT" >/dev/null 2>&1 && command -v zap.sh >/dev/null 2>&1; then
# Prefer native ZAP (Forgentic / Railway image — no Docker-in-Docker).
echo ">>> ZAP (native $ZAP_SCRIPT)"
(
cd "$OUT_ABS"
python3 "$(command -v "$ZAP_SCRIPT")" -t "$TARGET" -J zap.json -r zap.html
) || echo " ZAP exited nonzero (alerts found or error) -- see $OUT/zap.html"
elif command -v docker >/dev/null 2>&1; then
# Local fallback when ZAP is not installed natively.
echo ">>> ZAP (Docker $ZAP_SCRIPT)"
docker run --rm -v "$OUT_ABS:/zap/wrk/:rw" \
ghcr.io/zaproxy/zaproxy:stable \
"$ZAP_SCRIPT" -t "$TARGET" -J zap.json -r zap.html \
|| echo " ZAP exited nonzero (alerts found or error) -- see $OUT/zap.html"
else
echo "(ZAP not available -- need native zap.sh + $ZAP_SCRIPT, or Docker; skipping)"
fi
if command -v nuclei >/dev/null 2>&1; then
echo ">>> Nuclei"
NUCLEI_ARGS=(-u "$TARGET" -jsonl -o "$OUT/nuclei.jsonl" -severity low,medium,high,critical)
[[ $ACTIVE == 0 ]] && NUCLEI_ARGS+=(-exclude-tags dos,fuzz,intrusive)
nuclei "${NUCLEI_ARGS[@]}" || echo " nuclei exited nonzero"
else
echo "(nuclei not installed -- skipping)"
fi
echo
echo "=== results in $OUT ==="
ls -1 "$OUT" 2>/dev/null
exit 0