Malicious Package Watch — npm/PyPI Supply Chain Alerts avatar

Malicious Package Watch — npm/PyPI Supply Chain Alerts

Pricing

$5.50 / 1,000 new advisories

Go to Apify Store
Malicious Package Watch — npm/PyPI Supply Chain Alerts

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

0xGollum

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

7 days ago

Last modified

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

  1. 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.

  2. 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.

  3. 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. flash is not a typo of flask, block is not a typo of black, task is not a typo of dask — those are ordinary words and somebody's real package. A scanner that reports them is a scanner people mute.

Two ways to run it

modeBehaviourUse 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.
auditOne-shot. No baseline — reports every current advisory and name-confusion hit right now.Scan a repo on demand, or gate a CI build.

Input

FieldNotes
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.
packagesOptional. [{ "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.
modewatch (default) or audit.
checksAny of advisories, typosquat (default: both).
request_timeout_secsOSV.dev call timeout. Default 20.
max_resultsCap 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 holds lodash 4.17.21 at the root and 3.10.1 nested under an old dependency yields findings for both, each labelled with its version — the nested old copy is usually the one that matters. One row per vulnerability: OSV often carries the same flaw as two records (a PYSEC-… and its GHSA-… twin); they're merged, the richest one supplies vuln_id/summary, the rest go to aliases, and source_records lists 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.
  • audit mode for on-demand repo scans (vs the existing scheduled watch).
  • Exact-version advisory matching from pinned manifests → fewer false alarms.
  • Rows now carry type; severity normalized to a fixed scale; advisory rows gained aliases / 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 watch mode, the first check per package is a silent baseline; alerts start from the second run. Use audit mode if you want everything now.
  • The typosquat check compares against a curated list of the most-abused popular packages for npm and PyPI only, 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.