Supply-chain Threat Database
arcis sca ships with 100 curated supply-chain advisories embedded in the binary. Browse what we cover, see how new entries get added, and understand how the OSV layer extends it.
Transparent by design. Every entry below is auditable in packages/arcis-rust/crates/arcis-data/data/threat-db.json with a source advisory link. No black-box detections, no proprietary feed.
Coverage summary
| Dimension | Count |
|---|---|
| Total entries | 100 |
| npm ecosystem | 59 |
| PyPI ecosystem | 41 |
| Critical severity | 47 |
| High severity | 46 |
| Medium severity | 7 |
| Last shipped refresh | 2026-05-07 |
Attack classes covered
- Maintainer-credential compromise. Stolen npm/PyPI account tokens push trojanized versions to an otherwise-legit package. (event-stream, ua-parser-js, rc, faker, peacenotwar.)
- Trojanized dependency. A legit package adds a malicious sub-dependency via a release update. (axios 2026 via
plain-crypto-js, event-stream viaflatmap-stream.) - Typosquat. Package name one letter off from a popular target, ships exfiltration logic on install. (colourama vs colorama, crossenv vs cross-env, babelcli vs babel-cli, torchtriton vs torch-triton.)
- Persistent backdoors. Install scripts drop
.pthfiles in Pythonsite-packagesor runpostinstallhooks that survive package uninstall. (litellm 2026, crossenv.) - Wallet hijack. Targets crypto wallet apps via Solana / Ethereum sub-libraries. (@solana/web3.js, several typosquats.)
- Protestware. Maintainer self-sabotage that ships empty or destructive code as a political statement. (faker, peacenotwar / node-ipc.)
- ReDoS in dependency trees. Regex DoS introduced through a transitive update. (Several entries.)
- HTTP request-smuggling and parser DoS. Crafted input triggers worst-case parsing in HTTP libs. (Several npm entries.)
Notable advisories
A representative slice. Run arcis sca --list-threats to dump the full list with severities, malicious versions, and source URLs.
| Package | Ecosystem | Class | Reference |
|---|---|---|---|
axios | npm | Trojanized plain-crypto-js dep ships a RAT via postinstall | 2026 advisory |
litellm | PyPI | Credential harvester + persistent .pth backdoor that survives pip uninstall | 2026 advisory |
colourama | PyPI | Typosquat of colorama, exfiltrates wallet keys | CVE-2018-1000877 |
event-stream | npm | Trojanized flatmap-stream dep targeting bitcoin wallets | CVE-2018-1000620 |
flatmap-stream | npm | The payload half of the event-stream incident, indexed separately so re-imports are caught | CVE-2018-1000620 |
ua-parser-js | npm | Maintainer credentials stolen; trojanized versions deployed cryptominers | CVE-2021-3962 |
rc | npm | Same attack chain as ua-parser-js | CVE-2021-43138 |
peacenotwar | npm | Protestware sabotage propagating through node-ipc | CVE-2022-23812 |
@solana/web3.js | npm | Wallet-connect hijack via maintainer compromise | 2024 advisory |
faker | npm | Maintainer self-sabotage shipped empty / protestware versions | CVE-2022-42003 |
torch / torchtriton | PyPI | PyPI typosquat shipping a credential exfiltrator that survived the index for hours | CVE-2024-31580 / CVE-2022-45907 |
pytorch-lightning | PyPI | Trojanized release with credential exfiltration | 2024 advisory |
crossenv | npm | Typosquat of cross-env, postinstall exfiltrates env vars | 2017 advisory |
Entry schema
Every entry in threat-db.json follows this shape:
{
"ecosystem": "npm", // "npm" | "pypi"
"name": "axios",
"malicious_versions": ["1.14.1", "0.30.4"],
"vulnerable_ranges": [],
"attack_vector": "Trojanized dependency plain-crypto-js@4.2.1 deploys a remote access trojan...",
"severity": "critical", // "critical" | "high" | "medium"
"cve": "no-cve-assigned",
"disclosure_date": "2026-03-12",
"source": "npm Security Advisory",
"references": ["https://github.com/axios/axios/security/advisories/..."],
"trojanized_deps": ["plain-crypto-js@4.2.1"],
"persistence_artifacts": [], // e.g. .pth files for Python
"remediation": "pin axios to 1.13.x or 0.30.3; audit lockfile for plain-crypto-js"
}
How detection works
For each lockfile or manifest arcis sca walks the dependency tree (including transitive deps) and looks up every (ecosystem, name, version) tuple in the embedded DB. A match against either malicious_versions or a vulnerable_ranges entry triggers a finding with severity, attack class, remediation, and the full path-to-root through the dep tree.
For Python, --system also walks site-packages for .pth files matching known persistence artifacts (an entry in persistence_artifacts).
OSV layer
The embedded DB is curated and stays small (advisories worth a hand-written entry). For breadth, pass --osv and the scanner also queries osv.dev for each package found in your lockfiles and merges its findings on top of the embedded results.
arcis sca . # embedded DB only (offline)
arcis sca . --osv # + live OSV.dev advisories
arcis sca . --no-cache # bypass the 24h OSV cache
Responses are cached at ~/.arcis/osv-cache.json with a 24h TTL. --osv is the only flag in the CLI that touches the network; everything else runs fully offline.
Contributing a new entry
- Open the source advisory (GHSA, PyPI advisory, OSV record, or a credible blog post that names versions).
- Add an entry to
threat-db.jsonfollowing the schema above. Severity, malicious versions, attack vector, and at least one reference URL are required. - Run
cargo test --package arcis-engineto validate the schema. - Open a PR to
nwl. CI verifies the JSON shape and runs the SCA test suite against the fixtures.
Curation policy. The embedded DB is intentionally small. Each entry has to be worth a hand-written advisory record: versions, attack class, source. Pure ReDoS-only or low-severity advisories get pushed to the OSV layer instead.
False positives and dropping a finding
If arcis sca flags a package you have already addressed (pinned to a safe version inside a malicious range, vendored the patched source, etc.) you can suppress it via a baseline file:
arcis sca . --baseline ./.arcis-sca-baseline.json
The baseline schema mirrors the audit baseline. Findings already in the baseline are reported as baseline and do not affect the exit code.