@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.
Files changed (112) hide show
  1. package/.claude-plugin/plugin.json +8 -3
  2. package/README.md +8 -0
  3. package/commands/pentest.md +5 -0
  4. package/package.json +8 -3
  5. package/skills/analyzing-tls-config/SKILL.md +221 -0
  6. package/skills/analyzing-tls-config/references/AUTHORIZATION.md +133 -0
  7. package/skills/analyzing-tls-config/references/PLAYBOOK.md +267 -0
  8. package/skills/analyzing-tls-config/references/THEORY.md +128 -0
  9. package/skills/analyzing-tls-config/scripts/analyze_tls.py +415 -0
  10. package/skills/auditing-cors-policy/SKILL.md +186 -0
  11. package/skills/auditing-cors-policy/references/PLAYBOOK.md +220 -0
  12. package/skills/auditing-cors-policy/references/THEORY.md +142 -0
  13. package/skills/auditing-cors-policy/scripts/audit_cors.py +350 -0
  14. package/skills/auditing-npm-dependencies/SKILL.md +254 -0
  15. package/skills/auditing-npm-dependencies/references/PLAYBOOK.md +175 -0
  16. package/skills/auditing-npm-dependencies/references/THEORY.md +122 -0
  17. package/skills/auditing-npm-dependencies/scripts/audit_npm.py +408 -0
  18. package/skills/auditing-python-dependencies/SKILL.md +251 -0
  19. package/skills/auditing-python-dependencies/references/PLAYBOOK.md +193 -0
  20. package/skills/auditing-python-dependencies/references/THEORY.md +122 -0
  21. package/skills/auditing-python-dependencies/scripts/audit_python.py +459 -0
  22. package/skills/checking-http-security-headers/SKILL.md +176 -0
  23. package/skills/checking-http-security-headers/references/PLAYBOOK.md +212 -0
  24. package/skills/checking-http-security-headers/references/THEORY.md +137 -0
  25. package/skills/checking-http-security-headers/scripts/check_headers.py +362 -0
  26. package/skills/checking-license-compliance/SKILL.md +225 -0
  27. package/skills/checking-license-compliance/references/PLAYBOOK.md +161 -0
  28. package/skills/checking-license-compliance/references/THEORY.md +152 -0
  29. package/skills/checking-license-compliance/scripts/check_licenses.py +461 -0
  30. package/skills/composing-vulnerability-report/SKILL.md +212 -0
  31. package/skills/composing-vulnerability-report/references/PLAYBOOK.md +180 -0
  32. package/skills/composing-vulnerability-report/references/THEORY.md +178 -0
  33. package/skills/composing-vulnerability-report/scripts/compose_report.py +396 -0
  34. package/skills/confirming-pentest-authorization/SKILL.md +247 -0
  35. package/skills/confirming-pentest-authorization/references/PLAYBOOK.md +189 -0
  36. package/skills/confirming-pentest-authorization/references/THEORY.md +167 -0
  37. package/skills/confirming-pentest-authorization/scripts/check_authorization.py +457 -0
  38. package/skills/defining-pentest-scope/SKILL.md +227 -0
  39. package/skills/defining-pentest-scope/references/PLAYBOOK.md +238 -0
  40. package/skills/defining-pentest-scope/references/THEORY.md +170 -0
  41. package/skills/defining-pentest-scope/scripts/define_scope.py +472 -0
  42. package/skills/detecting-command-injection-patterns/SKILL.md +144 -0
  43. package/skills/detecting-command-injection-patterns/references/PLAYBOOK.md +302 -0
  44. package/skills/detecting-command-injection-patterns/references/THEORY.md +206 -0
  45. package/skills/detecting-command-injection-patterns/scripts/scan_cmdi.py +290 -0
  46. package/skills/detecting-debug-endpoints/SKILL.md +207 -0
  47. package/skills/detecting-debug-endpoints/references/PLAYBOOK.md +402 -0
  48. package/skills/detecting-debug-endpoints/references/THEORY.md +218 -0
  49. package/skills/detecting-debug-endpoints/scripts/probe_debug.py +518 -0
  50. package/skills/detecting-directory-listing/SKILL.md +206 -0
  51. package/skills/detecting-directory-listing/references/PLAYBOOK.md +277 -0
  52. package/skills/detecting-directory-listing/references/THEORY.md +203 -0
  53. package/skills/detecting-directory-listing/scripts/probe_directory_listing.py +180 -0
  54. package/skills/detecting-eval-exec-usage/SKILL.md +128 -0
  55. package/skills/detecting-eval-exec-usage/references/PLAYBOOK.md +306 -0
  56. package/skills/detecting-eval-exec-usage/references/THEORY.md +159 -0
  57. package/skills/detecting-eval-exec-usage/scripts/scan_eval.py +223 -0
  58. package/skills/detecting-exposed-secrets-files/SKILL.md +179 -0
  59. package/skills/detecting-exposed-secrets-files/references/PLAYBOOK.md +274 -0
  60. package/skills/detecting-exposed-secrets-files/references/THEORY.md +174 -0
  61. package/skills/detecting-exposed-secrets-files/scripts/probe_secrets.py +207 -0
  62. package/skills/detecting-insecure-deserialization/SKILL.md +148 -0
  63. package/skills/detecting-insecure-deserialization/references/PLAYBOOK.md +333 -0
  64. package/skills/detecting-insecure-deserialization/references/THEORY.md +199 -0
  65. package/skills/detecting-insecure-deserialization/scripts/scan_deserialization.py +250 -0
  66. package/skills/detecting-sql-injection-patterns/SKILL.md +161 -0
  67. package/skills/detecting-sql-injection-patterns/references/PLAYBOOK.md +317 -0
  68. package/skills/detecting-sql-injection-patterns/references/THEORY.md +261 -0
  69. package/skills/detecting-sql-injection-patterns/scripts/scan_sqli.py +354 -0
  70. package/skills/detecting-ssl-cert-issues/SKILL.md +182 -0
  71. package/skills/detecting-ssl-cert-issues/references/PLAYBOOK.md +203 -0
  72. package/skills/detecting-ssl-cert-issues/references/THEORY.md +133 -0
  73. package/skills/detecting-ssl-cert-issues/scripts/check_cert_chain.py +481 -0
  74. package/skills/detecting-weak-cryptography/SKILL.md +147 -0
  75. package/skills/detecting-weak-cryptography/references/PLAYBOOK.md +466 -0
  76. package/skills/detecting-weak-cryptography/references/THEORY.md +194 -0
  77. package/skills/detecting-weak-cryptography/scripts/scan_weak_crypto.py +417 -0
  78. package/skills/fingerprinting-server-software/SKILL.md +191 -0
  79. package/skills/fingerprinting-server-software/references/PLAYBOOK.md +337 -0
  80. package/skills/fingerprinting-server-software/references/THEORY.md +183 -0
  81. package/skills/fingerprinting-server-software/scripts/fingerprint_server.py +347 -0
  82. package/skills/generating-executive-summary/SKILL.md +261 -0
  83. package/skills/generating-executive-summary/references/PLAYBOOK.md +201 -0
  84. package/skills/generating-executive-summary/references/THEORY.md +195 -0
  85. package/skills/generating-executive-summary/scripts/exec_summary.py +538 -0
  86. package/skills/mapping-findings-to-owasp-top10/SKILL.md +235 -0
  87. package/skills/mapping-findings-to-owasp-top10/references/PLAYBOOK.md +193 -0
  88. package/skills/mapping-findings-to-owasp-top10/references/THEORY.md +160 -0
  89. package/skills/mapping-findings-to-owasp-top10/scripts/map_owasp.py +540 -0
  90. package/skills/performing-penetration-testing/SKILL.md +282 -190
  91. package/skills/performing-penetration-testing/references/OWASP_TOP_10.md +22 -0
  92. package/skills/performing-penetration-testing/references/REMEDIATION_PLAYBOOK.md +46 -0
  93. package/skills/performing-penetration-testing/references/SECURITY_HEADERS.md +41 -0
  94. package/skills/performing-penetration-testing/scripts/code_security_scanner.py +144 -79
  95. package/skills/performing-penetration-testing/scripts/dependency_auditor.py +116 -93
  96. package/skills/performing-penetration-testing/scripts/security_scanner.py +574 -446
  97. package/skills/probing-dangerous-http-methods/SKILL.md +182 -0
  98. package/skills/probing-dangerous-http-methods/references/PLAYBOOK.md +234 -0
  99. package/skills/probing-dangerous-http-methods/references/THEORY.md +145 -0
  100. package/skills/probing-dangerous-http-methods/scripts/probe_methods.py +263 -0
  101. package/skills/recording-pentest-engagement/SKILL.md +253 -0
  102. package/skills/recording-pentest-engagement/references/PLAYBOOK.md +203 -0
  103. package/skills/recording-pentest-engagement/references/THEORY.md +195 -0
  104. package/skills/recording-pentest-engagement/scripts/record_engagement.py +461 -0
  105. package/skills/scanning-for-hardcoded-secrets/SKILL.md +215 -0
  106. package/skills/scanning-for-hardcoded-secrets/references/PLAYBOOK.md +325 -0
  107. package/skills/scanning-for-hardcoded-secrets/references/THEORY.md +175 -0
  108. package/skills/scanning-for-hardcoded-secrets/scripts/scan_secrets.py +395 -0
  109. package/skills/tracing-transitive-vulnerabilities/SKILL.md +235 -0
  110. package/skills/tracing-transitive-vulnerabilities/references/PLAYBOOK.md +233 -0
  111. package/skills/tracing-transitive-vulnerabilities/references/THEORY.md +138 -0
  112. package/skills/tracing-transitive-vulnerabilities/scripts/trace_vulns.py +484 -0
@@ -0,0 +1,251 @@
1
+ ---
2
+ name: auditing-python-dependencies
3
+ description: |
4
+ Audit a Python project's installed dependencies for known CVEs by
5
+ wrapping pip-audit (PyPA's official vulnerability auditor) and
6
+ emitting findings in the canonical penetration-tester schema.
7
+ Detects vulnerable direct AND transitive packages, normalizes
8
+ pip-audit's severity output via OSV severity bands, falls back to
9
+ pip list --outdated when pip-audit isn't installed, and supports
10
+ requirements.txt, pyproject.toml (PEP 621), Pipfile.lock, and
11
+ poetry.lock as input sources.
12
+ Use when: pre-merge gate on a Python project, post-incident sweep
13
+ after a PyPI compromise (e.g. ctx, request-toolbelt typosquats,
14
+ ultralytics 8.3.42 compromise), SOC2 evidence collection, or
15
+ inheriting an unfamiliar Python codebase.
16
+ Threshold: any HIGH or CRITICAL CVE in the resolved dependency
17
+ tree. MODERATE / LOW reported informationally.
18
+ Trigger with: "audit python deps", "pip vulnerability scan",
19
+ "check pypi packages for CVEs", "pip-audit run".
20
+ allowed-tools:
21
+ - Read
22
+ - Bash(pip:*)
23
+ - Bash(pip-audit:*)
24
+ - Bash(python3:*)
25
+ - Glob
26
+ disallowed-tools:
27
+ - Bash(rm:*)
28
+ - Bash(curl:*)
29
+ - Bash(wget:*)
30
+ - Write(.env)
31
+ - Edit(.env)
32
+ - Bash(pip install:*)
33
+ - Bash(pip uninstall:*)
34
+ version: 3.0.0-dev
35
+ author: Jeremy Longshore <jeremy@intentsolutions.io>
36
+ license: MIT
37
+ compatibility: Designed for Claude Code
38
+ tags:
39
+ - security
40
+ - dependency-audit
41
+ - python
42
+ - pypi
43
+ - cve
44
+ - pentest
45
+ ---
46
+
47
+ # Auditing Python Dependencies
48
+
49
+ ## Overview
50
+
51
+ PyPI hosts north of 500,000 packages, with several thousand new
52
+ releases every day. The package-install model is identical to npm in
53
+ the relevant ways: a `pip install` resolves a transitive graph,
54
+ runs each package's `setup.py` (which executes arbitrary Python at
55
+ install time), and writes the result to your site-packages. The CVE
56
+ attack surface is therefore the same shape: known vulnerabilities,
57
+ maintainer-account takeovers, typosquats, and protestware.
58
+
59
+ The PyPA-blessed auditor is `pip-audit`. It queries the Open Source
60
+ Vulnerabilities (OSV) database (which mirrors PyPA's advisory feed
61
+ plus aggregated CVE / GHSA records) and reports per-package
62
+ vulnerable versions. `pip-audit` integrates with `requirements.txt`,
63
+ `pyproject.toml`, `Pipfile.lock`, and `poetry.lock`, so most Python
64
+ project layouts are first-class.
65
+
66
+ This skill wraps `pip-audit`, normalizes its severity vocabulary to
67
+ the shared `Severity` enum, and emits Findings in the canonical
68
+ penetration-tester schema. If `pip-audit` isn't installed on the
69
+ host, the skill falls back to `pip list --outdated` and emits
70
+ INFO-level findings recommending the operator install pip-audit
71
+ for accurate vulnerability detection.
72
+
73
+ ## When the skill produces findings
74
+
75
+ | Finding | Severity | Threshold | Affected control |
76
+ |---|---|---|---|
77
+ | Critical CVE in installed package | **CRITICAL** | OSV severity band corresponds to CVSS ≥ 9.0 | CWE-1104 |
78
+ | High CVE in installed package | **HIGH** | OSV severity band corresponds to CVSS 7.0–8.9 | CWE-1104 |
79
+ | Medium CVE in installed package | **MEDIUM** | OSV severity band corresponds to CVSS 4.0–6.9 | CWE-1104 |
80
+ | Low CVE in installed package | **LOW** | OSV severity band corresponds to CVSS 0.1–3.9 | CWE-1104 |
81
+ | Vulnerable package with no patch | **HIGH** | finding has no `fix_versions` and severity ≥ medium | CWE-1395 |
82
+ | Outdated package (no CVE) | **INFO** | pip list --outdated reports a newer version | (operational) |
83
+ | pip-audit not installed | **INFO** | binary not on PATH; scanner fell back to pip list | (operational) |
84
+ | Audit DB unreachable | **INFO** | pip-audit network error reaching OSV | (operational) |
85
+
86
+ OSV is the upstream of record. pip-audit also consults the PyPA
87
+ advisory database for Python-specific records that may not yet have
88
+ a CVE assigned.
89
+
90
+ ## Prerequisites
91
+
92
+ - Python 3.9+
93
+ - `pip-audit` installed (`pip install pip-audit`); skill falls back
94
+ to `pip list --outdated` if absent
95
+ - Target project containing at minimum one of: `requirements.txt`,
96
+ `pyproject.toml`, `Pipfile.lock`, `poetry.lock`
97
+ - Network access to OSV (`api.osv.dev`) and PyPI (`pypi.org`)
98
+
99
+ ## Instructions
100
+
101
+ ### Step 1 — Identify the scan target
102
+
103
+ Locate the project directory. The scanner auto-detects requirement
104
+ files in order of preference:
105
+
106
+ 1. `poetry.lock` (most precise — exact resolved tree)
107
+ 2. `Pipfile.lock`
108
+ 3. `requirements.txt` (and `requirements-*.txt` siblings)
109
+ 4. `pyproject.toml` (PEP 621 dependencies)
110
+ 5. Installed environment via `pip list` (last resort)
111
+
112
+ ### Step 2 — Run the audit
113
+
114
+ ```bash
115
+ python3 ./scripts/audit_python.py /path/to/python-project
116
+ ```
117
+
118
+ Options:
119
+
120
+ ```
121
+ Usage: audit_python.py PATH [OPTIONS]
122
+
123
+ Options:
124
+ --output FILE Write findings to FILE (default: stdout)
125
+ --format FMT json | jsonl | markdown (default: markdown)
126
+ --min-severity SEV (default: info)
127
+ --requirement FILE Override auto-detection; specify a particular
128
+ requirements file (repeatable)
129
+ --include-dev Include development dependencies (default: prod
130
+ only when project layout allows the distinction)
131
+ --strict Treat pip-audit warnings as errors
132
+ ```
133
+
134
+ ### Step 3 — Interpret findings
135
+
136
+ CRITICAL / HIGH = block release.
137
+
138
+ MEDIUM / LOW = track but don't block; many Python advisories report
139
+ edge-case theoretical issues that don't apply to your usage.
140
+
141
+ INFO = log only; e.g. "outdated but no known CVE" is information for
142
+ your release cadence, not a security action.
143
+
144
+ ### Step 4 — Remediation
145
+
146
+ For a vulnerable package with `fix_versions`:
147
+
148
+ 1. Bump the version pin in your requirements file:
149
+
150
+ ```diff
151
+ - requests==2.20.0
152
+ + requests==2.31.0
153
+ ```
154
+
155
+ 2. Run `pip install -r requirements.txt --upgrade` (or
156
+ `poetry lock --no-update && poetry update <pkg>`).
157
+
158
+ 3. Run the test suite. CVE fixes occasionally include behavioral
159
+ changes you didn't expect.
160
+
161
+ 4. Commit the lock file diff alongside the requirements bump.
162
+
163
+ For a vulnerable transitive dep (one you didn't declare directly):
164
+
165
+ 1. Find the parent: `pip show <vulnerable-package>` lists the parents
166
+ in its "Required-by" line.
167
+
168
+ 2. Check whether bumping the parent picks up the fix. `pip index
169
+ versions <parent>` lists available versions.
170
+
171
+ 3. If parent doesn't have a newer release that floors the vulnerable
172
+ dep above the fix version, pin the transitive dep yourself in
173
+ your requirements file. pip will use the more specific pin.
174
+
175
+ For a vulnerable package with NO fix available:
176
+
177
+ 1. Subscribe to PyPA advisory notifications for that package.
178
+
179
+ 2. If the vulnerability is exploitable in your usage, either
180
+ replace the package or vendor + patch locally.
181
+
182
+ 3. Document the exception in your security register with a
183
+ re-evaluation date.
184
+
185
+ ## Examples
186
+
187
+ ### Example 1 — Pre-merge gate
188
+
189
+ ```bash
190
+ python3 ./scripts/audit_python.py . --min-severity high --format json --output audit.json
191
+ jq -e '. == []' audit.json || { echo "High/critical Python CVE — fix before merge"; exit 1; }
192
+ ```
193
+
194
+ ### Example 2 — CI scan on every push
195
+
196
+ ```yaml
197
+ - name: pip-audit
198
+ run: pip install pip-audit
199
+ - name: Run audit
200
+ run: |
201
+ python3 plugins/security/penetration-tester/skills/auditing-python-dependencies/scripts/audit_python.py \
202
+ . --min-severity high --format markdown --output py-audit.md
203
+ ```
204
+
205
+ ### Example 3 — SOC2 evidence collection
206
+
207
+ ```bash
208
+ mkdir -p evidence/CC7/
209
+ python3 ./scripts/audit_python.py . --include-dev --format json \
210
+ --output evidence/CC7/py-audit-$(date +%Y%m%d).json
211
+ ```
212
+
213
+ `--include-dev` for SOC2: include dev/test deps so auditors see the
214
+ full surface, not just production.
215
+
216
+ ## Output
217
+
218
+ JSON / JSONL / Markdown per `lib/report.py`. Exit codes: 0 clean, 1
219
+ high/critical, 2 error.
220
+
221
+ Each Finding includes:
222
+
223
+ - `id` — synthesized as `pypi-audit::<cve-id>` (or `pypi-audit::<ghsa>` / `pypi-audit::<pypa-id>` when no CVE)
224
+ - `severity` — CRITICAL / HIGH / MEDIUM / LOW / INFO
225
+ - `category` — `dependency-vulnerability`
226
+ - `summary` — short CVE / GHSA title
227
+ - `evidence` — affected package, affected version, fix versions, advisory ID
228
+ - `references` — OSV URL, CVE URL, PyPA advisory URL
229
+
230
+ ## Error Handling
231
+
232
+ - **pip-audit not installed** → falls back to `pip list --outdated`,
233
+ emits an INFO Finding flagging the degraded scan, and proceeds.
234
+ - **No requirement file found** → emits an INFO Finding "no Python
235
+ project structure recognized" and exits 2.
236
+ - **OSV API unreachable** → emits an INFO Finding documenting the
237
+ outage and exits 0 (no actionable security finding).
238
+ - **pip-audit returns malformed JSON** → emits an INFO Finding with
239
+ the raw output truncated to 500 chars and exits 2.
240
+
241
+ ## Resources
242
+
243
+ - `references/THEORY.md` — PyPI supply-chain history, OSV vs NVD vs
244
+ PyPA advisory scopes, why ecosystem-specific severity matters,
245
+ Python-specific install-time risks (setup.py execution, eager
246
+ dependency resolution), pip-audit vs Safety vs Snyk trade-offs
247
+ - `references/PLAYBOOK.md` — Per-toolchain remediation patterns
248
+ (pip + requirements.txt, poetry, pipenv, uv, conda), monorepo /
249
+ workspace scanning, override-equivalent patterns in Python
250
+ ecosystem, GitHub Dependabot ecosystem mapping, SOC2 evidence
251
+ retention
@@ -0,0 +1,193 @@
1
+ # PLAYBOOK — Remediating Python Findings
2
+
3
+ ## Per-toolchain remediation patterns
4
+
5
+ ### Plain requirements.txt + pip
6
+
7
+ ```bash
8
+ # Edit requirements.txt to bump the pinned version
9
+ sed -i 's/requests==2.20.0/requests==2.31.0/' requirements.txt
10
+ pip install -r requirements.txt --upgrade
11
+ pytest # confirm no behavior regressions
12
+ git add requirements.txt && git commit -m "fix: bump requests to 2.31.0 (CVE-XXXX)"
13
+ ```
14
+
15
+ If you have a separate `requirements-lock.txt` generated by
16
+ `pip-compile`:
17
+
18
+ ```bash
19
+ pip-compile --upgrade-package requests requirements.in
20
+ ```
21
+
22
+ ### Poetry
23
+
24
+ ```bash
25
+ poetry add requests@^2.31.0
26
+ poetry lock --no-update # refresh just the affected entry
27
+ poetry install
28
+ pytest
29
+ git add pyproject.toml poetry.lock
30
+ ```
31
+
32
+ For a transitive bump (a dep not declared directly):
33
+
34
+ ```bash
35
+ poetry add requests@^2.31.0 --lock # forces resolution even if not direct
36
+ ```
37
+
38
+ Or use the `dependencies` table to pin transitive deps without
39
+ adding them as your project's direct deps.
40
+
41
+ ### Pipenv
42
+
43
+ ```bash
44
+ pipenv update requests
45
+ pipenv lock
46
+ pipenv install --deploy --ignore-pipfile # smoke test
47
+ ```
48
+
49
+ ### uv (modern fast resolver)
50
+
51
+ ```bash
52
+ uv pip install --upgrade requests
53
+ uv pip freeze > requirements.txt # if you track frozen requirements
54
+ ```
55
+
56
+ ### conda environments
57
+
58
+ `pip-audit` does not natively audit conda packages, only pip
59
+ packages installed inside a conda environment. If a vulnerability
60
+ affects a conda-installed package, fix via `conda update <pkg>`
61
+ and document the manual remediation; pip-audit will not see the
62
+ finding go away on its own.
63
+
64
+ ## Transitive dependency overrides
65
+
66
+ Python has no first-class `overrides` equivalent like npm 8.3+.
67
+ The patterns:
68
+
69
+ ### Pin in requirements (works in pip)
70
+
71
+ If `boto3` pulls in `urllib3<2.0` and you need `urllib3>=2.0.2`:
72
+
73
+ ```
74
+ urllib3>=2.0.2
75
+ boto3==1.34.0
76
+ ```
77
+
78
+ pip's resolver prefers the more specific version. This sometimes
79
+ causes conflicts the resolver flags ("ResolutionImpossible"); when
80
+ that happens, the parent itself needs to be bumped.
81
+
82
+ ### Poetry constraints
83
+
84
+ ```toml
85
+ [tool.poetry.dependencies]
86
+ boto3 = "^1.34.0"
87
+ urllib3 = "^2.0.2" # add as a direct dep to force the floor
88
+ ```
89
+
90
+ This makes the transitive dep your direct dep, which is messy but
91
+ effective.
92
+
93
+ ### Reset and re-resolve
94
+
95
+ When a transitive override produces conflicts, sometimes the cleanest
96
+ fix is to delete the lock file, bump everything, and re-resolve.
97
+ Reserve for major version refreshes or when you have a release window
98
+ to validate the full diff.
99
+
100
+ ## Monorepo / workspace scanning
101
+
102
+ For monorepos that have multiple Python projects (often `services/*`
103
+ or `apps/*` layout):
104
+
105
+ ```bash
106
+ for project in services/*/; do
107
+ if [ -f "$project/pyproject.toml" ] || [ -f "$project/requirements.txt" ]; then
108
+ python3 plugins/security/penetration-tester/skills/auditing-python-dependencies/scripts/audit_python.py \
109
+ "$project" --format json --output "audit-$(basename $project).json"
110
+ fi
111
+ done
112
+ ```
113
+
114
+ The skill scans one project at a time by design — keeps the
115
+ per-project blast radius clear and lets CI parallelize.
116
+
117
+ ## GitHub Dependabot ecosystem mapping
118
+
119
+ Dependabot's "pip" ecosystem auto-PRs requirements.txt and
120
+ pyproject.toml bumps. It does NOT audit poetry.lock — for that,
121
+ use the "poetry" ecosystem entry:
122
+
123
+ ```yaml
124
+ # .github/dependabot.yml
125
+ version: 2
126
+ updates:
127
+ - package-ecosystem: pip
128
+ directory: /
129
+ schedule:
130
+ interval: weekly
131
+ - package-ecosystem: pip # poetry is reported as "pip" too in newer versions
132
+ directory: /services/api
133
+ schedule:
134
+ interval: weekly
135
+ ```
136
+
137
+ For uv, Dependabot support was added in 2025; check Dependabot's
138
+ docs for the current ecosystem name.
139
+
140
+ ## SOC2 evidence retention
141
+
142
+ For Trust Service Category CC7 (System Operations):
143
+
144
+ ```bash
145
+ mkdir -p evidence/CC7/
146
+ python3 ./scripts/audit_python.py . --include-dev \
147
+ --format json \
148
+ --output evidence/CC7/py-audit-$(date +%Y%m%d).json
149
+ ```
150
+
151
+ Retain at minimum one audit per quarter, plus the audit run that
152
+ preceded each release. Auditors look for evidence that:
153
+
154
+ 1. The audit ran on a defined cadence.
155
+ 2. Findings were triaged within the window your vuln-response
156
+ policy commits to (typically 7 days for HIGH, 30 days for
157
+ MEDIUM, 90 days for LOW).
158
+ 3. Exceptions are documented with re-evaluation dates.
159
+
160
+ ## Common false positives
161
+
162
+ Three patterns produce findings that aren't actionable:
163
+
164
+ 1. **Dev-only test fixtures pinning old versions** — e.g. tests
165
+ that intentionally exercise an old `requests` to verify backward
166
+ compat. Mark the source file as dev-only via `--include-dev`
167
+ filtering or split test requirements into a separate file.
168
+
169
+ 2. **Yanked releases on PyPI** — a release pulled by the maintainer
170
+ may still have an open advisory while no longer installable.
171
+ pip-audit handles yanked correctly in recent versions; older
172
+ versions may still flag.
173
+
174
+ 3. **CVEs that don't apply in your usage** — a vulnerability in the
175
+ FTP transport of `urllib3` is irrelevant if you only use HTTPS.
176
+ Don't blanket-suppress; document the per-finding rationale in
177
+ your security register.
178
+
179
+ ## When to vendor + patch
180
+
181
+ If a package has an unpatched CRITICAL/HIGH CVE and replacement
182
+ isn't feasible:
183
+
184
+ 1. Fork the upstream source into a private vendored copy in your
185
+ repo (e.g. `vendor/<package>/`).
186
+ 2. Apply the upstream patch (cherry-pick from the maintainer's PR
187
+ if one exists).
188
+ 3. Install from your vendored path: `pip install ./vendor/<package>`.
189
+ 4. Set a calendar reminder to re-evaluate quarterly; switch back to
190
+ upstream once a published fix is available.
191
+
192
+ Vendor + patch is a maintenance burden; track it in your security
193
+ register the same way you'd track any other exception.
@@ -0,0 +1,122 @@
1
+ # THEORY — Why Python Dependency Audits Matter
2
+
3
+ ## The Python install model
4
+
5
+ `pip install <package>` does three things in sequence:
6
+
7
+ 1. Resolves a transitive dependency graph from PyPI metadata.
8
+ 2. Downloads each resolved package as a wheel (`.whl`) or sdist
9
+ (`.tar.gz`).
10
+ 3. For sdists, executes the package's `setup.py` (which is arbitrary
11
+ Python) at install time. For wheels, runs any post-install hooks.
12
+
13
+ The `setup.py` execution step is the load-bearing detail. A
14
+ compromised PyPI package can read environment variables, write to
15
+ the user's home directory, exfiltrate data, and pivot to other
16
+ systems — all on `pip install`, before the package is ever imported.
17
+
18
+ ## PyPI supply-chain incidents that drove audit adoption
19
+
20
+ | Year | Event | Mechanism |
21
+ |---|---|---|
22
+ | 2017 | Typosquat wave (PyTorch, RoboGirl, ...) | Names one character off from popular packages. Some shipped credential-stealing setup.py. |
23
+ | 2022 | `ctx` | Maintainer account compromise. Replaced legitimate package with a credential exfiltrator. ~22k weekly downloads. |
24
+ | 2022 | `request-toolbelt` (typosquat of `requests-toolbelt`) | Same week, same actor, similar tactics. |
25
+ | 2023 | `tornado` typosquats | Multiple variants targeting Tornado web framework users. |
26
+ | 2024 | `ultralytics` 8.3.42 / 8.3.43 | YOLO ML library hijacked through GitHub Actions cache poisoning. Crypto miner in the wheel. |
27
+ | 2025 | `requests-darwin-lite` | Targeted macOS users; trojanized binary inside an otherwise innocent wheel. |
28
+
29
+ Each case relied on either (a) someone installing the malicious
30
+ package by name without checking, or (b) a transitive dep updating
31
+ to a malicious version that an existing project pulled in
32
+ automatically.
33
+
34
+ ## OSV, PyPA, and the audit data sources
35
+
36
+ `pip-audit` queries the Open Source Vulnerabilities (OSV) database
37
+ (osv.dev), maintained by Google as an aggregator of ecosystem-specific
38
+ advisory feeds. For Python, OSV ingests the PyPA Advisory Database
39
+ (github.com/pypa/advisory-database), which is the upstream of record
40
+ for Python-specific vulnerabilities.
41
+
42
+ Why OSV and not NVD?
43
+
44
+ - **OSV is ecosystem-aware.** A finding tagged "PyPI" affects exactly
45
+ the packages installed via pip. NVD's CVE list is package-agnostic
46
+ and requires manual mapping to ecosystem.
47
+ - **PyPA records often pre-date CVE assignment.** A vulnerability
48
+ in a Python package can be published in PyPA's database before
49
+ NIST assigns a CVE number. Tools that only query NVD miss the
50
+ early window.
51
+ - **Severity bands are normalized.** OSV maps CVSS scores to a
52
+ consistent severity vocabulary across ecosystems.
53
+
54
+ The skill consumes pip-audit's output (which already does the OSV
55
+ query) rather than querying OSV directly. Reasons: pip-audit's
56
+ parser is mature, handles edge cases (yanked releases, retracted
57
+ advisories), and integrates with PEP 621 / poetry / pipenv project
58
+ layouts natively.
59
+
60
+ ## Python-specific install-time risks
61
+
62
+ Two install-time behaviors make Python uniquely vulnerable:
63
+
64
+ ### setup.py execution
65
+
66
+ Sdists run `setup.py` to build. `setup.py` is arbitrary Python.
67
+ A malicious sdist can do anything Python can do at install time,
68
+ including:
69
+
70
+ - Read `~/.aws/credentials`, `~/.ssh/id_*`, `.env` files.
71
+ - Open a reverse shell via socket.
72
+ - Modify other installed packages in site-packages.
73
+
74
+ `pip install <package> --only-binary :all:` refuses sdists,
75
+ forcing wheels — but most published packages still publish sdists
76
+ alongside wheels.
77
+
78
+ ### Eager dependency resolution
79
+
80
+ Pre-pip 20.3, pip's resolver was first-match-wins, leading to
81
+ inconsistent dependency trees across environments. Pip's modern
82
+ resolver (PEP 517 + 2020-resolver) is consistent but slower; some
83
+ CI pipelines disable it for speed, reintroducing the inconsistency.
84
+
85
+ Inconsistent resolution = the audit on your laptop may show
86
+ different packages than the audit in CI. Locking via `pip-tools`,
87
+ `poetry`, or `uv` is the only durable fix.
88
+
89
+ ## pip-audit vs Safety vs Snyk
90
+
91
+ Three audit tools compete in the Python space.
92
+
93
+ | Tool | Backed by | Strengths | Weaknesses |
94
+ |---|---|---|---|
95
+ | pip-audit | PyPA | Official; consumes the PyPA advisory DB directly; supports requirements/poetry/pipenv | Severity normalization is sometimes coarser than CVSS |
96
+ | Safety | safetycli.com | Commercial advisory DB with curated severity; web UI | Free tier rate-limited; relies on a third-party DB |
97
+ | Snyk | Snyk Inc. | Commercial advisory DB; rich vulnerability metadata; web UI | Auth required; commercial pricing for production use |
98
+
99
+ The skill standardizes on pip-audit because it's PyPA-blessed,
100
+ zero-cost, and ships with the data quality SOC2 auditors expect to
101
+ see in evidence packages.
102
+
103
+ ## Why severity normalization matters
104
+
105
+ OSV emits severity as free-text strings or CVSS vectors. NVD emits
106
+ CVSS scores. GitHub uses 4 levels. PyPA uses ecosystem-specific
107
+ labels. The penetration-tester `Severity` enum (`lib/finding.py`)
108
+ is the canonical mapping target so downstream consumers (executive
109
+ reports, SOC2 evidence collection, dashboards) see one vocabulary
110
+ across every tool.
111
+
112
+ ## When "no fix" is itself a finding
113
+
114
+ A vulnerability with no `fix_versions` is not less severe — it's
115
+ MORE remediation-bound. You can't `pip install -U` your way out of
116
+ it. The skill bumps such findings to at-least HIGH severity to make
117
+ this visible in the report. Operator options are limited:
118
+
119
+ 1. Pin to an older safe version (if one exists pre-vulnerability).
120
+ 2. Vendor the package locally and patch it in-tree.
121
+ 3. Replace the package with an alternative.
122
+ 4. Accept the risk with an explicit security-register exception.