Chaintrap · PyPI supply chain
Registry metadata, verified artifact, OSV for this release, requires_dist dependency OSV pass, line-level rules (pypi_malware_rules), optional pip-audit/Bandit — same report shell as npm-mal-scan.
PyPI greenfield scan rated this release BLOCK (heuristic score 10.0 / 10). OSV reported 0 advisory ID(s); static analysis emitted 20 pattern hit(s).
Scanners prioritize signal over certainty: expect both false positives and blind spots. Combine OSV data with static findings and your own policy — this report does not replace manual review.
Heuristic score combines static rules, OSV hits for this exact version, and optional pip-audit / Bandit output. It is not a malware conviction.
Raw sum before 10.0 cap: 18.45 · Capped total: 10.0
Findings by severity medium: 18, low: 1, info: 1
| Static pattern rules (line-level) | 18.45 | 20 match(es); weights sum to this bucket before global cap. |
| OSV advisories (exact name@version) | 0 record(s); capped at 4.0 points. | |
| pip-audit (optional) | 0 vuln row(s); capped at 3.0; enable PYPI_PIP_AUDIT. | |
| Bandit high/critical (optional) | 0 finding(s); capped at 3.0; enable PYPI_BANDIT. |
Ruleset: 2026-04-17
Use Source Code / Homepage for manual review of the upstream repo. This scan does not clone those URLs.
Author Tirth
Trove classifiers
Persistent incremental knowledge graph for token-efficient, context-aware code reviews with Claude Code
Requires-Dist (from JSON API)
Line-level rules ran over text-like files under the extracted artifact (max 400000 bytes per file).
Files by suffix (top 24):
.py | 50 |
.yaml | 6 |
.txt | 1 |
Chaintrap pairs static behavior signals above with OSV data for this exact version — cross-check CVEs and malware listings with install scripts, execution paths, and scanner findings.
Source: osv.dev — queried at scan time.
0 advisory ID(s) returned by OSV query.
No known vulnerabilities reported for this exact version.
Declared requires_dist strings from package metadata. Each dependency is resolved to the highest PyPI version matching the version specifier, then checked against OSV for that exact name@version. Does not affect the headline verdict score.
Skipped 6 duplicate name(s).
| Declared requirement | Resolved | OSV | Status | Advisory IDs |
|---|---|---|---|---|
fastmcp<3,>=2.14.0 | fastmcp@2.14.7 | 3 | Vulnerabilities reported | GHSA-m8x7-r2rg-vh5g, GHSA-rww4-4w9c-7733, GHSA-vv7q-7jx5-f767 |
mcp<2,>=1.0.0 | mcp@1.27.0 | 0 | No OSV hits | — |
networkx<4,>=3.2 | networkx@3.6.1 | 0 | No OSV hits | — |
tree-sitter-language-pack<1,>=0.3.0 | tree-sitter-language-pack@0.13.0 | 0 | No OSV hits | — |
tree-sitter<1,>=0.23.0 | tree-sitter@0.25.2 | 0 | No OSV hits | — |
watchdog<6,>=4.0.0 | watchdog@5.0.3 | 0 | No OSV hits | — |
igraph>=0.11.0; extra == "all" | igraph@1.0.0Marker: extra == "all" | 0 | No OSV hits | — |
matplotlib>=3.7.0; extra == "all" | matplotlib@3.10.8Marker: extra == "all" | 0 | No OSV hits | — |
numpy<3,>=1.26; extra == "all" | numpy@2.4.4Marker: extra == "all" | 0 | No OSV hits | — |
ollama>=0.1.0; extra == "all" | ollama@0.6.1Marker: extra == "all" | 0 | No OSV hits | — |
pyyaml>=6.0; extra == "all" | pyyaml@6.0.3Marker: extra == "all" | 0 | No OSV hits | — |
sentence-transformers<4,>=3.0.0; extra == "all" | sentence-transformers@3.4.1Marker: extra == "all" | 0 | No OSV hits | — |
pytest-asyncio<1,>=0.23; extra == "dev" | pytest-asyncio@0.26.0Marker: extra == "dev" | 0 | No OSV hits | — |
pytest-cov<8,>=4.0; extra == "dev" | pytest-cov@7.1.0Marker: extra == "dev" | 0 | No OSV hits | — |
pytest<9,>=8.0; extra == "dev" | pytest@8.4.2Marker: extra == "dev" | 1 | Vulnerabilities reported | GHSA-6w46-j5rx-g56g |
ruff<1,>=0.3.0; extra == "dev" | ruff@0.15.11Marker: extra == "dev" | 0 | No OSV hits | — |
tomli>=2.0; python_version < "3.11" and extra == "dev" | tomli@2.4.1Marker: python_version < "3.11" and extra == "dev" | 0 | No OSV hits | — |
google-generativeai<1,>=0.8.0; extra == "google-embeddings" | google-generativeai@0.8.6Marker: extra == "google-embeddings" | 0 | No OSV hits | — |
Detection library pypi_malware_rules (2026-04-17) — 75 line-level rules over .py and other text artifacts. Matches are triage signals, not proof of malice.
Matches by category process (19), network (1) · Total hits 20
Category process
Runs external commands; scope depends on arguments and caller.
Analyst note Very common in legitimate packages — use for triage, not automatic verdicts.
code_review_graph/changes.py:49
result = subprocess.run(
Category network
Fetches remote content via stdlib urllib.
Analyst note Correlate with decode/exec chains.
code_review_graph/embeddings.py:206
with urllib.request.urlopen(req, timeout=60, context=_ssl_ctx) as resp: # nosec B310
Category process
Runs external commands; scope depends on arguments and caller.
Analyst note Very common in legitimate packages — use for triage, not automatic verdicts.
code_review_graph/incremental.py:260
result = subprocess.run(
Category process
Runs external commands; scope depends on arguments and caller.
Analyst note Very common in legitimate packages — use for triage, not automatic verdicts.
code_review_graph/incremental.py:270
result = subprocess.run(
Category process
Runs external commands; scope depends on arguments and caller.
Analyst note Very common in legitimate packages — use for triage, not automatic verdicts.
code_review_graph/incremental.py:290
result = subprocess.run(
Category process
Runs external commands; scope depends on arguments and caller.
Analyst note Very common in legitimate packages — use for triage, not automatic verdicts.
code_review_graph/incremental.py:299
result = subprocess.run(
Category process
Runs external commands; scope depends on arguments and caller.
Analyst note Very common in legitimate packages — use for triage, not automatic verdicts.
code_review_graph/incremental.py:315
result = subprocess.run(
Category process
Runs external commands; scope depends on arguments and caller.
Analyst note Very common in legitimate packages — use for triage, not automatic verdicts.
code_review_graph/incremental.py:356
result = subprocess.run(
Category process
Environment fingerprinting (OS, hostname).
Analyst note Often benign; suspicious when paired with exfiltration or downloaders.
code_review_graph/skills.py:25
if platform.system() == "Darwin":
Category process
Runs external commands; scope depends on arguments and caller.
Analyst note Very common in legitimate packages — use for triage, not automatic verdicts.
code_review_graph/eval/runner.py:69
subprocess.run(
Category process
Runs external commands; scope depends on arguments and caller.
Analyst note Very common in legitimate packages — use for triage, not automatic verdicts.
code_review_graph/eval/runner.py:75
subprocess.run(
Category process
Runs external commands; scope depends on arguments and caller.
Analyst note Very common in legitimate packages — use for triage, not automatic verdicts.
code_review_graph/eval/runner.py:82
subprocess.run(
Category process
Runs external commands; scope depends on arguments and caller.
Analyst note Very common in legitimate packages — use for triage, not automatic verdicts.
code_review_graph/eval/benchmarks/impact_accuracy.py:14
result = subprocess.run(
Category process
Runs external commands; scope depends on arguments and caller.
Analyst note Very common in legitimate packages — use for triage, not automatic verdicts.
code_review_graph/eval/benchmarks/impact_accuracy.py:21
result = subprocess.run(
Category process
Runs external commands; scope depends on arguments and caller.
Analyst note Very common in legitimate packages — use for triage, not automatic verdicts.
code_review_graph/eval/benchmarks/token_efficiency.py:20
result = subprocess.run(
Category process
Runs external commands; scope depends on arguments and caller.
Analyst note Very common in legitimate packages — use for triage, not automatic verdicts.
code_review_graph/eval/benchmarks/token_efficiency.py:28
result = subprocess.run(
Category process
Runs external commands; scope depends on arguments and caller.
Analyst note Very common in legitimate packages — use for triage, not automatic verdicts.
code_review_graph/eval/benchmarks/token_efficiency.py:52
result = subprocess.run(
Category process
Runs external commands; scope depends on arguments and caller.
Analyst note Very common in legitimate packages — use for triage, not automatic verdicts.
code_review_graph/eval/benchmarks/token_efficiency.py:59
result = subprocess.run(
Category process
Runs external commands; scope depends on arguments and caller.
Analyst note Very common in legitimate packages — use for triage, not automatic verdicts.
code_review_graph/tools/context.py:19
result = subprocess.run(
Category process
Runs external commands; scope depends on arguments and caller.
Analyst note Very common in legitimate packages — use for triage, not automatic verdicts.
code_review_graph/tools/context.py:27
result2 = subprocess.run(
MAL-* OSV IDs appear, review OpenSSF malicious-packages context and isolate affected hosts.