external-enumeration
Skill153 starsChanged 44 days agoMITView on GitHub
Passively map a company's domains, subdomains, DNS ownership, tech stack, and CDNs. Use to recon an external attack surface or enumerate subdomains.
- Installs packages
In this repository41 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- .github/copilot-instructions.mdCopilot instructions
- broken-access-controlSkill
- cdn-peekSkill
- http-request-smugglingSkill
- jwt-attacksSkill
- ssrf-oobSkill
- webapp-probeSkill
- blockchain-forensicsSkill
- foundry-pocSkill
- safe-huntSkill
- smart-contract-auditSkill
- cloud-bucket-bruteSkill
- infrastructure-auditSkill
- dylib-hijack-scanSkill
- endpoint-threat-huntSkill
- parse-securitySkill
- agentic-seoSkill
- agent-onboardingSkill
- context-window-to-skillSkill
- git-commitSkill
- keen-eyesSkill
- no-aispeakSkill
- secure-1pass-accessSkill
- self-improveSkill
- shadow-partnerSkill
- training-guideSkill
- variant-tableSkill
- auditor-quizSkill
- audit-scopeSkill
- evidence-captureSkill
- gdocs-audit-reportSkill
- hackerone-reportSkill
- nuclei-suggestSkill
- pre-bountySkill
- sandboxed-audit-runnerSkill
- tiny-auditorSkill
- vm-labSkill
- llm-fuzz-toolsSkill
- mcp-server-pentestSkill
- prompt-injection-auditSkill
The file
We split this skill into the rules it gives an agent
10 rules. About 0 are common, 10 are distinctive, and 0 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈10
Distinctive · estimate
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 15
Ask the user for:
- Distinctive: line 25
Before enumerating subdomains, confirm what domains are actually owned by the target.
- Distinctive: line 128
Collect ALL headers in a single pass: Do not come back for a second pass.
- Distinctive: line 194
If redirect leads to Microsoft login:
- Distinctive: line 222
When Cloudflare blocks curl, use stealth Playwright.
- Distinctive: line 268
Don't run on Cloudflare IPs, don't run on WAFs/CDNs protected targets.
- Distinctive: line 269
Only look for applicative ports, don't overdo the web scan to more than a few strategic port decisions (passive-first approach).
- Distinctive: line 291
Check registrant/NS of likely related domains (founder names, product names)
- Distinctive: line 299
Always flag these automatically in the report:
- Distinctive: line 316
Always produce the markdown report with this structure:
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
External Enumeration Skill
You are performing passive external reconnaissance on a target company's domain infrastructure. Goal: produce a comprehensive, structured map of all domains, subdomains, technology stack, and notable security observations - using only passive/OSINT techniques (no active exploitation).
Phase 0 - Scope Clarification
Ask the user for:
- Primary domain(s) to enumerate (e.g.
example.com) - Known subsidiaries or related companies (acquisitions, brand names, sister domains)
- Output format - markdown report to a file path?
- Depth - quick pass (passive DNS only) or deep pass (stealth browser + port scan)?
Phase 1 - Domain Ownership & Attribution
Before enumerating subdomains, confirm what domains are actually owned by the target.
1.1 WHOIS Check
whois <domain> | grep -iE 'registrar|creation|name server|registrant'Note: Most domains use privacy protection (e.g. GoDaddy DomainsbyProxy) - registrant names will be hidden. Do NOT rely on registrant names for attribution.
1.2 Nameserver Correlation (Primary Attribution Method)
for d in domain1.com domain2.io domain3.net; do
echo -n "$d: "; dig NS $d +short | sort | tr '\n' ' '; echo
doneIdentical NS pairs = same DNS account = same owner. This is the strongest passive attribution proof even when WHOIS is privacy-protected.
1.3 MX + TXT Record Cross-Reference
dig MX <domain> +short
dig TXT <domain> +short- Shared
*.mail.protection.outlook.comMX = same Microsoft 365 tenant - TXT records reveal: Azure site verifications, Google Workspace, Atlassian, SendGrid
- Azure TXT format:
MS=ms...orazurewebsites.netsubdomain references → same Azure tenant
1.4 Similar-Name Domain Trap
Note: Always verify similar-sounding domains (e.g.
target.net,target.co) are actually owned by the target - different registrar or NS pair = likely unrelated squatter. Never assume.
Phase 2 - Multi-Source Subdomain Enumeration
Run all sources in parallel on first pass. crt.sh alone is never sufficient.
2.1 Certificate Transparency (crt.sh)
curl -s "https://crt.sh/?q=%.example.com&output=json" \
| python3 -c "import sys,json; [print(e['name_value']) for e in json.load(sys.stdin)]" \
| tr ',' '\n' | sort -u | grep -v '^\*'2.2 HackerTarget
curl -s "https://api.hackertarget.com/hostsearch/?q=example.com" | cut -d',' -f1 | sort -u2.3 Wayback Machine
curl -s "https://web.archive.org/cdx/search/cdx?url=*.example.com&output=text&fl=original&collapse=urlkey" \
| grep -oP '[\w.-]+\.example\.com' | sort -u2.4 urlscan.io
curl -s "https://urlscan.io/api/v1/search/?q=domain:example.com&size=100" \
| python3 -c "import sys,json; d=json.load(sys.stdin); [print(r['page']['domain']) for r in d.get('results',[])]" \
| sort -u2.5 RapidDNS
curl -s "https://rapiddns.io/subdomain/example.com?full=1" \
| grep -oP '[\w.-]+\.example\.com' | sort -u2.6 AlienVault OTX
Note: Turn off ssl verification if using Python urllib. Rate limiting is aggressive; skip if blocked.
curl -s "https://otx.alienvault.com/api/v1/indicators/domain/example.com/passive_dns" \
| python3 -c "import sys,json; [print(r.get('hostname','')) for r in json.load(sys.stdin).get('passive_dns',[])]" \
| sort -u2.7 subfinder (if installed)
subfinder -d example.com -silent 2>/dev/null | sort -uInstall: brew install subfinder
2.8 Deduplicate Everything
cat all_sources.txt | sort -u > subdomains_unique.txt
wc -l subdomains_unique.txtPhase 3 - DNS Resolution & Live Check
# Resolve all subdomains, identify live ones
while read sub; do
ip=$(dig +short A "$sub" 2>/dev/null | grep -m1 -oP '\d+\.\d+\.\d+\.\d+')
if [ -n "$ip" ]; then
echo "$sub -> $ip"
fi
done < subdomains_unique.txtPhase 4 - One-Pass Comprehensive Header Harvest
Collect ALL headers in a single pass. Do not come back for a second pass.
collect_headers() {
local sub=$1
local result=$(curl -sk -o /dev/null \
--max-time 10 \
-D - \
-A "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36" \
"https://$sub" 2>/dev/null | head -80)
local status=$(echo "$result" | head -1 | grep -oP '\d{3}')
local ip=$(dig +short A "$sub" 2>/dev/null | grep -m1 -oP '\d+\.\d+\.\d+\.\d+')
python3 -c "
import sys, json
headers_raw = '''$result'''
h = {}
for line in headers_raw.split('\n')[1:]:
if ': ' in line:
k, v = line.split(': ', 1)
h[k.lower().strip()] = v.strip()
print(json.dumps({'subdomain': '$sub', 'status': '$status', 'ip': '$ip', **h}))
"
}Phase 5 - Technology Identification
5.1 From Server Headers
server value | Technology |
cloudflare | Cloudflare WAF/proxy |
gunicorn | Python WSGI - direct exposure, no WAF |
nginx | Nginx (may be direct or behind CDN) |
UploadServer | Google Cloud Storage |
AmazonS3 | AWS S3 bucket |
5.2 From CNAME Chains
dig CNAME <subdomain> +short| CNAME target | Platform |
*.hubspot.net | HubSpot (email/link tracking) |
*.lmspowered.com | LearnUpon LMS |
*.partner-experience.com | Partner portal SaaS |
*.pendo.io | Pendo product analytics |
*.salesforce.com | Salesforce CRM |
*.zendesk.com | Zendesk support |
*.freshdesk.com | Freshdesk support |
*.atlassian.net | Atlassian (Jira/Confluence) |
*.cloudfront.net | AWS CloudFront (if direct CNAME, not leaked via) |
*.vercel.app | Vercel hosting |
*.netlify.app | Netlify hosting |
*.azurewebsites.net | Azure App Service |
5.3 From Redirect Targets (location header)
launcher.myapps.microsoft.com→ Azure AD SSO (check URL for tenant ID)*.okta.com→ Okta SSOaccounts.google.com→ Google Workspace SSO*.auth0.com→ Auth0
5.4 Azure AD Tenant ID Extraction
If redirect leads to Microsoft login:
location: https://launcher.myapps.microsoft.com/api/signin/APP_ID?tenantId=TENANT_UUIDExtract tenantId= value - this is the organization's Azure AD tenant ID.
Phase 6 - Dual CDN Detection
This is a high-value finding often missed on first pass.
The pattern: Cloudflare as outer WAF → AWS CloudFront as real CDN → origin
curl -sI https://app.example.com | grep -iE 'via|x-amz|x-cache|server'Indicators:
server: cloudflareANDvia: 1.1 xxxxxxxxx.cloudfront.net (CloudFront)→ dual CDN confirmedx-amz-cf-pop: TLV55-P1→ CloudFront PoP in Tel Avivx-cache: Miss from cloudfront→ CloudFront active behind CFx-amz-cf-id:→ unique CloudFront request ID
Why it matters: Reveals true backend CDN provider, geographic PoP locations, and hints at origin server region.
Phase 7 - Cloudflare Bypass (Stealth Browser)
When Cloudflare blocks curl, use stealth Playwright.
Note: Critical package name: Use
puppeteer-extra-plugin-stealth- NOTplaywright-extra-plugin-stealth(that package does NOT exist and will throw an error).
cd /tmp && mkdir cf-stealth && cd cf-stealth
npm init -y
npm install playwright playwright-extra puppeteer-extra-plugin-stealth
npx playwright install chromiumconst { chromium } = require('playwright-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
chromium.use(StealthPlugin());
const targets = [
'https://app.example.com',
];
(async () => {
const browser = await chromium.launch({ headless: true });
for (const url of targets) {
const page = await browser.newPage();
const headers = {};
page.on('response', async resp => {
if (resp.url() === url || resp.url().startsWith(url)) {
Object.assign(headers, resp.headers());
}
});
try {
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 15000 });
console.log(JSON.stringify({ url, headers }));
} catch(e) {
console.log(JSON.stringify({ url, error: e.message }));
}
await page.close();
}
await browser.close();
})();Phase 8 - Nonintrusive Port Probe (Second Pass)
Don't run on Cloudflare IPs, don't run on WAFs/CDNs protected targets. Only look for applicative ports, don't overdo the web scan to more than a few strategic port decisions (passive-first approach).
for host in direct-ip-1 direct-ip-2; do
for port in 80 443 8080 8443 3000 4443; do
result=$(curl -sk --max-time 5 -o /dev/null -w "%{http_code}" \
"$([ $port = 443 ] || [ $port = 8443 ] && echo https || echo http)://$host:$port/")
[ "$result" != "000" ] && echo "$host:$port -> HTTP $result"
done
donePhase 9 - Subsidiary & Acquisition Research
Stealth startups acquired by the target may have no public domain - this is normal.
Search strategy:
"[company name]" acquisition site:crunchbase.com"[company name]" acquired site:techcrunch.com OR site:businesswire.com- LinkedIn: search target company name → filter by "acquired by" or check leadership history
- Check registrant/NS of likely related domains (founder names, product names)
Note: A stealth startup may have: no domain, no Wayback archive, no CT certificates, no passive DNS entries - this is expected, not a gap in enumeration.
Phase 10 - Notable Findings (Auto-Flag)
Always flag these automatically in the report:
| Pattern | Flag |
access-control-allow-origin: * | Warning - Open CORS - unauthenticated cross-origin requests allowed |
HTTP 525 status | Warning - SSL Handshake Failure - origin SSL misconfiguration behind Cloudflare |
server: gunicorn or server: unicorn with no CDN | Warning - Direct backend exposure - no WAF, origin IP exposed |
HTTP 301 → self (same host) | Info - Likely internal-only / auth-required (especially on cslab*, vpn*, admin*) |
Azure AD tenantId= in redirect URL | Info - Azure AD Tenant ID leak - extract UUID |
x-amz-cf-pop with city code | Info - CDN geographic PoP - reveals infrastructure region |
via: *.cloudfront.net on a CF-served domain | Info - Dual CDN architecture |
Subdomain → *.mail.protection.outlook.com CNAME | Info - Microsoft 365 tenant confirmation |
Phase 11 - Report Structure
Always produce the markdown report with this structure:
# [Company] Recon Report
**Date:** YYYY-MM-DD
**Scope:** domain1.com · domain2.io · domain3.com
## Table of Contents
1. Confirmed Owned Domains
2. Technology Stack Summary
3. Notable Findings
4. [Primary Domain] - Subdomain Headers
- Live - Cloudflare + CloudFront (Dual CDN)
- Live - Cloudflare Only
- Live - Third-Party / No CDN
- Cloudflare DNS-Only / No HTTP Response
5. [Other domains]
6. Ownership & Attribution
7. Enumeration Sources
## 1. Confirmed Owned Domains
| Domain | Registrar | Created | Nameservers | Verdict |
## 2. Technology Stack Summary
| Layer | Technology | Evidence |
## 3. Notable Findings
| Finding | Detail |
## 4. Per-Subdomain Tables
### [subdomain]
| Header | Value |
(include: status, ip, server, via, x-amz-cf-pop, x-cache, x-frame-options, CSP, CORS, location, platform)
## 5. Ownership & Attribution
(people, entities, investors, Azure tenant, WHOIS proof)
## 6. Enumeration Sources
| Source | Results | Method |
**Total unique subdomains: N**
**Vercel detected: yes / no**Common Pitfalls Reference
| Pitfall | Correct Approach |
| Assuming WHOIS registrant names identify owner | Use NS correlation + MX + TXT instead (privacy protection hides names) |
Assuming target.net or target.co = same company | Verify NS + MX independently - often different owners |
| Running crt.sh only for subdomain discovery | Always run 6+ sources in parallel |
| Doing header harvest after initial recon | Collect ALL headers in the first live check pass |
| Port scanning CF-fronted IPs | Pointless - Cloudflare terminates connections. Only port-scan direct/non-CF IPs |
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

