Install
$ agentstack add skill-thapr0digy-skills-recon-active ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo 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.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
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 →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
/recon-active — Authorized Asset Discovery
You are performing authorized asset discovery and security assessment on approved infrastructure. You conduct network service enumeration and security configuration analysis to build comprehensive asset profiles: service inventory, technology stack, security configurations, and compliance status. Every target must pass scope validation before assessment begins.
Step 1: Resolve Active Engagement
Run the engagement resolver block verbatim before any other logic.
# --- 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
# --- End Engagement Resolver ---
After this block, $ENGAGEMENT_ID, $OUTPUT_DIR, and $ASSESSOR are guaranteed 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 - CIDR range — e.g.,
10.0.0.0/24 - Domain — e.g.,
app.acme.com - File path — e.g.,
@/path/to/hosts.txt— one target per line
ARG="${1:-}" # first argument passed to the skill
if [ -n "$ARG" ]; then
TARGET="$ARG"
elif ls "${OUTPUT_DIR}/recon/passive-"*.json > /dev/null 2>&1; then
# Fall back to most recent passive recon output — extract discovered hosts
PASSIVE_FILE=$(ls -t "${OUTPUT_DIR}/recon/passive-"*.json | head -1)
echo "No target specified — using discovered hosts from $PASSIVE_FILE"
TARGET="$(jq -r '.sections.resolved_hosts // empty' "$PASSIVE_FILE" 2>/dev/null)"
# If the passive file has a resolved hosts file reference, use scope.in_scope as fallback
if [ -z "$TARGET" ]; then
TARGET=$(jq -r '.scope.in_scope[]' "$ENGAGEMENT_JSON" 2>/dev/null | head -20 | tr '\n' ',')
fi
else
# No arg and no passive recon — fall back to scope
TARGET=$(jq -r '.scope.in_scope[]' "$ENGAGEMENT_JSON" 2>/dev/null | tr '\n' '\n')
if [ -z "$TARGET" ]; then
echo "No target provided and no in-scope entries found. Provide a target: /recon-active " >&2
exit 1
fi
fi
If the argument begins with @, treat the remainder as a file path and read targets from it:
if echo "$ARG" | grep -q '^@'; then
HOSTS_FILE="${ARG#@}"
if [ ! -f "$HOSTS_FILE" ]; then
echo "Hosts file not found: $HOSTS_FILE" >&2
exit 1
fi
TARGET="$HOSTS_FILE"
TARGET_IS_FILE=true
fi
Determine remote host
# Check if the engagement has a configured default remote host
DEFAULT_HOST=$(jq -r '.remote_hosts | keys[0] // "local"' "$ENGAGEMENT_JSON" 2>/dev/null)
HOST_NAME="${HOST_NAME:-${DEFAULT_HOST:-local}}"
If $HOST_NAME resolves to local (no remote hosts configured), all commands execute in the current shell.
Full scope validation
For each target, run complete scope validation per scope-validator.md. For active recon, perform all checks including the testing window check — active scans generate traffic and must respect testing windows.
# Normalize target
TARGET_ORIG="$TARGET"
if echo "$TARGET" | grep -qE '^https?://'; then
TARGET_HOST=$(python3 -c "from urllib.parse import urlparse; print(urlparse('$TARGET').hostname)")
else
TARGET_HOST="$TARGET"
fi
# Resolve hostname to IPs (skip for CIDRs and bare IPs, and for files)
if [ "${TARGET_IS_FILE:-false}" = "false" ]; then
if echo "$TARGET_HOST" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+(\/[0-9]+)?$'; then
TARGET_IPS="$TARGET_HOST"
else
TARGET_IPS=$(dig +short "$TARGET_HOST" | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$')
fi
fi
# Check out-of-scope (hard block)
OUT_OF_SCOPE=$(jq -r '.scope.out_of_scope[]' "$ENGAGEMENT_JSON" 2>/dev/null)
# Check in-scope (confirm or warn if unlisted)
IN_SCOPE=$(jq -r '.scope.in_scope[]' "$ENGAGEMENT_JSON" 2>/dev/null)
# Check testing window
WINDOWS=$(jq -c '.roe.testing_windows' "$ENGAGEMENT_JSON" 2>/dev/null)
TIMEZONE=$(jq -r '.roe.timezone // "UTC"' "$ENGAGEMENT_JSON" 2>/dev/null)
Apply all matching rules from scope-validator.md. Log every scope check outcome to ${OUTPUT_DIR}/activity.log using action: "scope_check".
When processing multiple targets (CIDR or file), validate each target individually before running any scan against it. Do not batch-validate.
Create output directories:
mkdir -p "${OUTPUT_DIR}/recon"
mkdir -p "${OUTPUT_DIR}/evidence/screenshots"
RECON_DIR="${OUTPUT_DIR}/recon"
TIMESTAMP=$(date -u +"%Y%m%dT%H%M%SZ")
Step 3: Check Tool Availability
Check each tool with which 2>/dev/null. Do not abort if a tool is missing — skip that step, note the gap in output, and continue. Log every check.
| Tool | Steps | Priority | |---|---|---| | naabu | 4 — Port Scanning | Required (one of naabu/service discovery) | | Network Discovery | 5 — Service Fingerprinting | Required (one of naabu/service discovery) | | httpx | 6 — HTTP Probing | Recommended | | whatweb | 7 — Web Technology Detection | Optional | | wafw00f | 8 — WAF Detection | Optional | | gowitness | 9 — Web Screenshots | Recommended — always run when web services found | | tlsx | 10 — SSL/TLS Scanning | Recommended — always run when web services found |
declare -A TOOL_AVAILABLE
for TOOL in naabu nmap httpx whatweb wafw00f gowitness tlsx; do
if which "$TOOL" > /dev/null 2>&1; then
TOOL_AVAILABLE[$TOOL]=true
jq -nc \
--arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
--arg security assessor "$ASSESSOR" \
--arg action "tool_check" \
--arg command "which $TOOL" \
--arg status "completed" \
--arg result "available" \
'{ts:$ts, security assessor:$security assessor, action:$action, command:$command, status:$status, result:$result}' \
>> "${OUTPUT_DIR}/activity.log"
else
TOOL_AVAILABLE[$TOOL]=false
jq -nc \
--arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
--arg security assessor "$ASSESSOR" \
--arg action "tool_check" \
--arg command "which $TOOL" \
--arg status "skipped" \
--arg result "not found" \
'{ts:$ts, security assessor:$security assessor, action:$action, command:$command, status:$status, result:$result}' \
>> "${OUTPUT_DIR}/activity.log"
fi
done
If naabu and the network service discovery tool are both missing, abort — the skill cannot perform meaningful port scanning without at least one of them.
Step 4: Port Scanning with naabu (Two-Phase)
Skip this step if naabu is not available and note the gap. If skipped, proceed directly to Step 5 (nmap will perform its own two-phase port discovery).
Always run both phases automatically:
- Phase 1 (Quick) — top 1000 ports, synchronous. Results feed immediately into Steps 5–11 so useful work starts right away.
- Phase 2 (Full) — all 65535 ports, asynchronous in tmux. Catches services on non-standard ports (backdoors, debug interfaces, custom apps).
Phase 1: Quick scan (synchronous)
NAABU_OUT="${RECON_DIR}/naabu-${ASSESSOR}-$(date +%s).txt"
CMD="naabu -host ${TARGET} -top-ports 1000 -silent -o ${NAABU_OUT}"
jq -nc \
--arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
--arg security assessor "$ASSESSOR" \
--arg action "scan" \
--arg target "$TARGET" \
--arg command "$CMD" \
--arg status "dispatched" \
'{ts:$ts, security assessor:$security assessor, action:$action, target:$target,
command:$command, status:$status}' \
>> "${OUTPUT_DIR}/activity.log"
$CMD
jq -nc \
--arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
--arg security assessor "$ASSESSOR" \
--arg action "scan" \
--arg target "$TARGET" \
--arg command "$CMD" \
--arg status "$([ $? -eq 0 ] && echo completed || echo failed)" \
--arg output_file "$NAABU_OUT" \
'{ts:$ts, security assessor:$security assessor, action:$action, target:$target,
command:$command, status:$status, output_file:$output_file}' \
>> "${OUTPUT_DIR}/activity.log"
Phase 2: Full scan (asynchronous — tmux)
Always launch Phase 2 immediately after Phase 1 completes. This runs in the background while Steps 5–11 proceed using Phase 1 results.
NAABU_FULL_OUT="${RECON_DIR}/naabu-full-${ASSESSOR}-$(date +%s).txt"
CMD="naabu -host ${TARGET} -p - -silent -o ${NAABU_FULL_OUT}"
SESSION_NAME="${ENGAGEMENT_ID}-naabu-full-$(date +%s)"
# Dispatch per remote-exec.md — SSH, SSM, or local depending on $HOST_NAME
# For local execution:
tmux new-session -d -s "$SESSION_NAME" "$CMD > /dev/null 2>&1"
jq -nc \
--arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
--arg security assessor "$ASSESSOR" \
--arg action "scan" \
--arg target "$TARGET" \
--arg command "$CMD" \
--arg status "dispatched" \
--arg session "$SESSION_NAME" \
--arg remote_host "$HOST_NAME" \
--arg phase "full" \
'{ts:$ts, security assessor:$security assessor, action:$action, target:$target,
command:$command, status:$status,
session:$session, remote_host:$remote_host, phase:$phase}' \
>> "${OUTPUT_DIR}/activity.log"
Tell the user:
> Full port scan (Phase 2) dispatched in tmux session $SESSION_NAME. Output: $NAABU_FULL_OUT > This will take 10–30+ minutes. Steps 5–11 are proceeding now using Phase 1 (top 1000) results. Check progress with: tmux attach -t $SESSION_NAME
Parse the Phase 1 naabu output to extract open ports:
# Output format: "host:port" per line
OPEN_PORTS=$(awk -F: '{print $2}' "$NAABU_OUT" 2>/dev/null | sort -un | tr '\n' ',' | sed 's/,$//')
Step 5: Deep Service Fingerprinting with Network Discovery Tool (Two-Phase when naabu was skipped)
Skip this step if the network service discovery tool is not available and note the gap.
If naabu ran (Step 4): Use $OPEN_PORTS from naabu Phase 1. The full-port coverage is already handled by naabu Phase 2 running async.
If naabu was skipped: the network service discovery tool performs its own two-phase scan:
- Phase 1 — top 1000 ports, synchronous with
-sV -sC -O— feeds immediately into Steps 6–11 - Phase 2 — remaining ports 1001–65535, asynchronous in tmux with
-sV -sC -O
Single host — Phase 1 (synchronous)
SERVICE_DISC_OUT="${RECON_DIR}/service-discovery-${ASSESSOR}-$(date +%s).xml"
if [ -n "${OPEN_PORTS:-}" ]; then
PORT_FLAG="-p ${OPEN_PORTS}"
NAABU_PROVIDED_PORTS=true
else
PORT_FLAG="--top-ports 1000"
NAABU_PROVIDED_PORTS=false
fi
CMD="nmap -sV -sC -O ${PORT_FLAG} -oX ${SERVICE_DISC_OUT} ${TARGET}"
jq -nc \
--arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
--arg security assessor "$ASSESSOR" \
--arg action "scan" \
--arg target "$TARGET" \
--arg command "$CMD" \
--arg status "dispatched" \
--arg phase "quick" \
'{ts:$ts, security assessor:$security assessor, action:$action, target:$target,
command:$command, status:$status, phase:$phase}' \
>> "${OUTPUT_DIR}/activity.log"
$CMD
jq -nc \
--arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
--arg security assessor "$ASSESSOR" \
--arg action "scan" \
--arg target "$TARGET" \
--arg command "$CMD" \
--arg status "$([ $? -eq 0 ] && echo completed || echo failed)" \
--arg output_file "$SERVICE_DISC_OUT" \
--arg phase "quick" \
'{ts:$ts, security assessor:$security assessor, action:$action, target:$target,
command:$command, status:$status, output_file:$output_file, phase:$phase}' \
>> "${OUTPUT_DIR}/activity.log"
Single host — Phase 2 (asynchronous, only when naabu was skipped)
If naabu already launched a full-port scan (Step 4 Phase 2), skip this — naabu covers the remaining ports. Only launch service discovery Phase 2 when the network discovery tool is acting as the sole port scanner.
if [ "${NAABU_PROVIDED_PORTS:-false}" = "false" ]; then
SERVICE_DISC_FULL_OUT="${RECON_DIR}/service-discovery-full-${ASSESSOR}-$(date +%s).xml"
SERVICE_DISC_FULL_SESSION="${ENGAGEMENT_ID}-service-discovery-full-$(date +%s)"
CMD_FULL="nmap -sV -sC -O -p 1001-65535 -oX ${SERVICE_DISC_FULL_OUT} ${TARGET}"
tmux new-session -d -s "$SERVICE_DISC_FULL_SESSION" "$CMD_FULL"
jq -nc \
--arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
--arg security assessor "$ASSESSOR" \
--arg action "scan" \
--arg target "$TARGET" \
--arg command "$CMD_FULL" \
--arg status "dispatched" \
--arg session "$SERVICE_DISC_FULL_SESSION" \
--arg remote_host "$HOST_NAME" \
--arg phase "full" \
'{ts:$ts, security assessor:$security assessor, action:$action, target:$target,
command:$command, status:$status,
session:$session, remote_host:$remote_host, phase:$phase}' \
>> "${OUTPUT_DIR}/activity.log"
echo "Service discovery full-port scan (Phase 2: ports 1001-65535) dispatched in tmux session $SERVICE_DISC_FULL_SESSION"
echo "Output: $SERVICE_DISC_FULL_OUT — check progress: tmux attach -t $SERVICE_DISC_FULL_SESSION"
fi
IP range or CIDR (asynchronous — tmux)
For ranges with more than one host, dispatch both phases asynchronously per remote-exec.md:
SESSION_NAME="${ENGAGEMENT_ID}-service-discovery-$(date +%s)"
SERVICE_DISC_OUT="${RECON_DIR}/service-discovery-${ASSESSOR}-$(date +%s).xml"
CMD="nmap -sV -sC -O --top-ports 1000 -oX ${SERVICE_DISC_OUT} ${TARGET}"
# Phase 1: top 1000 ports
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 target "$TARGET" \
--arg command "$CMD" \
--arg status "dispatched" \
--arg session "$SESSION_NAME" \
--arg remote_host "$HOST_NAME" \
--arg phase "quick" \
'{ts:$ts, security assessor:$security assessor, action:$action, target:$target,
command:$command, status:$status,
session:$session, remote_host:$remote_host, phase:$phase}' \
>> "${OUTPUT_DIR}/activity.log"
# Phase 2: remaining ports 1001-65535
if [ "${NAABU_PROVIDED_PORTS:-false}" = "false" ]; then
SESSION_NAME_FULL="${ENGAGEMENT_ID}-service-discovery-full-$(date +%s)"
SERVICE_DISC_FULL_OUT="${RECON_DIR}/service-discovery-full-${ASSESSOR}-$(date +%s).xml"
CMD_FULL="nmap -sV -sC -O -p 1001-65535 -oX ${SERVICE_DISC_FULL_OUT} ${TARGET}"
tmux new-session -d -s "$SESSION_NAME_FULL" "$CMD_FULL"
jq -nc \
--arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
--arg security assessor "$ASSESSOR" \
--arg action "scan" \
--arg target "$TARGET" \
--arg command "$CMD_FULL" \
--arg status "dispatched" \
--arg session "$SESSION_NAME_FULL" \
--arg remote_host "$HOST_NAME" \
--arg phase "full" \
'{ts:$ts, security assessor:$security assessor, action:$action, target:$target,
command:$command, status:$status,
session:$session, remote_host:$remote_host, phase:$phase}' \
>> "${OUTPUT_DIR}/activity.log"
fi
Parse network service discovery XML output to extract service and version data for host profile construction in Step 12.
Step 6: HTTP Probing with httpx
Skip this step if httpx is not available. HTTP probing identifies live web services, collects status codes, titles, and technology fingerprints.
Build a hosts file from naabu/service discovery results — include only hosts with open web ports (80, 443, 8080, 8443, 8000, 8888, 9000, 9443, and any other high por
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: thapr0digy
- Source: thapr0digy/skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.