AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Scan Vuln

skill-thapr0digy-skills-scan-vuln · by thapr0digy

Security vulnerability validation — comprehensive vulnerability assessment, security control testing, and compliance verification using systematic assessment methodologies. Invoke via /scan-vuln [target].

— No reviews yet
0 installs
35 views
0.0% view→install

Install

$ agentstack add skill-thapr0digy-skills-scan-vuln

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • ✓ Prompt-injection patterns
  • ✓ Secret / credential exfiltration
  • ✓ Dangerous shell & filesystem operations
  • ✓ Untrusted network calls
  • ✓ Known-malicious package signatures

What it can access

  • ● Network access Used
  • ✓ Filesystem access No
  • ✓ Shell / process execution No
  • ✓ Environment & secrets No
  • ✓ Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-thapr0digy-skills-scan-vuln)

Reliability & compatibility

✓ Security review passed
0 installs to date
— no reviews yet
○ 4mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Scan Vuln? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

@pentest-core/skills/shared/engagement-resolver.md @pentest-core/skills/shared/scope-validator.md @pentest-core/skills/shared/remote-exec.md @pentest-core/skills/shared/activity-log.md

/scan-vuln — Security Vulnerability Validation

You are conducting systematic vulnerability assessment to identify security weaknesses, validate security controls, and ensure compliance with security standards. You use comprehensive scanning methodologies combined with manual validation techniques to provide accurate vulnerability assessment results for security improvement planning.


Step 1: Resolve Active Engagement

Run the engagement resolver block verbatim before any other logic. Also read custom_templates_dir from the engagement for use in Step 4.

# --- Engagement Resolver ---
ENGAGEMENT_JSON=$(cat ~/.pentest/active-engagement 2>/dev/null)

if [ -z "$ENGAGEMENT_JSON" ]; then
  echo "No active engagement found. Run /pentest-init or /pentest-switch." >&2
  exit 1
fi

if [ ! -f "$ENGAGEMENT_JSON" ]; then
  echo "Active engagement path '$ENGAGEMENT_JSON' does not exist. Run /pentest-switch." >&2
  exit 1
fi

ENGAGEMENT_ID=$(jq -r '.engagement_id' "$ENGAGEMENT_JSON")
OUTPUT_DIR=$(jq -r '.output_dir' "$ENGAGEMENT_JSON")
ASSESSOR=$(whoami)

ASSESSOR_MATCH=$(jq -r --arg h "$ASSESSOR" '.security assessors[] | select(.handle == $h) | .handle' "$ENGAGEMENT_JSON")
if [ -z "$ASSESSOR_MATCH" ]; then
  echo "Operator '$ASSESSOR' is not registered on this engagement." >&2
  exit 1
fi

CUSTOM_TEMPLATES_DIR=$(jq -r '.custom_templates_dir // empty' "$ENGAGEMENT_JSON")
# --- End Engagement Resolver ---

After this block, $ENGAGEMENT_ID, $OUTPUT_DIR, $ASSESSOR, and optionally $CUSTOM_TEMPLATES_DIR are set and valid. If the resolver fails for any reason, stop and tell the user to run /pentest-init.


Step 2: Parse Arguments and Determine Targets

Accepted input formats

  • IP address — e.g., 10.0.0.1
  • URL — e.g., https://app.acme.com
  • CIDR range — e.g., 10.0.0.0/24
  • File path — e.g., @/path/to/targets.txt — one target per line
ARG="${1:-}"

if [ -n "$ARG" ]; then
  if echo "$ARG" | grep -q '^@'; then
    TARGETS_FILE="${ARG#@}"
    if [ ! -f "$TARGETS_FILE" ]; then
      echo "Targets file not found: $TARGETS_FILE" >&2
      exit 1
    fi
    TARGET_IS_FILE=true
  else
    # Write single target to a temp file for nuclei -l flag
    TARGETS_FILE=$(mktemp)
    echo "$ARG" > "$TARGETS_FILE"
    TARGET_IS_FILE=false
  fi
else
  # Build target list from recon and enum outputs
  TARGETS_FILE="${OUTPUT_DIR}/findings/scan-vuln-targets-${ASSESSOR}-$(date +%s).txt"

  # Pull hosts from active recon profiles
  for f in "${OUTPUT_DIR}"/recon/active-*.json; do
    [ -f "$f" ] && jq -r '
      .hosts[] |
      .ip as $ip |
      .ports[] |
      select(.state == "open") |
      if .category == "web" then
        ($ip + ":" + (.port | tostring))
      else
        $ip
      end
    ' "$f" 2>/dev/null
  done >> "$TARGETS_FILE"

  # Pull live URLs from web enumeration outputs
  for f in "${OUTPUT_DIR}"/enum/web-*.json; do
    [ -f "$f" ] && jq -r '.live_urls[]? // empty' "$f" 2>/dev/null
  done >> "$TARGETS_FILE"

  sort -u -o "$TARGETS_FILE" "$TARGETS_FILE"

  if [ ! -s "$TARGETS_FILE" ]; then
    echo "No target provided and no recon/enum data found." >&2
    echo "Provide a target: /scan-vuln " >&2
    echo "Or run /recon-active and /enum-web first." >&2
    exit 1
  fi

  echo "No target specified — built target list from recon/enum data: $TARGETS_FILE"
fi

TARGET_COUNT=$(wc -l /dev/null)
HOST_NAME="${HOST_NAME:-${DEFAULT_HOST:-local}}"

Full scope validation

For each target in $TARGETS_FILE, run complete scope validation per scope-validator.md. Perform all checks including the testing window check — nuclei sends active probes and must respect testing windows. Hard-block out-of-scope targets; warn and confirm for unlisted targets. Do not batch-validate — check each target individually.

Scan mode selection

Ask the user:

> Scan mode: > 1. Quick — critical and high severity templates only, runs faster (~5–15 min per 10 hosts) > 2. Comprehensive — all severity levels, full template coverage (slower, recommended for final assessments) > > Which mode? (1/2, default: 1)

Store as SCAN_MODE (quick or comprehensive).

mkdir -p "${OUTPUT_DIR}/findings"
TIMESTAMP=$(date -u +"%Y%m%dT%H%M%SZ")

Step 3: Check Tool Availability

Nuclei is required. If it is not available, abort.

if ! which nuclei > /dev/null 2>&1; then
  jq -nc \
    --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
    --arg security assessor "$ASSESSOR" \
    --arg action "tool_check" \
    --arg command "which nuclei" \
    --arg status "failed" \
    --arg result "not found" \
    '{ts:$ts, security assessor:$security assessor, action:$action, command:$command, status:$status, result:$result}' \
    >> "${OUTPUT_DIR}/activity.log"
  echo "nuclei not found. Install from https://github.com/projectdiscovery/nuclei or via: go install github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest" >&2
  exit 1
fi

NUCLEI_VERSION=$(nuclei -version 2>&1 | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+' | head -1)

jq -nc \
  --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
  --arg security assessor "$ASSESSOR" \
  --arg action "tool_check" \
  --arg command "exit 1" \
  --arg status "completed" \
  --arg result "available: $NUCLEI_VERSION" \
  '{ts:$ts, security assessor:$security assessor, action:$action, command:$command, status:$status, result:$result}' \
  >> "${OUTPUT_DIR}/activity.log"

Offer to update templates:

> nuclei $NUCLEI_VERSION found. Update nuclei templates before scanning? (yes/no, default: yes)

If yes (or default):

nuclei -update-templates -silent

Step 4: Build Template Selection

Read tech stack data from recon outputs to select the most relevant nuclei template paths. Only load templates you have evidence for — do not throw every available template at every target.

Always-on template categories

These run regardless of discovered tech stack:

TEMPLATE_ARGS="-t cves/ -t misconfiguration/ -t exposures/"

Tech-stack-aware templates

Read httpx and whatweb outputs to determine which technologies are present:

DETECTED_TECH=""

for f in "${OUTPUT_DIR}"/recon/httpx-*.json; do
  [ -f "$f" ] && DETECTED_TECH="$DETECTED_TECH $(jq -r '.tech[]? // .technologies[]? // empty' "$f" 2>/dev/null | tr '[:upper:]' '[:lower:]')"
done

for f in "${OUTPUT_DIR}"/recon/whatweb-*.json; do
  [ -f "$f" ] && DETECTED_TECH="$DETECTED_TECH $(jq -r '.[].plugins | keys[]' "$f" 2>/dev/null | tr '[:upper:]' '[:lower:]')"
done

DETECTED_TECH=$(echo "$DETECTED_TECH" | tr ' ' '\n' | sort -u | tr '\n' ' ')

For each technology present in $DETECTED_TECH, add the corresponding template path:

| Technology keyword(s) | Template path to add | |---|---| | apache | -t technologies/apache/ | | nginx | -t technologies/nginx/ | | wordpress | -t technologies/wordpress/ | | joomla | -t technologies/joomla/ | | drupal | -t technologies/drupal/ | | php | -t technologies/php/ | | java, spring, springframework | -t technologies/java/ -t technologies/spring/ | | asp.net, aspnet | -t technologies/aspnet/ | | node, nodejs, express | -t technologies/nodejs/ | | iis | -t technologies/iis/ | | tomcat | -t technologies/tomcat/ | | jenkins | -t technologies/jenkins/ | | gitlab | -t technologies/gitlab/ | | grafana | -t technologies/grafana/ |

# Example detection and conditional addition — repeat for each technology
if echo "$DETECTED_TECH" | grep -qi "apache"; then
  TEMPLATE_ARGS="$TEMPLATE_ARGS -t technologies/apache/"
fi
if echo "$DETECTED_TECH" | grep -qi "nginx"; then
  TEMPLATE_ARGS="$TEMPLATE_ARGS -t technologies/nginx/"
fi
if echo "$DETECTED_TECH" | grep -qiE "wordpress|wp-"; then
  TEMPLATE_ARGS="$TEMPLATE_ARGS -t technologies/wordpress/"
fi
if echo "$DETECTED_TECH" | grep -qi "joomla"; then
  TEMPLATE_ARGS="$TEMPLATE_ARGS -t technologies/joomla/"
fi
if echo "$DETECTED_TECH" | grep -qi "drupal"; then
  TEMPLATE_ARGS="$TEMPLATE_ARGS -t technologies/drupal/"
fi
if echo "$DETECTED_TECH" | grep -qi "php"; then
  TEMPLATE_ARGS="$TEMPLATE_ARGS -t technologies/php/"
fi
if echo "$DETECTED_TECH" | grep -qiE "java|spring"; then
  TEMPLATE_ARGS="$TEMPLATE_ARGS -t technologies/java/ -t technologies/spring/"
fi
if echo "$DETECTED_TECH" | grep -qiE "asp\.net|aspnet"; then
  TEMPLATE_ARGS="$TEMPLATE_ARGS -t technologies/aspnet/"
fi
if echo "$DETECTED_TECH" | grep -qiE "node|nodejs|express"; then
  TEMPLATE_ARGS="$TEMPLATE_ARGS -t technologies/nodejs/"
fi
if echo "$DETECTED_TECH" | grep -qi "iis"; then
  TEMPLATE_ARGS="$TEMPLATE_ARGS -t technologies/iis/"
fi
if echo "$DETECTED_TECH" | grep -qi "tomcat"; then
  TEMPLATE_ARGS="$TEMPLATE_ARGS -t technologies/tomcat/"
fi
if echo "$DETECTED_TECH" | grep -qi "jenkins"; then
  TEMPLATE_ARGS="$TEMPLATE_ARGS -t technologies/jenkins/"
fi
if echo "$DETECTED_TECH" | grep -qi "gitlab"; then
  TEMPLATE_ARGS="$TEMPLATE_ARGS -t technologies/gitlab/"
fi
if echo "$DETECTED_TECH" | grep -qi "grafana"; then
  TEMPLATE_ARGS="$TEMPLATE_ARGS -t technologies/grafana/"
fi

Custom templates

If $CUSTOM_TEMPLATES_DIR is set and the directory exists, add it:

if [ -n "$CUSTOM_TEMPLATES_DIR" ] && [ -d "$CUSTOM_TEMPLATES_DIR" ]; then
  TEMPLATE_ARGS="$TEMPLATE_ARGS -t ${CUSTOM_TEMPLATES_DIR}"
fi

Severity filter

if [ "$SCAN_MODE" = "quick" ]; then
  SEVERITY_FLAG="-severity critical,high"
else
  SEVERITY_FLAG=""
fi

Step 5: Handle Authentication

If the targets include authenticated web applications, ask the user:

> Authentication — does any target require authentication to scan effectively? > 1. Cookie (paste your session cookie value) > 2. Bearer token (paste your token) > 3. Basic auth (format: username:password) > 4. No authentication needed

For each credential provided, store as a header flag:

AUTH_HEADERS=""

# Cookie
# AUTH_HEADERS="-H 'Cookie: session='"

# Bearer token
# AUTH_HEADERS="-H 'Authorization: Bearer '"

# Basic auth
# AUTH_HEADERS="-H 'Authorization: Basic '"

If multiple auth types are needed (different credentials per target), ask the user which targets each set of credentials applies to, and plan to run nuclei once per credential set against the appropriate target subset.

Log the auth method used (not the credential value itself):

jq -nc \
  --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
  --arg security assessor "$ASSESSOR" \
  --arg action "scan" \
  --arg command "nuclei auth configuration: ${AUTH_METHOD:-none}" \
  --arg status "dispatched" \
  --arg result "auth configured: ${AUTH_METHOD:-none}" \
  '{ts:$ts, security assessor:$security assessor, action:$action, command:$command, status:$status, result:$result}' \
  >> "${OUTPUT_DIR}/activity.log"

Step 6: Execute Nuclei

Rate limit selection

Check the engagement RoE for rate-limit guidance. Ask the user:

> Rate limiting: > 1. Default (150 req/s) — suitable for most external assessments > 2. Conservative (50 req/s) — recommended for red team ops, fragile targets, or when RoE restricts load > 3. Custom — enter requests per second > > Which setting? (1/2/3, default: 1)

For red team engagements (type: "red_team" in engagement.json), default to conservative:

ENGAGEMENT_TYPE=$(jq -r '.type' "$ENGAGEMENT_JSON")
if [ "$ENGAGEMENT_TYPE" = "red_team" ]; then
  RATE_LIMIT=50
else
  RATE_LIMIT=150
fi
# Override with user selection

Output path

NUCLEI_RAW="${OUTPUT_DIR}/findings/nuclei-raw-${ASSESSOR}-$(date +%s).jsonl"

Execution command

CMD="nuclei -l ${TARGETS_FILE} ${TEMPLATE_ARGS} ${SEVERITY_FLAG} ${AUTH_HEADERS} -jsonl -o ${NUCLEI_RAW} -silent -rate-limit ${RATE_LIMIT} -bulk-size 25 -concurrency 10"

Dispatch strategy based on target count

TARGET_COUNT=$(wc -l > "${OUTPUT_DIR}/activity.log"

Fewer than 10 targets — run synchronously:

$CMD

jq -nc \
  --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
  --arg security assessor "$ASSESSOR" \
  --arg action "scan" \
  --arg command "$CMD" \
  --arg status "$([ $? -eq 0 ] && echo completed || echo failed)" \
  --arg output_file "$NUCLEI_RAW" \
  '{ts:$ts, security assessor:$security assessor, action:$action, command:$command,
    status:$status, output_file:$output_file}' \
  >> "${OUTPUT_DIR}/activity.log"

10–50 targets — run synchronously with a warning to the user:

> Scanning $TARGET_COUNT targets synchronously. This may take 15–60 minutes. Do not close this session.

50+ targets — dispatch asynchronously using the remote execution abstraction from remote-exec.md. Use $HOST_NAME to determine SSH, SSM, or local tmux dispatch:

SESSION_NAME="${ENGAGEMENT_ID}-nuclei-$(date +%s)"

# Dispatch per remote-exec.md — SSH, SSM, or local tmux based on $HOST_NAME
# For local execution:
tmux new-session -d -s "$SESSION_NAME" "$CMD"

jq -nc \
  --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
  --arg security assessor "$ASSESSOR" \
  --arg action "scan" \
  --arg command "$CMD" \
  --arg status "dispatched" \
  --arg session "$SESSION_NAME" \
  --arg remote_host "$HOST_NAME" \
  --arg output_file "$NUCLEI_RAW" \
  '{ts:$ts, security assessor:$security assessor, action:$action,     command:$command, status:$status, session:$session,
    remote_host:$remote_host, output_file:$output_file}' \
  >> "${OUTPUT_DIR}/activity.log"

Tell the user:

> Nuclei dispatched in tmux session $SESSION_NAME (remote: $HOST_NAME). > Output: $NUCLEI_RAW > Check progress: tmux attach -t $SESSION_NAME > > The skill will now wait for the output file to appear, then continue with parsing. You will be notified when parsing begins.

Wait for $NUCLEI_RAW to exist and stop growing before proceeding to Step 7.


Step 7: Parse Nuclei Output

Read $NUCLEI_RAW line by line. Each line is a JSON object from nuclei's -jsonl output. Map each line to the standard finding schema.

Field mapping

| Finding field | Nuclei source field | |---|---| | title | info.name | | severity | info.severity | | cvss.vector | info.classification.cvss-metrics (preferred); fallback canonical vector by severity (see below) | | cvss.score | info.classification.cvss-score (preferred); fallback by severity (see below) | | cwe | info.classification.cwe-id[0]; fallback: map from template tag/category (see below) | | description | info.description; generate from template name and severity if absent | | affected_assets | [""] | | evidence.steps | ["Nuclei template matched at "] | | evidence.tool_output | raw nuclei JSONL line | | impact | derive from severity and vulnerability type | | remediation | info.remediation if present | | references | info.reference array |

CVSS fallback canonical vectors

Use these only when info.classification.cvss-metrics is absent or empty. All vectors must pass ^CVSS:3.1/ pattern validation.

| Severity | Fallback vector | Fallback score | |---|---|---| | critical | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H | 9.8 | | high | CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H | 8.0 | | medium | CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N | 5.5 | | low | CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:N/A:N | 3.0 | | informational | CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:N | 0.0 |

CWE fallback mapping by template category

Use when info.classification.cwe-id is absent:

| Template tag / category | CWE | |---|---| | xss, cross-site-scripting | CWE-79 | | sqli, sql-injection | CWE-89 | | lfi, path-traversal | CWE-22 | | rce, code-injection | CWE-94 | | ssrf | CWE-918 | | xxe | CWE-611 | | redirect, open-redirect | CWE-601 | | idor, `broke

…

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.