Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Audit a Python project's installed dependencies for known CVEs by wrapping pip-audit (PyPA's official vulnerability auditor) and emitting findings in the canonical penetration-tester schema. Detects vulnerable direct AND transitive packages, normalizes pip-audit's severity output via OSV severity bands, falls back to pip list --outdated when pip-audit isn't installed, and supports requirements.txt, pyproject.toml (PEP 621), Pipfile.lock, and poetry.lock as input sources. Use when: pre-merge gate
.claude/skills/jeremylongshore-auditing-python-dependencies/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-18 | ✗→✓ | ▲ Improved | 77% | 0% |
| case-12 | ✗→✓ | ▲ Improved | 8% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 92% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 12% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 18% | 0% |
PyPI hosts north of 500,000 packages, with several thousand new releases every day. The package-install model is identical to npm in the relevant ways: a pip install resolves a transitive graph, runs each package's setup.py (which executes arbitrary Python at install time), and writes the result to your site-packages. The CVE attack surface is therefore the same shape: known vulnerabilities, maintainer-account takeovers, typosquats, and protestware.
The PyPA-blessed auditor is pip-audit. It queries the Open Source Vulnerabilities (OSV) database (which mirrors PyPA's advisory feed plus aggregated CVE / GHSA records) and reports per-package vulnerable versions. pip-audit integrates with requirements.txt, pyproject.toml, Pipfile.lock, and poetry.lock, so most Python project layouts are first-class.
This skill wraps pip-audit, normalizes its severity vocabulary to the shared Severity enum, and emits Findings in the canonical penetration-tester schema. If pip-audit isn't installed on the host, the skill falls back to pip list --outdated and emits INFO-level findings recommending the operator install pip-audit for accurate vulnerability detection.
| Finding | Severity | Threshold | Affected control | |---|---|---|---| | Critical CVE in installed package | CRITICAL | OSV severity band corresponds to CVSS ≥ 9.0 | CWE-1104 | | High CVE in installed package | HIGH | OSV severity band corresponds to CVSS 7.0–8.9 | CWE-1104 | | Medium CVE in installed package | MEDIUM | OSV severity band corresponds to CVSS 4.0–6.9 | CWE-1104 | | Low CVE in installed package | LOW | OSV severity band corresponds to CVSS 0.1–3.9 | CWE-1104 | | Vulnerable package with no patch | HIGH | finding has no fix_versions and severity ≥ medium | CWE-1395 | | Outdated package (no CVE) | INFO | pip list --outdated reports a newer version | (operational) | | pip-audit not installed | INFO | binary not on PATH; scanner fell back to pip list | (operational) | | Audit DB unreachable | INFO | pip-audit network error reaching OSV | (operational) |
OSV is the upstream of record. pip-audit also consults the PyPA advisory database for Python-specific records that may not yet have a CVE assigned.
pip-audit installed (pip install pip-audit); skill falls backto pip list --outdated if absent
requirements.txt,pyproject.toml, Pipfile.lock, poetry.lock
api.osv.dev) and PyPI (pypi.org)Locate the project directory. The scanner auto-detects requirement files in order of preference:
poetry.lock (most precise — exact resolved tree)Pipfile.lockrequirements.txt (and requirements-*.txt siblings)pyproject.toml (PEP 621 dependencies)pip list (last resort)bashpython3 ./scripts/audit_python.py /path/to/python-project
Options:
Usage: audit_python.py PATH [OPTIONS]
Options:
--output FILE Write findings to FILE (default: stdout)
--format FMT json | jsonl | markdown (default: markdown)
--min-severity SEV (default: info)
--requirement FILE Override auto-detection; specify a particular
requirements file (repeatable)
--include-dev Include development dependencies (default: prod
only when project layout allows the distinction)
--strict Treat pip-audit warnings as errorsCRITICAL / HIGH = block release.
MEDIUM / LOW = track but don't block; many Python advisories report edge-case theoretical issues that don't apply to your usage.
INFO = log only; e.g. "outdated but no known CVE" is information for your release cadence, not a security action.
For a vulnerable package with fix_versions:
diff
+ requests==2.31.0
pip install -r requirements.txt --upgrade (orpoetry lock --no-update && poetry update <pkg>).
changes you didn't expect.
For a vulnerable transitive dep (one you didn't declare directly):
pip show <vulnerable-package> lists the parentsin its "Required-by" line.
versions <parent> lists available versions.
dep above the fix version, pin the transitive dep yourself in your requirements file. pip will use the more specific pin.
For a vulnerable package with NO fix available:
replace the package or vendor + patch locally.
re-evaluation date.
bashpython3 ./scripts/audit_python.py . --min-severity high --format json --output audit.json jq -e '. == []' audit.json || { echo "High/critical Python CVE — fix before merge"; exit 1; }
yaml- name: pip-audit run: pip install pip-audit - name: Run audit run: | python3 plugins/security/penetration-tester/skills/auditing-python-dependencies/scripts/audit_python.py \ . --min-severity high --format markdown --output py-audit.md
bashmkdir -p evidence/CC7/ python3 ./scripts/audit_python.py . --include-dev --format json \ --output evidence/CC7/py-audit-$(date +%Y%m%d).json
--include-dev for SOC2: include dev/test deps so auditors see the full surface, not just production.
JSON / JSONL / Markdown per lib/report.py. Exit codes: 0 clean, 1 high/critical, 2 error.
Each Finding includes:
id — synthesized as pypi-audit::<cve-id> (or pypi-audit::<ghsa> / pypi-audit::<pypa-id> when no CVE)severity — CRITICAL / HIGH / MEDIUM / LOW / INFOcategory — dependency-vulnerabilitysummary — short CVE / GHSA titleevidence — affected package, affected version, fix versions, advisory IDreferences — OSV URL, CVE URL, PyPA advisory URLpip list --outdated,emits an INFO Finding flagging the degraded scan, and proceeds.
project structure recognized" and exits 2.
outage and exits 0 (no actionable security finding).
the raw output truncated to 500 chars and exits 2.
references/THEORY.md — PyPI supply-chain history, OSV vs NVD vsPyPA advisory scopes, why ecosystem-specific severity matters, Python-specific install-time risks (setup.py execution, eager dependency resolution), pip-audit vs Safety vs Snyk trade-offs
references/PLAYBOOK.md — Per-toolchain remediation patterns(pip + requirements.txt, poetry, pipenv, uv, conda), monorepo / workspace scanning, override-equivalent patterns in Python ecosystem, GitHub Dependabot ecosystem mapping, SOC2 evidence retention
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-18 | fail→pass | 6,859 | 1,835 | -73% | 1 | 1 | 0% | 1,358 | 2,398 | +77% | 0 | 0 | — |
case-12 | fail→pass | 14,069 | 4,025 | -71% | 1 | 1 | 0% | 2,517 | 2,715 | +8% | 0 | 0 | — |
case-01 | fail→fail | 27,558 | 7,505 | -73% | 1 | 1 | 0% | 6,056 | 2,293 | -62% | 0 | 0 | — |
case-02 | fail→fail | 22,757 | 24,086 | +6% | 1 | 1 | 0% | 2,506 | 4,813 | +92% | 0 | 0 | — |
case-03 | fail→fail | 19,339 | 22,699 | +17% | 1 | 1 | 0% | 2,643 | 5,563 | +110% | 0 | 0 | — |
case-04 | pass→pass | 12,708 | 2,896 | -77% | 1 | 1 | 0% | 2,168 | 2,448 | +13% | 0 | 0 | — |
case-05 | fail→pass | 8,743 | 5,986 | -32% | 1 | 1 | 0% | 1,582 | 3,034 | +92% | 0 | 0 | — |
case-06 | pass→pass | 5,305 | 2,166 | -59% | 1 | 1 | 0% | 952 | 2,454 | +158% | 0 | 0 | — |
case-07 | pass→pass | 13,655 | 9,740 | -29% | 1 | 1 | 0% | 2,408 | 3,765 | +56% | 0 | 0 | — |
case-08 | pass→pass | 14,239 | 10,895 | -23% | 1 | 1 | 0% | 2,346 | 3,978 | +70% | 0 | 0 | — |
case-09 | fail→pass | 15,665 | 5,628 | -64% | 1 | 1 | 0% | 2,771 | 3,100 | +12% | 0 | 0 | — |
case-10 | fail→pass | 32,107 | 8,752 | -73% | 1 | 1 | 0% | 3,023 | 3,554 | +18% | 0 | 0 | — |
case-11 | fail→pass | 11,777 | 3,061 | -74% | 1 | 1 | 0% | 1,881 | 2,418 | +29% | 0 | 0 | — |
case-13 | fail→pass | 11,288 | 2,260 | -80% | 1 | 1 | 0% | 1,957 | 2,412 | +23% | 0 | 0 | — |
case-14 | fail→pass | 13,766 | 4,335 | -69% | 1 | 1 | 0% | 2,471 | 2,747 | +11% | 0 | 0 | — |
case-15 | fail→pass | 8,659 | 2,919 | -66% | 1 | 1 | 0% | 1,378 | 2,506 | +82% | 0 | 0 | — |
case-16 | fail→pass | 7,957 | 2,922 | -63% | 1 | 1 | 0% | 1,258 | 2,307 | +83% | 0 | 0 | — |
case-17 | pass→pass | 3,854 | 2,024 | -47% | 1 | 1 | 0% | 619 | 2,395 | +287% | 0 | 0 | — |
case-19 | pass→pass | 4,433 | 2,658 | -40% | 1 | 1 | 0% | 835 | 2,566 | +207% | 0 | 0 | — |
case-20 | fail→pass | 19,017 | 7,666 | -60% | 1 | 1 | 0% | 4,043 | 3,378 | -16% | 0 | 0 | — |
case-21 | pass→pass | 12,716 | 7,108 | -44% | 1 | 1 | 0% | 2,355 | 3,393 | +44% | 0 | 0 | — |
case-22 | fail→pass | 14,329 | 12,797 | -11% | 1 | 1 | 0% | 2,871 | 4,454 | +55% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 21 counted toward the lift figure. The other 1 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +55 percentage points is the difference between those two pass rates over the 21 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.