autopentestx

Automated pentest pipelines — designing, running, and auditing bash-driven recon-to-report automation

SKILL.md

GitHub

Automated Pentest Pipelines

AI LOAD INSTRUCTION: This skill is about the automation pattern, not about one repository. A tool named AutoPentestX exists 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


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:

  1. 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.
  2. 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.
  3. 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:

  1. Build and test the scope gate before any scanning code — deny-beats-allow, fail-closed, and re-checked before every stage.
  2. Keep exploitation manual and reviewed — have the pipeline write a proposal queue and execute nothing. This is the single most important control.
  3. Set conservative, configurable scan rates — default slow; a rate limit that is too high is a denial-of-service against your own client.
  4. 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.
  5. Never let one tool's failure abort the run — check exit codes and continue, recording the failure.
  6. Insert a mandatory triage stage between scanning and reporting — scanner output is a candidate list, not a findings list.
  7. Log every command with a timestamp and operator — this is your audit trail and your defence if the engagement is questioned.
  8. 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.
  9. 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