Engagement Setup

Scope, rules of engagement, a tracked workspace, and a working toolbox — everything before the first packet leaves your box.

The work you do before scanning is what keeps the engagement clean, repeatable, and defensible. Skip it and you end up scanning out-of-scope hosts, losing evidence, or unable to reconstruct what you ran on day 9.

1. Pin down scope and rules of engagement

Get these in writing before anything else. They decide which commands you’re allowed to run.

  • In-scope assets — root domains, IP ranges/CIDRs, ASNs, specific URLs.
  • Out-of-scope assets — explicit exclusions (shared SaaS, third-party CDNs, partner domains). These become your blacklist (see below).
  • Allowed activity — passive only? Active scanning? Exploitation? Brute force? Phishing?
  • Rate / timing limits — some clients cap requests-per-second or forbid scanning during business hours.
  • Blackout windows & emergency contact — who to call when something falls over, and when not to test.
  • Credentials & test accounts — for authenticated testing.

A wildcard like *.example.com means “enumerate and prove the subdomains”; a bare example.com usually means just that host. Confirm which one the client means — it changes the size of the engagement.

2. Stand up a tracked workspace

I treat the engagement as a git repo from the first minute. Every scan output, every scope change, and every note ends up version-controlled — it’s both the audit trail and the backup.

mkdir ~/engagements/acme && cd ~/engagements/acme
git init
mkdir -p recon hosts report tmp
printf '/tmp\n' > .gitignore
git add .gitignore && git commit -m "init workspace"

A directory convention that scales (this is basically the layout Arsenic enforces):

acme/
├── scope-domains.txt        # in-scope root domains, one per line
├── scope-ips.txt            # in-scope IPs / CIDRs
├── recon/                   # org-wide recon output (domains, ips, discovery)
├── hosts/<host>/recon/      # per-host scan output
├── report/
│   ├── findings/            # one folder per finding
│   └── static/              # screenshots & evidence
└── tmp/                     # scratch (git-ignored)

Commit early and often. A habit I borrowed straight from the Arsenic scripts: after each meaningful scan, git add the new output and commit with a message describing what ran. If you’re collaborating, push between steps so teammates don’t re-scan the same hosts.

3. Define the scope files

The whole pipeline is driven by two seed files. Everything you discover later gets validated back against these plus a blacklist.

# Seed roots — the things you were explicitly told are in scope
printf 'example.com\nexample.net\n' >> scope-domains.txt
printf '203.0.113.0/24\n198.51.100.10\n' >> scope-ips.txt

Keep a blacklist of root domains that show up in results but aren’t yours to test — shared infrastructure that certificate transparency and reverse DNS will constantly surface. Arsenic ships a sensible default; the usual offenders:

1e100.net            akamaitechnologies.com   amazonaws.com
azurewebsites.net    cloudfront.net           cloudapp.net
googleusercontent.com  readthedocs.io         sites.hubspot.net

Every time you generate a new candidate list of domains/IPs, run it through this blacklist before adding it to scope. This one habit prevents the most common engagement mistake: scanning someone else’s CDN.

Ingesting scope from a CSV / bug-bounty program

Real scope rarely arrives as a clean list. For a HackerOne-style CSV, I normalize it with mlr (Miller) and jq:

curl -s https://hackerone.com/teams/acme/assets/download_csv.csv \
  | mlr --icsv --ojson cat | jq | tee acme-scope.json

# Pull eligible, non-wildcard identifiers into the domain scope
jq -r '.[]
  | select(.eligible_for_submission == "true")
  | select(.max_severity != "none")
  | .identifier' acme-scope.json \
  | grep -v '\*' \
  | sort -u >> scope-domains.txt

Handle wildcard entries (*.acme.com) separately — strip the *. and feed the parent to subdomain enumeration in the Discovery phase.

4. Build your toolbox

Install the toolchain once and keep it on $PATH. Full install commands are in the Toolbox Reference; the essentials:

# ProjectDiscovery suite (Go)
go install github.com/projectdiscovery/subfinder/v2/cmd/subfinder@latest
go install github.com/projectdiscovery/dnsx/cmd/dnsx@latest
go install github.com/projectdiscovery/naabu/v2/cmd/naabu@latest
go install github.com/projectdiscovery/httpx/cmd/httpx@latest
go install github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest

# Content discovery & fuzzing
go install github.com/ffuf/ffuf/v2@latest
# feroxbuster, gobuster — package manager or release binaries

# Classics
sudo apt install -y nmap amass exploitdb jq miller   # searchsploit ships with exploitdb

# Wordlists
git clone https://github.com/danielmiessler/SecLists /opt/SecLists

Let nmap run unprivileged

Most useful nmap scans need raw sockets. Rather than sudo on every run, grant the binary the capabilities once:

sudo setcap cap_net_raw,cap_net_admin,cap_net_bind_service+eip "$(command -v nmap)"

With setup done, move on to Discovery to turn your seed scope into a full asset inventory.

Last modified July 4, 2026: Post/mobi (#71) (ff64902)