autopentestx
Automated pentest pipelines — designing, running, and auditing bash-driven recon-to-report automation
SKILL.mdskills/impl/autopentestx/SKILL.md
GitHubAutomated Pentest Pipelines
AI LOAD INSTRUCTION: This skill is about the automation pattern, not about one repository. A tool named
AutoPentestXexists as a bash script that chains recon, scanning, exploitation, and reporting — and the lesson worth internalising is that such scripts are orchestration, not intelligence. They do not know what makes your target unusual, they cannot distinguish a real finding from a scanner artefact, and their exploitation stage frequently takes an action that changes the target's state.The mistake to avoid is running a full auto-exploit pipeline against a scope you have not verified. An automated exploitation stage that "attempts exploitation" will attempt it against whatever it finds — including out-of-scope assets, production systems, and fragility-prone services. Automation amplifies both throughput and damage.
The correct posture: automate the deterministic stages (enumeration, fingerprinting, differential scanning) and keep exploitation manual and deliberate. A pipeline that produces a great inventory and stops before exploiting is far more useful than one that fires payloads at everything it found.
0. RELATED ROUTING
- recon-methodology — the stage automation helps most
- vuln-research-methodology — the manual counterpart to automated scanning
- recon-and-methodology — the engagement and scoping discipline automation must respect
- security-reporting-and-documentation — where the pipeline's output must land
- bug-bounty-agents — the agent-prompt variant of the same idea
- orchestration — coordinating long-running multi-stage work
1. THE PIPELINE STAGES
A pentest pipeline has five stages with very different automation suitability.
| Stage | Automate? | Why |
|---|---|---|
| scope validation | mandatory | every stage must respect it; automate the enforcement |
| reconnaissance / enumeration | yes, fully | deterministic, high volume, low risk |
| fingerprinting / version detection | yes | pattern matching against banners |
| vulnerability scanning | yes, with review | high false-positive rate; needs triage |
| exploitation | no — manual | state-changing, context-dependent, risky |
| reporting | partially | draft generation is automatable; findings are not |
The dividing line is state change. Anything that only reads can be automated; anything that writes, executes, or alters state must be deliberate and reviewed.
A pipeline that respects this line is safe to run against production. One that does not is a liability, and the exploitation stage is where it goes wrong.
2. SCOPE ENFORCEMENT — THE GATE
Every automated stage must be filtered through scope. Build the gate first, before any scanning code.
#!/usr/bin/env bash
# scope.sh — the single source of truth for what is in scope
#
# scope.txt format:
# in-scope:
# 10.10.10.0/24
# *.target.com
# out-of-scope:
# 10.10.10.5
# payments.target.com
# forbidden-actions:
# dos, brute-force, exploitation
in_scope() {
local target="$1"
# deny-list wins over allow-list, always
while read -r ex; do
[ -z "$ex" ] && continue
case "$target" in $ex) return 1 ;; esac
done < <(grep -A999 'out-of-scope:' scope.txt | tail -n +2 | grep -v '^[a-z-]*:$')
while read -r inc; do
[ -z "$inc" ] && continue
case "$target" in $inc) return 0 ;; esac
done < <(grep -A999 'in-scope:' scope.txt | tail -n +2 | grep -v '^[a-z-]*:$')
return 1
}
Three rules for the gate:
- Deny always beats allow. An exclusion for a specific host inside an included range must win. Getting this backwards is how out-of-scope systems get scanned.
- The gate runs before every tool invocation, not once at the start. A subdomain discovered in minute 40 must be checked before it is scanned.
- Fail closed. If the gate cannot determine scope, it returns "not in scope". Never default to allowing.
Verify the gate works before running anything else:
for t in 10.10.10.1 10.10.10.5 payments.target.com api.target.com evil.com; do
in_scope "$t" && echo "IN $t" || echo "OUT $t"
done
That test is not optional. A broken gate is the single most damaging bug in a pentest pipeline.
3. THE RECON STAGE
The highest-value automatable stage, because it is read-only and its output compounds.
#!/usr/bin/env bash
set -euo pipefail
OUT="out/$(date +%Y%m%d-%H%M)"
mkdir -p "$OUT"
# 1. subdomain enumeration
subfinder -d "$ROOT" -silent 2>/dev/null | sort -u > "$OUT/subs.txt"
# 2. scope filter — every subsequent stage reads the filtered list
while read -r s; do in_scope "$s" && echo "$s"; done < "$OUT/subs.txt" > "$OUT/subs-scoped.txt"
# 3. resolve and identify live hosts
while read -r s; do
ip=$(dig +short A "$s" | head -1)
[ -n "$ip" ] && printf "%s %s\n" "$s" "$ip"
done < "$OUT/subs-scoped.txt" > "$OUT/resolved.txt"
# 4. HTTP probe with tech detection
httpx -l "$OUT/subs-scoped.txt" -silent -title -tech-detect -status-code \
-o "$OUT/httpx.txt" 2>/dev/null || true
# 5. port scan — keep the rate conservative
naabu -l "$OUT/subs-scoped.txt" -silent -top-ports 1000 -o "$OUT/ports.txt" 2>/dev/null || true
echo "recon complete: $(wc -l < "$OUT/subs-scoped.txt") in-scope hosts"
Design rules that make a recon stage reliable:
| Rule | Reason |
|---|---|
| timestamped output directory | runs are comparable and reproducible |
| every stage writes a file | you can resume after a failure |
| scope filter between stages | nothing reaches a scanner unfiltered |
| conservative scan rates | a port scan can saturate a link and cause an outage |
-silent and ` |
|
| never scan a third-party service by default | CDN edges, mail providers, and hosting panels are frequently out of scope |
A recon stage that produces a clean, scoped, annotated inventory is worth more than any automated exploitation.
4. TRIAGE — THE STAGE MOST PIPELINES SKIP
Scanner output is not findings. A pipeline that pipes scanner results into a report produces a document nobody trusts.
Triage is the filter between scanning and reporting:
| Scanner output | Triage decision |
|---|---|
| a version banner matching a CVE | verify the version is actually exploitable — banners lie and backports exist |
| a "vulnerable" template match | reproduce manually; templates are heuristic |
| an exposed path returning 200 | verify it is the real resource, not a catch-all 200 handler |
| a missing security header | check whether it matters for that endpoint |
| an information disclosure | assess whether the information is sensitive |
| everything else | priority 5 unless proven otherwise |
Automate the triage collection, not the triage decision. Group by finding type, attach the raw evidence, and let a human assign severity. A pipeline can queue 200 candidates for review; it cannot decide which of them matter.
False-positive ratio is the metric that matters. If a pipeline reports 100 findings and 5 are real, it has created 95 units of human work and lost the team's trust. Precision beats recall.
5. WHY EXPLOITATION STAYS MANUAL
An automated exploitation stage cannot know:
| Unknown | Consequence |
|---|---|
| whether the service is fragile | a payload crashes it |
| whether the finding is a honeypot | you alert the blue team |
| whether exploitation is in the engagement's rules | you breach the contract |
| whether the effect is reversible | you corrupt data |
| what the target actually is | you exploit the wrong system |
| whether the payload is destructive | you take down production |
| whether you have authorisation for this asset | you commit a crime |
Every row is a reason a human must decide. Automation can propose an exploit and prepare the command; it must not fire it.
The safe pattern — propose, review, execute:
# 1. Pipeline writes a proposed action to a review queue (never executes)
echo "PROPOSE: sqlmap -u '$url' --batch --level 1 --risk 1" >> "$OUT/review-queue.txt"
# 2. A human reviews, edits, and runs approved commands manually
# 3. The executed command and its output are logged for the report
Never wire a tool's --exploit flag into an unattended loop. The gap between "here is a
candidate exploit" and "here is the command, reviewed and authorised" is the entire safety
margin.
6. WHAT CONSTITUTES A USEFUL PIPELINE OUTPUT
| Output | Value |
|---|---|
| a scoped, deduplicated asset inventory | high — the foundation of everything else |
| technology fingerprints with versions | high — drives manual research |
| a queue of review candidates with raw evidence | high — saves enumeration time |
| a proposed-exploit queue listing commands for review | medium — saves command construction |
| a machine-readable findings store | high — feeds the report |
| a directly generated report | low — unreviewed scanner output, usually wrong |
| an audit log of every command run | high — reproducibility and defensibility |
The audit log is essential and frequently omitted. Every command executed against the target, with a timestamp and the operator, is what lets you answer "what did we do to this system?" afterwards.
7. EVIDENCE STANDARD
| Item | Why |
|---|---|
| the scope definition used for the run | proves the run was constrained |
| the scope-gate test output | proves the gate works, not just that it exists |
| the raw output of every stage, unmodified | the pipeline's actual product |
| the exact command lines executed, with timestamps | reproducibility and audit |
| the scan rates and any rate-limiting observed | proves the run did not endanger availability |
| the triage decisions and who made them | separates scanner output from findings |
| confirmation that no exploitation ran unattended | the safety control |
| a control: a re-run with the same inputs producing the same inventory | proves determinism |
The audit log and the scope-gate test are the two artefacts that distinguish a professional pipeline from a script.
Failure modes to watch for:
| Symptom | Cause |
|---|---|
| out-of-scope hosts scanned | a broken or bypassed scope gate |
| the same host reported repeatedly | no deduplication between stages |
| a target's availability degraded | scan rates too aggressive |
| findings that cannot be reproduced | scanner artefacts reported without triage |
| the pipeline stopped silently mid-run | missing ` |
| the report contains hundreds of priority-5s | no triage stage |
8. REMEDIATION REFERENCE
For hardening a pipeline you operate:
- Build and test the scope gate before any scanning code — deny-beats-allow, fail-closed, and re-checked before every stage.
- Keep exploitation manual and reviewed — have the pipeline write a proposal queue and execute nothing. This is the single most important control.
- Set conservative, configurable scan rates — default slow; a rate limit that is too high is a denial-of-service against your own client.
- Make every stage resumable and idempotent — timestamped output, one artefact per stage, so a failure at stage 4 does not require rerunning stages 1-3.
- Never let one tool's failure abort the run — check exit codes and continue, recording the failure.
- Insert a mandatory triage stage between scanning and reporting — scanner output is a candidate list, not a findings list.
- Log every command with a timestamp and operator — this is your audit trail and your defence if the engagement is questioned.
- Exclude third-party and shared infrastructure by default — CDN edges, managed hosting, and mail providers are usually out of scope even when they serve in-scope hostnames.
- Test the pipeline on a lab target before every engagement — a pipeline change that breaks the scope gate is discovered cheaply in a lab and expensively in the field.
9. CONFIRMING THE FINDING
A pipeline's output is a candidate list, and the finding is not produced by the pipeline at all. This table is what converts a pipeline's row into a finding someone will accept.
| Step | Question | What it proves |
|---|---|---|
| 1 | Is the scope gate recorded, with the target's authorisation, window, and exclusions? | a pipeline finding outside scope is not a finding |
| 2 | Did the row come from a stage's own output artefact, with the exact command and tool version? | the pipeline's audit trail is its only evidence |
| 3 | Was it triaged by a human action, not auto-promoted from scanner severity? | scanner severity is a vendor's guess |
| 4 | Is the observation reproduced outside the pipeline, by hand? | a pipeline that fires once and cannot be re-run proved nothing |
| 5 | Is the operator and timestamp on the log line? | the audit trail is what defends the result |
| 6 | Was a failed or aborted stage reported, not silently skipped? | a pipeline that swallowed an error claims coverage it does not have |
| 7 | Is the impact the step actually demonstrated, not the scanner's template category? | the template names a class; it does not demonstrate value |
A scoped row, a stage artefact, a human triage, and a hand reproduction. A scanner row is a lead; the pipeline's value is that it is a repeatable lead, and repeatability is what makes it triage-able.
10. EXECUTION PRIMITIVES
This domain executes as a pipeline with a gate and an audit trail. Every step below is a procedure, and the control pair is the in-scope target against the identical scan pointed at an out-of-scope target.
9.1 The scope gate, which runs first and aborts
echo "=== THE SCOPE GATE: it must run BEFORE any recon, and it must be able to ABORT ==="
cat > scope.yaml <<'YAML'
engagement:
name: # the engagement identifier used in every log line
authorised_by: # WHO signed the authorisation, and the document reference
window_start: # an ISO timestamp
window_end: # an ISO timestamp
in_scope:
domains: [] # apex domains - SUBDOMAINS ARE NOT AUTOMATICALLY IN SCOPE, state the rule
cidrs: []
exclusions: [] # CDN edges, managed hosting, mail providers, shared infrastructure
touching_this_out_of_scope_aborts_the_run: true
YAML
echo
cat <<'GATE'
THE GATE'S FOUR JOBS, IN ORDER:
1. RESOLVE each target to an address, and CHECK the address is within the authorised CIDRs.
A hostname in scope resolving to an out-of-scope address (a CDN, a shared host) is OUT.
2. CHECK the clock against the window. A scan out of window is an unauthorised scan, regardless
of intent.
3. CHECK the exclusion list, and REPORT a conflict rather than silently skipping (silent skips
become phantom coverage in the report).
4. ABORT, not warn. A gate that logs and continues is not a gate.
AND THE CONTROL PAIR, WHICH IS THE WHOLE POINT:
A. the pipeline runs against an IN-SCOPE target -> proceeds, and the run is recorded
B. THE IDENTICAL COMMAND points at an OUT-OF-SCOPE target -> ABORTS, with the reason in the log
IF B DOES NOT ABORT, THE GATE IS DECORATIVE, AND EVERY FINDING FROM THE RUN IS AT RISK.
GATE
The gate must abort, not warn — and the control is the identical command against an out-of-scope target being refused. If it does not, the gate is decorative.
9.2 The stages, and the artefact each one owes
echo "=== EVERY STAGE OWES AN ARTEFACT, A LOG LINE, AND AN EXIT CODE ==="
python3 - <<'PY'
S = [("scope gate", "the target list, post-gate", "the gate's decision per target, and any conflicts"),
("recon", "the surface inventory (hosts, ports, services)", "the command, version, and timestamp per observation"),
("triage", "the graded candidate list", "WHY each row was kept or dropped - this is the stage most pipelines skip"),
("reporting", "the report, built from triage", "a link from every finding back to its stage artefact")]
print("%-14s %-48s %s" % ("stage","its artefact","its log obligation"))
for a,b,c in S: print("%-14s %-48s %s" % (a,b,c))
print()
print(" THE RULE: A STAGE THAT PRODUCED NO ARTEFACT DID NOT RUN, and it must be reported as such.")
print(" A stage that FAILED must be reported as FAILED, not as an empty result. THE DIFFERENCE")
print(" BETWEEN 'NO FINDINGS' AND 'THE SCANNER CRASHED' IS THE ENTIRE VALUE OF THE AUDIT TRAIL.")
print()
print(" AND THE COMMAND LOG: one line per invocation -")
print(" <ISO timestamp> <operator> <stage> <exact command> <exit code> <artefact path>")
print(" THIS IS THE PIPELINE'S OWN EVIDENCE. Without it, a finding cannot be reproduced and a")
print(" missed target cannot be distinguished from a target that was never scanned.")
PY
A stage that produced no artefact did not run — and "no findings" must never be conflated with "the scanner crashed".
9.3 Triage, the stage most pipelines skip, and the end-to-end harness
echo "=== TRIAGE: the human gate between a scanner row and a finding ==="
cat <<'TRIAGE'
A SCANNER ROW IS A CANDIDATE. TRIAGE ASKS FIVE QUESTIONS, IN ORDER:
1. IS IT REPRODUCIBLE BY HAND? If the pipeline is the only thing that can see it, it is not
reportable until you have reproduced it manually.
2. IS IT A FALSE POSITIVE FROM THE VERSION OR THE CONFIG? A banner-version match is not a
vulnerable build; a template that matched a header is not an exploit.
3. IS IT IN SCOPE AND REACHABLE? A finding behind an authenticating proxy is a different finding.
4. WHAT IS THE DEMONSTRATED IMPACT? The highest step actually observed - not the template's category.
5. WAS IT ALREADY KNOWN? A duplicate wastes the reviewer's time and dilutes the report.
THE GRADES: CONFIRMED (reproduced by hand, impact demonstrated) / CANDIDATE (reproducible, impact
unclear) / DROPPED (reason recorded). DROPPED ROWS STAY IN THE RECORD WITH THEIR REASON - the
reviewer needs to see that they were considered.
TRIAGE
echo
echo "=== the reproducibility discipline, which is what makes a pipeline finding credible ==="
cat <<'REPRO'
A PIPELINE FINDING IS REPRODUCIBLE WHEN A SECOND OPERATOR CAN RE-RUN IT FROM THE LOG ALONE:
the exact COMMAND, its VERSION, and its ARGUMENTS
the INPUT (the target list, the wordlist, the template set) with its HASH
the ENVIRONMENT if it matters (source IP, vantage, time)
the OUTPUT ARTEFACT, stored, with its path
TEST IT: hand the log line to a colleague with no context and have them reproduce it. If they cannot,
the log is incomplete. THIS TEST IS THE PIPELINE'S OWN CONTROL.
AND: A PIPELINE RUN AGAINST A MOVING TARGET (a live site, a cloud autoscaler) WILL DIFFER BETWEEN
RUNS. Record the TARGET STATE (a response hash, a version, a timestamp) alongside the finding so
the difference is attributable to the target rather than to your tooling.
REPRO
echo
echo "=== end-to-end harness ==="
python3 - <<'PY'
print("=== AUTOPENTEST PIPELINE ACCEPTANCE CHECKLIST ===")
CHECKS = [
("the SCOPE GATE ran first and its per-target decision is logged",
"a scan outside the authorised scope is not a finding, it is an incident"),
("the gate ABORTS on an out-of-scope target, and the abort was tested",
"a gate that warns and continues is decorative"),
("the authorised window was checked against the clock",
"an out-of-window scan is unauthorised regardless of intent"),
("exclusions were checked and CONFLICTS REPORTED, not silently skipped",
"silent skips become phantom coverage"),
("every stage produced an ARTEFACT, a LOG LINE, and an EXIT CODE",
"a stage with no artefact did not run"),
("a FAILED stage is reported as failed, not as an empty result",
"'no findings' and 'the scanner crashed' are different claims"),
("every invocation is logged with timestamp, operator, command, exit code, and artefact path",
"the audit trail is the pipeline's only evidence"),
("a TRIAGE stage exists between scanning and reporting, with the five questions applied",
"scanner output is a candidate list, not a findings list"),
("dropped rows are retained WITH their reason",
"the reviewer needs to see the rows were considered"),
("each reported finding was REPRODUCED BY HAND outside the pipeline",
"a pipeline-only finding is not reportable until it is"),
("a second operator reproduced a finding from the LOG ALONE",
"the log is the pipeline's own control"),
("the target STATE (response hash, version, timestamp) is recorded with each finding",
"a moving target makes a difference attributable to the target, not the tooling"),
("third-party and shared infrastructure are excluded by default",
"a CDN edge serving an in-scope hostname is usually still out of scope"),
]
for n, how in CHECKS: print(" [ ] %-74s -> %s" % (n, how))
print()
print("=== THE REPORT SHAPE ===")
print(" gate : the authorisation, window, target list, exclusions, and the gate's decisions")
print(" stages : each stage's command, version, exit code, and artefact")
print(" triage : the graded list, with dropped rows and their reasons")
print(" findings : each with its hand reproduction and its target-state record")
print(" gaps : any failed or skipped stage, named explicitly")
PY
11. RELATED SIBLINGS - LOAD TOGETHER
- recon-methodology - the recon stage's own discipline
- vuln-research-methodology - the triage questions in differential form
- security-reporting-and-documentation - how the pipeline's artefact becomes a report
- nuclei-template-library-operations - the scanner layer a recon stage drives
- insecure-source-code-management - the repository exposure a recon stage may surface