Malicious Package Watch — npm/PyPI Supply Chain Alerts
Pricing
$5.50 / 1,000 new advisories
Malicious Package Watch — npm/PyPI Supply Chain Alerts
Watch the open-source packages your codebase depends on and get alerted the moment a new security advisory (including typosquat/malicious package takedowns) is published for one - built on the free OSV.dev vulnerability database. Only new advisories are reported after the first baseline check.
Pricing
$5.50 / 1,000 new advisories
Rating
0.0
(0)
Developer
0xGollum
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
7 days ago
Last modified
Categories
Share
Malicious Package Watch — Dependency Scanner + Supply Chain Alerts
Paste a requirements.txt, package.json or lockfile. Get back its known
security advisories, plus any dependency name that looks like a typosquat of a
popular package. Run once to audit a repo, or on a schedule to be alerted only
on what's new.
What a row looks like
Two row types, told apart by type.
A known advisory (type: "advisory") — one row per vulnerability, however
many OSV records describe it:
{"type": "advisory","package": "PyPI/flask","version": "2.0.0","vuln_id": "GHSA-m2qf-hxjv-5gpq","aliases": ["CVE-2023-30861", "PYSEC-2023-62"],"source_records": ["GHSA-m2qf-hxjv-5gpq", "PYSEC-2023-62"],"summary": "Flask vulnerable to possible disclosure of permanent session cookie due to missing Vary: Cookie header","severity": "HIGH","malicious": false,"published": "2023-05-02T18:15:52Z","reference_url": "https://osv.dev/vulnerability/GHSA-m2qf-hxjv-5gpq","checked_at": "2026-09-09T12:46:30Z"}
A name that looks like a typosquat (type: "typosquat", offline check, no API):
{"type": "typosquat","package": "PyPI/reqeusts","source_file": "requirements.txt","looks_like": "PyPI/requests","confidence": "HIGH","edit_distance": 1,"summary": "'reqeusts' two characters swapped ('ue' -> 'eu') away from 'requests'. If you meant 'requests', this is a likely typosquat — verify the package name before installing.","severity": "CRITICAL","checked_at": "2026-09-09"}
What it does
-
Reads your dependencies. Paste one or more real dependency files (
manifest_files) and the package list — with pinned versions where present — is extracted for you. Or list packages by hand (packages), same as before. -
Checks each against OSV.dev — Google's free, no-auth vulnerability database, which aggregates GitHub Security Advisories, the PyPA and npm advisory feeds, RustSec, Go and more. That includes outright malicious-package takedowns (
malicious: true), not just ordinary CVEs. A pinned version only matches advisories that actually affect that version. -
Checks the names themselves for typosquats — offline, no API call. OSV can only warn about a malicious package after a takedown advisory exists; this catches the install-time trap first.
A typosquat is a misspelling, so a name is only flagged when the difference from a popular package is a real typing error: two characters swapped (
lodahs→lodash), a missing letter (expres→express), a doubled or inserted one (requessts→requests), an adjacent-key slip (nunpy→numpy), or a look-alike glyph (f1ask→flask). Added affixes and separator variants (lodash-js,react_dom) are reported at MEDIUM.Deliberately not flagged: names that merely resemble a popular package without being a plausible slip.
flashis not a typo offlask,blockis not a typo ofblack,taskis not a typo ofdask— those are ordinary words and somebody's real package. A scanner that reports them is a scanner people mute.
Two ways to run it
mode | Behaviour | Use it to |
|---|---|---|
watch (default) | Scheduled. The first run per package is a silent baseline; after that, only advisories/typosquats new since the last run are reported. | Get pinged when a fresh advisory drops for something you ship. |
audit | One-shot. No baseline — reports every current advisory and name-confusion hit right now. | Scan a repo on demand, or gate a CI build. |
Input
| Field | Notes |
|---|---|
manifest_files | [{ "filename": "requirements.txt", "content": "<paste file>" }, …]. Supported: requirements*.txt, Pipfile, Pipfile.lock, poetry.lock, pyproject.toml, package.json, package-lock.json, yarn.lock, pnpm-lock.yaml, go.mod, Gemfile, Gemfile.lock, composer.json, composer.lock, Cargo.toml, Cargo.lock. Paste the lockfile if you have one — it carries the versions actually installed. A manifest range (^18.2.0, ~4.17.0, "1.36" in Cargo) is queried by name only, never as a version: the floor of a range is not what you run, and asking OSV about it would report flaws your real version may already fix. |
packages | Optional. [{ "name": …, "ecosystem": …, "version": … (optional) }]. Ecosystem: npm, PyPI, Go, crates.io, Packagist, RubyGems, Maven, NuGet. version must be the exact installed version (4.17.21); a range (^4.17.0) is checked by name only, with a warning. |
mode | watch (default) or audit. |
checks | Any of advisories, typosquat (default: both). |
request_timeout_secs | OSV.dev call timeout. Default 20. |
max_results | Cap on rows, severity-first. Free preview is capped at 25. |
Provide manifest_files, packages, or both — at least one must yield a
package.
Output
type: "advisory"—package,version(the copy this finding is about),vuln_id,aliases,source_records,summary,severity(CRITICAL/HIGH/MEDIUM/LOW/UNKNOWN),malicious,published,reference_url,checked_at. Every locked copy is checked. A lockfile that holdslodash4.17.21 at the root and 3.10.1 nested under an old dependency yields findings for both, each labelled with itsversion— the nested old copy is usually the one that matters. One row per vulnerability: OSV often carries the same flaw as two records (aPYSEC-…and itsGHSA-…twin); they're merged, the richest one suppliesvuln_id/summary, the rest go toaliases, andsource_recordslists every OSV id the row stands for. You're billed once per vulnerability, not once per record.type: "typosquat"—package,source_file,looks_like,confidence(HIGH= a single typing error away,MEDIUM= an added affix or separator variant),edit_distance,summary(naming the exact slip),severity,checked_at.
Rows come back severity-first (worst on top), so a truncated max_results
keeps the findings that matter. In watch mode anything the cap holds back
stays unreported rather than lost — it comes through on the next run, and
the log tells you how many were held back.
New in 0.2
- Paste a dependency file instead of hand-listing packages (
manifest_files). - Proactive typosquat detection on the names themselves — offline, catches the trap before OSV has an advisory for it.
auditmode for on-demand repo scans (vs the existing scheduledwatch).- Exact-version advisory matching from pinned manifests → fewer false alarms.
- Rows now carry
type; severity normalized to a fixed scale; advisory rows gainedaliases/malicious/reference_url.
Everything from 0.1 — the packages input, scheduled diff-based alerting, the
free-tier preview cap, empty-run = no charge — is unchanged. See CHANGELOG.md.
0.2.3 hardened the above: typosquat detection now requires a genuine typing
error (no more flagging flash as a squat of flask), results held back by
max_results are no longer lost, repeat alerts for the same finding are fixed,
and Pipfile.lock actually parses.
0.2.5 fixed what a second review found: one row per vulnerability instead of one per OSV record (a real run went from 91 billed rows to 58), an OSV outage no longer makes every old advisory come back as "new", manifest ranges are no longer queried as installed versions, and a pasted lockfile always wins over its manifest.
0.2.6 closed the last gap a third review found: every locked copy of a
package is checked, including an old vulnerable one nested under a dependency
in your lockfile — that copy used to be silently skipped. Full detail in
CHANGELOG.md.
Known constraints
- Advisory coverage is whatever OSV.dev aggregates — broad, but not exhaustive for every ecosystem.
- In
watchmode, the first check per package is a silent baseline; alerts start from the second run. Useauditmode if you want everything now. - The typosquat check compares against a curated list of the most-abused
popular packages for
npmandPyPIonly, and only reports plausible typing errors. It is deliberately tuned for precision over recall — a novel squat of a less-common package can slip past it. It is a heuristic, not proof: always confirm before acting.