@intentsolutionsio/penetration-tester 2.0.0 → 3.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +8 -3
- package/README.md +8 -0
- package/commands/pentest.md +5 -0
- package/package.json +8 -3
- package/skills/analyzing-tls-config/SKILL.md +221 -0
- package/skills/analyzing-tls-config/references/AUTHORIZATION.md +133 -0
- package/skills/analyzing-tls-config/references/PLAYBOOK.md +267 -0
- package/skills/analyzing-tls-config/references/THEORY.md +128 -0
- package/skills/analyzing-tls-config/scripts/analyze_tls.py +415 -0
- package/skills/auditing-cors-policy/SKILL.md +186 -0
- package/skills/auditing-cors-policy/references/PLAYBOOK.md +220 -0
- package/skills/auditing-cors-policy/references/THEORY.md +142 -0
- package/skills/auditing-cors-policy/scripts/audit_cors.py +350 -0
- package/skills/auditing-npm-dependencies/SKILL.md +254 -0
- package/skills/auditing-npm-dependencies/references/PLAYBOOK.md +175 -0
- package/skills/auditing-npm-dependencies/references/THEORY.md +122 -0
- package/skills/auditing-npm-dependencies/scripts/audit_npm.py +408 -0
- package/skills/auditing-python-dependencies/SKILL.md +251 -0
- package/skills/auditing-python-dependencies/references/PLAYBOOK.md +193 -0
- package/skills/auditing-python-dependencies/references/THEORY.md +122 -0
- package/skills/auditing-python-dependencies/scripts/audit_python.py +459 -0
- package/skills/checking-http-security-headers/SKILL.md +176 -0
- package/skills/checking-http-security-headers/references/PLAYBOOK.md +212 -0
- package/skills/checking-http-security-headers/references/THEORY.md +137 -0
- package/skills/checking-http-security-headers/scripts/check_headers.py +362 -0
- package/skills/checking-license-compliance/SKILL.md +225 -0
- package/skills/checking-license-compliance/references/PLAYBOOK.md +161 -0
- package/skills/checking-license-compliance/references/THEORY.md +152 -0
- package/skills/checking-license-compliance/scripts/check_licenses.py +461 -0
- package/skills/composing-vulnerability-report/SKILL.md +212 -0
- package/skills/composing-vulnerability-report/references/PLAYBOOK.md +180 -0
- package/skills/composing-vulnerability-report/references/THEORY.md +178 -0
- package/skills/composing-vulnerability-report/scripts/compose_report.py +396 -0
- package/skills/confirming-pentest-authorization/SKILL.md +247 -0
- package/skills/confirming-pentest-authorization/references/PLAYBOOK.md +189 -0
- package/skills/confirming-pentest-authorization/references/THEORY.md +167 -0
- package/skills/confirming-pentest-authorization/scripts/check_authorization.py +457 -0
- package/skills/defining-pentest-scope/SKILL.md +227 -0
- package/skills/defining-pentest-scope/references/PLAYBOOK.md +238 -0
- package/skills/defining-pentest-scope/references/THEORY.md +170 -0
- package/skills/defining-pentest-scope/scripts/define_scope.py +472 -0
- package/skills/detecting-command-injection-patterns/SKILL.md +144 -0
- package/skills/detecting-command-injection-patterns/references/PLAYBOOK.md +302 -0
- package/skills/detecting-command-injection-patterns/references/THEORY.md +206 -0
- package/skills/detecting-command-injection-patterns/scripts/scan_cmdi.py +290 -0
- package/skills/detecting-debug-endpoints/SKILL.md +207 -0
- package/skills/detecting-debug-endpoints/references/PLAYBOOK.md +402 -0
- package/skills/detecting-debug-endpoints/references/THEORY.md +218 -0
- package/skills/detecting-debug-endpoints/scripts/probe_debug.py +518 -0
- package/skills/detecting-directory-listing/SKILL.md +206 -0
- package/skills/detecting-directory-listing/references/PLAYBOOK.md +277 -0
- package/skills/detecting-directory-listing/references/THEORY.md +203 -0
- package/skills/detecting-directory-listing/scripts/probe_directory_listing.py +180 -0
- package/skills/detecting-eval-exec-usage/SKILL.md +128 -0
- package/skills/detecting-eval-exec-usage/references/PLAYBOOK.md +306 -0
- package/skills/detecting-eval-exec-usage/references/THEORY.md +159 -0
- package/skills/detecting-eval-exec-usage/scripts/scan_eval.py +223 -0
- package/skills/detecting-exposed-secrets-files/SKILL.md +179 -0
- package/skills/detecting-exposed-secrets-files/references/PLAYBOOK.md +274 -0
- package/skills/detecting-exposed-secrets-files/references/THEORY.md +174 -0
- package/skills/detecting-exposed-secrets-files/scripts/probe_secrets.py +207 -0
- package/skills/detecting-insecure-deserialization/SKILL.md +148 -0
- package/skills/detecting-insecure-deserialization/references/PLAYBOOK.md +333 -0
- package/skills/detecting-insecure-deserialization/references/THEORY.md +199 -0
- package/skills/detecting-insecure-deserialization/scripts/scan_deserialization.py +250 -0
- package/skills/detecting-sql-injection-patterns/SKILL.md +161 -0
- package/skills/detecting-sql-injection-patterns/references/PLAYBOOK.md +317 -0
- package/skills/detecting-sql-injection-patterns/references/THEORY.md +261 -0
- package/skills/detecting-sql-injection-patterns/scripts/scan_sqli.py +354 -0
- package/skills/detecting-ssl-cert-issues/SKILL.md +182 -0
- package/skills/detecting-ssl-cert-issues/references/PLAYBOOK.md +203 -0
- package/skills/detecting-ssl-cert-issues/references/THEORY.md +133 -0
- package/skills/detecting-ssl-cert-issues/scripts/check_cert_chain.py +481 -0
- package/skills/detecting-weak-cryptography/SKILL.md +147 -0
- package/skills/detecting-weak-cryptography/references/PLAYBOOK.md +466 -0
- package/skills/detecting-weak-cryptography/references/THEORY.md +194 -0
- package/skills/detecting-weak-cryptography/scripts/scan_weak_crypto.py +417 -0
- package/skills/fingerprinting-server-software/SKILL.md +191 -0
- package/skills/fingerprinting-server-software/references/PLAYBOOK.md +337 -0
- package/skills/fingerprinting-server-software/references/THEORY.md +183 -0
- package/skills/fingerprinting-server-software/scripts/fingerprint_server.py +347 -0
- package/skills/generating-executive-summary/SKILL.md +261 -0
- package/skills/generating-executive-summary/references/PLAYBOOK.md +201 -0
- package/skills/generating-executive-summary/references/THEORY.md +195 -0
- package/skills/generating-executive-summary/scripts/exec_summary.py +538 -0
- package/skills/mapping-findings-to-owasp-top10/SKILL.md +235 -0
- package/skills/mapping-findings-to-owasp-top10/references/PLAYBOOK.md +193 -0
- package/skills/mapping-findings-to-owasp-top10/references/THEORY.md +160 -0
- package/skills/mapping-findings-to-owasp-top10/scripts/map_owasp.py +540 -0
- package/skills/performing-penetration-testing/SKILL.md +282 -190
- package/skills/performing-penetration-testing/references/OWASP_TOP_10.md +22 -0
- package/skills/performing-penetration-testing/references/REMEDIATION_PLAYBOOK.md +46 -0
- package/skills/performing-penetration-testing/references/SECURITY_HEADERS.md +41 -0
- package/skills/performing-penetration-testing/scripts/code_security_scanner.py +144 -79
- package/skills/performing-penetration-testing/scripts/dependency_auditor.py +116 -93
- package/skills/performing-penetration-testing/scripts/security_scanner.py +574 -446
- package/skills/probing-dangerous-http-methods/SKILL.md +182 -0
- package/skills/probing-dangerous-http-methods/references/PLAYBOOK.md +234 -0
- package/skills/probing-dangerous-http-methods/references/THEORY.md +145 -0
- package/skills/probing-dangerous-http-methods/scripts/probe_methods.py +263 -0
- package/skills/recording-pentest-engagement/SKILL.md +253 -0
- package/skills/recording-pentest-engagement/references/PLAYBOOK.md +203 -0
- package/skills/recording-pentest-engagement/references/THEORY.md +195 -0
- package/skills/recording-pentest-engagement/scripts/record_engagement.py +461 -0
- package/skills/scanning-for-hardcoded-secrets/SKILL.md +215 -0
- package/skills/scanning-for-hardcoded-secrets/references/PLAYBOOK.md +325 -0
- package/skills/scanning-for-hardcoded-secrets/references/THEORY.md +175 -0
- package/skills/scanning-for-hardcoded-secrets/scripts/scan_secrets.py +395 -0
- package/skills/tracing-transitive-vulnerabilities/SKILL.md +235 -0
- package/skills/tracing-transitive-vulnerabilities/references/PLAYBOOK.md +233 -0
- package/skills/tracing-transitive-vulnerabilities/references/THEORY.md +138 -0
- package/skills/tracing-transitive-vulnerabilities/scripts/trace_vulns.py +484 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
# PLAYBOOK — Scope Templates and Hand-Off Patterns
|
|
2
|
+
|
|
3
|
+
## Per-engagement-type scope templates
|
|
4
|
+
|
|
5
|
+
### External web app pentest
|
|
6
|
+
|
|
7
|
+
```yaml
|
|
8
|
+
in_scope_targets:
|
|
9
|
+
- host: app.acme.example
|
|
10
|
+
notes: production web app
|
|
11
|
+
- host: api.acme.example
|
|
12
|
+
notes: REST API; rate-limit 60 req/min observed
|
|
13
|
+
- url: https://app.acme.example/admin/
|
|
14
|
+
notes: admin UI (test as authorized admin user)
|
|
15
|
+
out_of_scope_targets:
|
|
16
|
+
- host: payments.acme.example
|
|
17
|
+
reason: PCI scope, separate authz required
|
|
18
|
+
- host: legal.acme.example
|
|
19
|
+
reason: third-party hosted; not customer's
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Internal network pentest
|
|
23
|
+
|
|
24
|
+
```yaml
|
|
25
|
+
in_scope_targets:
|
|
26
|
+
- cidr: 10.50.0.0/16
|
|
27
|
+
notes: corporate user range
|
|
28
|
+
- cidr: 10.51.0.0/16
|
|
29
|
+
notes: developer subnet
|
|
30
|
+
- cidr: 10.52.0.0/24
|
|
31
|
+
notes: test infrastructure
|
|
32
|
+
out_of_scope_targets:
|
|
33
|
+
- cidr: 10.99.0.0/16
|
|
34
|
+
reason: production DB tier, separate authz
|
|
35
|
+
- cidr: 10.250.0.0/24
|
|
36
|
+
reason: physical surveillance VLAN
|
|
37
|
+
- cidr: 10.251.0.0/24
|
|
38
|
+
reason: VOIP (avoid call disruption)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Red-team engagement
|
|
42
|
+
|
|
43
|
+
```yaml
|
|
44
|
+
in_scope_targets:
|
|
45
|
+
- cidr: 203.0.113.0/24
|
|
46
|
+
notes: customer ASN block 1
|
|
47
|
+
- cidr: 198.51.100.0/24
|
|
48
|
+
notes: customer ASN block 2
|
|
49
|
+
- host: "*.acme.example"
|
|
50
|
+
notes: any subdomain of acme.example
|
|
51
|
+
- cloud_account: aws:123456789012
|
|
52
|
+
notes: production AWS account
|
|
53
|
+
out_of_scope_targets:
|
|
54
|
+
- host: ceo.acme.example
|
|
55
|
+
reason: executive personal device
|
|
56
|
+
- cidr: 203.0.113.250/32
|
|
57
|
+
reason: SOC bastion (would tip off SOC)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Cloud account pentest (AWS)
|
|
61
|
+
|
|
62
|
+
```yaml
|
|
63
|
+
in_scope_targets:
|
|
64
|
+
- cloud_account: aws:123456789012
|
|
65
|
+
notes: prod-1 account; full read scope
|
|
66
|
+
- cloud_account: aws:210987654321
|
|
67
|
+
notes: prod-2 account; identity-services only
|
|
68
|
+
out_of_scope_targets:
|
|
69
|
+
- cloud_account: aws:999999999999
|
|
70
|
+
reason: management account; out of agreed scope
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### SaaS tenant pentest
|
|
74
|
+
|
|
75
|
+
```yaml
|
|
76
|
+
in_scope_targets:
|
|
77
|
+
- saas_tenant: okta:acme-corp
|
|
78
|
+
notes: customer Okta tenant; SSO config audit
|
|
79
|
+
- saas_tenant: auth0:acme
|
|
80
|
+
notes: customer Auth0 tenant
|
|
81
|
+
out_of_scope_targets:
|
|
82
|
+
- saas_tenant: salesforce:acme
|
|
83
|
+
reason: separate vendor-authz required
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Many SaaS vendors require explicit prior notification before
|
|
87
|
+
pentesting (Salesforce, Okta, etc. all have their own pentest
|
|
88
|
+
authorization forms). The skill flags `saas:` entries informationally;
|
|
89
|
+
the operator should verify the vendor's own authz separately.
|
|
90
|
+
|
|
91
|
+
## Allowlist emission patterns per scanner
|
|
92
|
+
|
|
93
|
+
### nmap
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
python3 ./scripts/define_scope.py --roe roe.yaml --emit-allowlist /tmp/allowed.txt
|
|
97
|
+
nmap -iL /tmp/allowed.txt -sV -oN nmap-scan.txt
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Burp Suite Target → Scope
|
|
101
|
+
|
|
102
|
+
Burp uses regex-based scope rules. Convert the allowlist by
|
|
103
|
+
escaping dots and accepting any port:
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
# Quick converter
|
|
107
|
+
import re
|
|
108
|
+
with open("/tmp/allowed.txt") as f:
|
|
109
|
+
for line in f:
|
|
110
|
+
entry = line.strip()
|
|
111
|
+
# Convert hostname/CIDR to Burp regex
|
|
112
|
+
print(re.escape(entry))
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Paste output into Burp's "Include in scope" with "Use advanced
|
|
116
|
+
scope control" enabled.
|
|
117
|
+
|
|
118
|
+
### AWS WAF allowlist
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
python3 - <<EOF
|
|
122
|
+
import json
|
|
123
|
+
ips = open("/tmp/allowed.txt").read().splitlines()
|
|
124
|
+
v4 = [ip for ip in ips if ":" not in ip]
|
|
125
|
+
print(json.dumps({"Addresses": v4}, indent=2))
|
|
126
|
+
EOF
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Pipe the output to `aws wafv2 update-ip-set` to install the
|
|
130
|
+
allowlist.
|
|
131
|
+
|
|
132
|
+
### Cloud security tools (ScoutSuite, Prowler, CloudSploit)
|
|
133
|
+
|
|
134
|
+
Cloud scope is by account ID, not IP. Read the `cloud_account`
|
|
135
|
+
entries from the normalized targets JSON:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
jq -r '.[] | select(.type=="cloud") | .normalized' /tmp/targets.json
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Scope-extension protocol
|
|
142
|
+
|
|
143
|
+
When testing reveals a target that should have been in scope but
|
|
144
|
+
wasn't:
|
|
145
|
+
|
|
146
|
+
1. Halt testing of the extension target.
|
|
147
|
+
2. Request a scope amendment from the authorizer.
|
|
148
|
+
3. Authorizer signs an extension YAML:
|
|
149
|
+
|
|
150
|
+
```yaml
|
|
151
|
+
amendment_id: ACME-2026-Q2-PENTEST-001-AMEND-01
|
|
152
|
+
amendment_to: ACME-2026-Q2-PENTEST-001
|
|
153
|
+
amendment_date: 2026-06-15T10:00:00Z
|
|
154
|
+
in_scope_targets:
|
|
155
|
+
- host: newly-discovered.acme.example
|
|
156
|
+
notes: discovered during port-scan of cidr 203.0.113.0/24; serves admin UI
|
|
157
|
+
signature_block:
|
|
158
|
+
signer: jane.doe@acme.example
|
|
159
|
+
signed_at: 2026-06-15T11:00:00Z
|
|
160
|
+
signature: |
|
|
161
|
+
<signature>
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
4. Re-run this skill with `--extension`.
|
|
165
|
+
5. Verify the new scope is clean before resuming testing.
|
|
166
|
+
|
|
167
|
+
## Allowlist file format
|
|
168
|
+
|
|
169
|
+
The `--emit-allowlist` output is one entry per line:
|
|
170
|
+
|
|
171
|
+
```
|
|
172
|
+
203.0.113.10
|
|
173
|
+
203.0.113.0/24
|
|
174
|
+
2001:db8::10
|
|
175
|
+
2001:db8::/64
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Hostnames are NOT in the allowlist (DNS resolves at scan time;
|
|
179
|
+
see THEORY.md). The normalized targets JSON is the source of
|
|
180
|
+
truth for hostnames + URLs + cloud accounts + SaaS tenants.
|
|
181
|
+
|
|
182
|
+
## Normalized targets JSON format
|
|
183
|
+
|
|
184
|
+
```json
|
|
185
|
+
[
|
|
186
|
+
{"raw": "app.acme.example", "type": "hostname", "normalized": "app.acme.example"},
|
|
187
|
+
{"raw": "203.0.113.0/24", "type": "cidrv4", "normalized": "203.0.113.0/24"},
|
|
188
|
+
{"raw": "https://api.acme.example/v2", "type": "url", "normalized": "https://api.acme.example/v2"},
|
|
189
|
+
{"raw": "aws:123456789012", "type": "cloud", "normalized": "aws:123456789012"}
|
|
190
|
+
]
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Downstream skills consume this JSON via `--targets-file` argument
|
|
194
|
+
patterns (planned across the cluster 1-4 skills).
|
|
195
|
+
|
|
196
|
+
## Common scope-mistake patterns
|
|
197
|
+
|
|
198
|
+
| Pattern | Fix |
|
|
199
|
+
|---|---|
|
|
200
|
+
| `host: 203.0.113.0/24` | Use `cidr:` not `host:` |
|
|
201
|
+
| `host: https://app.acme.example` | Use `url:` not `host:` |
|
|
202
|
+
| `cidr: 203.0.113.10` | Single IP without mask; CIDR /32 implied but explicit is better |
|
|
203
|
+
| Hostname with trailing dot (`acme.example.`) | DNS-canonical form; strip the dot |
|
|
204
|
+
| `*.acme.example/admin` | Mixes wildcard + path; not supported |
|
|
205
|
+
| Cloud account with hyphenated number `aws:1234-5678-9012` | Use bare number, no hyphens |
|
|
206
|
+
| Unicode in hostname (`münich.acme.example`) | Convert to Punycode (`xn--mnich-rta.acme.example`) |
|
|
207
|
+
|
|
208
|
+
## Pre-scan gate (CI)
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
python3 ./scripts/define_scope.py --roe roe.yaml --min-severity high \
|
|
212
|
+
--format json --output scope-issues.json
|
|
213
|
+
jq -e '. == []' scope-issues.json || {
|
|
214
|
+
echo "::error::Scope issues block testing"
|
|
215
|
+
exit 1
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
This pattern works for engagements where the ROE is checked into
|
|
220
|
+
a private engagement repo with CI.
|
|
221
|
+
|
|
222
|
+
## Scope drift detection between engagements
|
|
223
|
+
|
|
224
|
+
When running multiple engagements for the same customer over time,
|
|
225
|
+
diff this engagement's scope against the previous:
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
python3 ./scripts/define_scope.py --roe engagements/acme-2026-q1/roe.yaml \
|
|
229
|
+
--emit-targets engagements/acme-2026-q1/targets.json
|
|
230
|
+
python3 ./scripts/define_scope.py --roe engagements/acme-2026-q2/roe.yaml \
|
|
231
|
+
--emit-targets engagements/acme-2026-q2/targets.json
|
|
232
|
+
diff <(jq -S .[].normalized engagements/acme-2026-q1/targets.json) \
|
|
233
|
+
<(jq -S .[].normalized engagements/acme-2026-q2/targets.json)
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Scope changes between engagements are common (customer added new
|
|
237
|
+
infra, decommissioned old) — but they should be explicit and
|
|
238
|
+
documented, not silent.
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# THEORY — Scope as the Load-Bearing Artifact
|
|
2
|
+
|
|
3
|
+
## Why scope is the load-bearing legal artifact
|
|
4
|
+
|
|
5
|
+
Authorization is the gate (see `confirming-pentest-authorization`),
|
|
6
|
+
but SCOPE is the perimeter the authorization applies to. A signed
|
|
7
|
+
ROE that says "test ACME's stuff" authorizes nothing in practice
|
|
8
|
+
because it doesn't define ACME's stuff. The scope list is the
|
|
9
|
+
projection of "what we're allowed to touch" into a list of concrete
|
|
10
|
+
targets a tester or tool can verify against.
|
|
11
|
+
|
|
12
|
+
The skill's purpose is to convert the human-readable ROE scope
|
|
13
|
+
section into a machine-readable, syntactically-validated, conflict-
|
|
14
|
+
checked artifact that downstream cluster 1-4 skills can consume
|
|
15
|
+
without ambiguity.
|
|
16
|
+
|
|
17
|
+
## Target-type taxonomy
|
|
18
|
+
|
|
19
|
+
Real-world scope lists mix several target types. The taxonomy:
|
|
20
|
+
|
|
21
|
+
| Type | Use | Validation |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| Hostname | `app.acme.example` | Valid DNS character set, length |
|
|
24
|
+
| Wildcard | `*.acme.example` | Wildcard prefix + valid suffix |
|
|
25
|
+
| IPv4 | `203.0.113.10` | Valid 4-octet form |
|
|
26
|
+
| IPv4 CIDR | `203.0.113.0/24` | Valid network + mask |
|
|
27
|
+
| IPv6 | `2001:db8::10` | Valid hex form |
|
|
28
|
+
| IPv6 CIDR | `2001:db8::/32` | Valid network + mask |
|
|
29
|
+
| URL with path | `https://app.acme.example/api` | Valid URL parse + non-empty netloc |
|
|
30
|
+
| Cloud account | `aws:123456789012` | Recognized cloud prefix |
|
|
31
|
+
| SaaS tenant | `okta:acme-corp` | Recognized SaaS prefix |
|
|
32
|
+
|
|
33
|
+
Mixing types in one list is normal; the skill's `--emit-targets`
|
|
34
|
+
output preserves the type tagging so downstream tools can route
|
|
35
|
+
each entry to the right scanner.
|
|
36
|
+
|
|
37
|
+
## Why DNS resolution is NOT done at scope-definition time
|
|
38
|
+
|
|
39
|
+
It would be tempting to resolve every hostname to its current IP
|
|
40
|
+
at scope-definition time and bake the IPs into the allowlist. This
|
|
41
|
+
is wrong, for two reasons:
|
|
42
|
+
|
|
43
|
+
1. **DNS resolution is itself a probe.** A DNS query against the
|
|
44
|
+
target's authoritative DNS server (or against a recursive
|
|
45
|
+
resolver that forwards to it) is detectable by sophisticated
|
|
46
|
+
defenders. By the governance model, no probes happen before
|
|
47
|
+
scope is locked.
|
|
48
|
+
|
|
49
|
+
2. **DNS changes during the engagement.** Resolving `app.acme.example`
|
|
50
|
+
to `203.0.113.10` at scope-definition time, then having the
|
|
51
|
+
customer's load balancer rotate to `203.0.113.11` mid-engagement,
|
|
52
|
+
means the tester's IP allowlist is stale. Hostname-based scope
|
|
53
|
+
resolves at scan time and tracks current DNS state.
|
|
54
|
+
|
|
55
|
+
The downstream cluster 1 skills resolve hostnames at scan time
|
|
56
|
+
themselves. The allowlist this skill emits contains the explicit
|
|
57
|
+
IPs/CIDRs the ROE listed, not resolved hostnames.
|
|
58
|
+
|
|
59
|
+
## CIDR overlap detection
|
|
60
|
+
|
|
61
|
+
Python's `ipaddress` module provides exact CIDR-overlap checks
|
|
62
|
+
via `IPv4Network.overlaps()` / `IPv6Network.overlaps()`. The skill
|
|
63
|
+
uses these directly.
|
|
64
|
+
|
|
65
|
+
A subtle case: `203.0.113.0/24` overlaps `203.0.113.128/25` (the
|
|
66
|
+
second is a sub-range of the first). If the ROE has the /24 in
|
|
67
|
+
in-scope and the /25 in out-of-scope, the skill emits a CRITICAL
|
|
68
|
+
finding: probing within the /25 sub-range would violate the
|
|
69
|
+
exclusion.
|
|
70
|
+
|
|
71
|
+
The customer's authorizer decides the resolution:
|
|
72
|
+
|
|
73
|
+
- Narrow in-scope to `203.0.113.0/25` (excludes the /25 explicitly)
|
|
74
|
+
- Remove the out-of-scope /25 entry (broaden authorization)
|
|
75
|
+
- Keep both and require per-target check at scan time
|
|
76
|
+
|
|
77
|
+
## Known third-party SaaS ranges
|
|
78
|
+
|
|
79
|
+
The skill ships an illustrative (NOT exhaustive) map of well-known
|
|
80
|
+
cloud / CDN / SaaS ranges. The most common ones in customer scope
|
|
81
|
+
lists by accident:
|
|
82
|
+
|
|
83
|
+
- AWS — customer mistakes their AWS-hosted endpoint's CDN front
|
|
84
|
+
for their own infrastructure.
|
|
85
|
+
- Cloudflare — customer's domain resolves to Cloudflare; the IP
|
|
86
|
+
is Cloudflare's, not the customer's.
|
|
87
|
+
- GitHub — customer's hosted-status page or docs site is on GitHub
|
|
88
|
+
Pages.
|
|
89
|
+
- Vercel / Netlify — customer's marketing site frontend.
|
|
90
|
+
|
|
91
|
+
Probing these without separate authorization is testing the SaaS
|
|
92
|
+
vendor's infrastructure, which is almost universally prohibited
|
|
93
|
+
without the SaaS vendor's own pentest-authorization process.
|
|
94
|
+
|
|
95
|
+
Real engagements should consult the authoritative published IP
|
|
96
|
+
ranges:
|
|
97
|
+
|
|
98
|
+
- AWS: https://ip-ranges.amazonaws.com/ip-ranges.json
|
|
99
|
+
- Cloudflare: https://www.cloudflare.com/ips/
|
|
100
|
+
- GCP: https://www.gstatic.com/ipranges/cloud.json
|
|
101
|
+
- Azure: published quarterly as a JSON file
|
|
102
|
+
|
|
103
|
+
A future skill enhancement could ingest these authoritative
|
|
104
|
+
sources at scope-definition time and verify against current data.
|
|
105
|
+
|
|
106
|
+
## Reserved ranges
|
|
107
|
+
|
|
108
|
+
The skill flags RFC1918 (`10/8`, `172.16/12`, `192.168/16`),
|
|
109
|
+
link-local (`169.254/16`), multicast (`224/4`), loopback
|
|
110
|
+
(`127/8`), and IPv6 equivalents.
|
|
111
|
+
|
|
112
|
+
In an internal pentest, RFC1918 ranges are expected — these are
|
|
113
|
+
the customer's internal networks. The skill flags them as MEDIUM
|
|
114
|
+
rather than HIGH/CRITICAL: "verify intentional." The customer's
|
|
115
|
+
acknowledgement of the internal-pentest context resolves the
|
|
116
|
+
finding.
|
|
117
|
+
|
|
118
|
+
In an external pentest, RFC1918 in scope is a configuration error —
|
|
119
|
+
the tester would be testing their own network, not the customer's.
|
|
120
|
+
The skill cannot determine engagement type from the ROE alone, so
|
|
121
|
+
the operator interprets the finding in context.
|
|
122
|
+
|
|
123
|
+
## Wildcard subdomain semantics
|
|
124
|
+
|
|
125
|
+
`*.acme.example` is a scope-by-pattern. It says "any subdomain of
|
|
126
|
+
acme.example is in scope." The skill flags wildcards as INFO
|
|
127
|
+
because they're not malformed but they ARE broad — the customer
|
|
128
|
+
should confirm intent.
|
|
129
|
+
|
|
130
|
+
Wildcard expansion happens at scan time, when the tester:
|
|
131
|
+
|
|
132
|
+
1. Enumerates subdomains via passive sources (Certificate
|
|
133
|
+
Transparency, DNS history, brute-force).
|
|
134
|
+
2. Each enumerated subdomain is checked against the wildcard's
|
|
135
|
+
pattern.
|
|
136
|
+
3. Matched subdomains become concrete targets.
|
|
137
|
+
|
|
138
|
+
The cluster 2 fingerprinting skills handle subdomain enumeration.
|
|
139
|
+
|
|
140
|
+
## Scope hygiene patterns
|
|
141
|
+
|
|
142
|
+
Three patterns characterize well-defined scope lists:
|
|
143
|
+
|
|
144
|
+
1. **Explicit inclusion + explicit exclusion.** Always have both
|
|
145
|
+
lists, even if one is empty. "Nothing else is included"
|
|
146
|
+
beats "I assume the rest is excluded."
|
|
147
|
+
|
|
148
|
+
2. **Type-tagged entries.** Use the schema's `host:` / `cidr:` /
|
|
149
|
+
`url:` keys explicitly. Bare string entries work but require
|
|
150
|
+
the skill to guess the type, which can produce subtle errors.
|
|
151
|
+
|
|
152
|
+
3. **Notes on every entry.** Why is this in scope? Why is this
|
|
153
|
+
out? Future you, six months from now, won't remember.
|
|
154
|
+
|
|
155
|
+
## When scope changes mid-engagement
|
|
156
|
+
|
|
157
|
+
The protocol:
|
|
158
|
+
|
|
159
|
+
1. Tester requests amendment via the engagement's documented
|
|
160
|
+
communication channel.
|
|
161
|
+
2. Authorizer signs an amendment YAML referencing the original
|
|
162
|
+
ROE's `engagement_id`.
|
|
163
|
+
3. Tester archives the amendment alongside the original ROE.
|
|
164
|
+
4. Re-run this skill with `--extension` pointing at the
|
|
165
|
+
amendment.
|
|
166
|
+
5. The new combined scope becomes the authoritative scope from
|
|
167
|
+
the amendment timestamp forward.
|
|
168
|
+
|
|
169
|
+
Never extend scope by verbal agreement. The whole point of the
|
|
170
|
+
ROE schema is that scope changes are auditable.
|