Known malicious

Check P1 · provenance family · severity CRITICAL · automatic · one of the 12 npm and PyPI package checks

Maps to OWASP LLM03 ATLAS AML.T0011.001 A package the OSV malicious-package database lists: the malicious package ATLAS names, installed by the person or agent who asked for it by name.

The question this check asks: has anyone published a report that this package is malware? Not a pattern match and not a guess: the OSV database carries malicious-package entries (MAL- ids) for npm and PyPI, and this check asks it about the package by name. It is the one P-check whose evidence is someone else's finished investigation.

Why it matters

A malicious package is installed by name, by a person or an agent that asked for it. The typosquat is a near-miss of the package that was meant (lodahs for lodash; OSV lists it as MAL-2025-25502). The hijacked release is the real name, published from a maintainer's stolen account: in September 2025 releases of chalk and debug were published that way, reported and pulled. And a campaign publishes its own: the 26 October 2026 testmetest campaign put npm packages that run code at install beside the repositories it hijacked — the testmetest page has the record. Once a report exists, installing the package anyway is the one mistake nobody needs to make.

How RepoGates scores it

The check asks OSV twice, in parallel: once for the package at the version the registry serves as latest — the one a bare npm install name or pip install name takes — and once for the package at any version. Only the package's name, its ecosystem and that version are sent; nothing about the caller.

A MAL- report that covers the latest version is pkg-malicious:<id>, CRITICAL and 45 points: the verdict is BLOCK, and every shipped profile blocks on it. A report on other versions is CRITICAL too, unless the record proves it is the hijacked-release shape and not a package that was malicious from the start. Proof means all of these at once: the report lists exact versions and no open range; the package was first published 90 days or more ago; its release history was read; every reported version is in that history; and releases the report does not name were published before the first one it does. Then the row is pkg-malicious-history, a note at 0 points, which names the reports and says to pin a version that is not listed. Anything short of proof stays CRITICAL. If OSV does not answer, the scan is partial, P1 is listed as not checked, and the verdict is never a pass on its account.

Beside this check, a package on RepoGates' own campaign list is BLOCK as a campaign listing whatever OSV says; the testmetest package names are listed that way.

False positives we know about

A report that is itself wrong. OSV's malicious-package entries are published reports, and a mistaken one is withdrawn upstream; until it is, this check reads it as written and the finding names the id so the reader can open the report. A package with a hijacked release in its past is the other case: it is graded by the proof above, and a package whose history could not be read stays CRITICAL until it can — the check would rather ask than pass a package it could not clear.

What this check does not cover

A malicious package nobody has reported yet. This check reads published reports; a package published this morning has none, and the age, name and install-code checks (P6, P10, P5) are what read it then. The package's code. Nothing here reads it. A version written on the command line. npm install name@1.2.3 is judged as the package: the version compared with the reports is the registry's latest, and every other reported version is read through the second question above, not matched against the one typed. What the package installs after it. Its own dependencies are not looked up.

Scope, the same on every page of this roster: RepoGates does not see git clone, package managers or curl — outside Claude Code with the RepoGates plugin, whose hook refuses a clone or install that names a blocked repository on the command line, before it runs. The hook sees Bash tool calls in that one client and nothing else; a package named on the line (npm install express, pip install flask, npx, npm create) is judged by its own verdict under this roster, its declared repository riding along. Direct dependencies named on the command line only; transitive dependencies and lockfiles are not resolved. A package added by editing package.json or requirements.txt and installed later is not a line the hook judges. Edit and Write are read for one thing only — an API key about to be saved — checked on the machine and never sent; that guard asks, it never denies. This roster reads what npmjs.org and pypi.org publish about a package — its record, its release history, its declared repository — and never the package's code or what it installs after it. A registry other than those two (a --registry or --index-url on the line) is asked about, not assessed. A package the registry no longer serves is not assessed, never a pass. A PASS means nothing matched on what was read.

Check it yourself

Ask OSV the same question the check asks, with the package's name and ecosystem (npm or PyPI):

curl -s https://api.osv.dev/v1/query \
  -d '{"package":{"name":"NAME","ecosystem":"npm"}}' | jq -r '.vulns[]?.id' | grep '^MAL-'

Any id printed is a malicious-package report; open it on osv.dev to read which versions it names.

Questions

What does RepoGates send to OSV? The package's name, its ecosystem (npm or PyPI) and the version the registry serves as latest, in one query, and the name alone in a second. Nothing about who is asking, what machine they are on or what else they are installing is sent.

Why is a package with an old malicious release not always blocked? Because a hijacked release that was reported and pulled is in the history of some of the most-used packages on npm, and blocking every later install of them would teach people to override the check. A report on other versions is a note only when the record proves the hijack shape: exact versions, an established package, a history that was read, and unreported releases published before the first reported one. Anything short of that proof stays critical.

Does a PASS on P1 mean the package is not malware? No. It means OSV holds no malicious-package report that covers the latest version, and none on other versions that the check could not account for. A package nobody has reported yet passes this check; the age, name and install-code checks are the ones that read a new package.

Related checks

P10 Lookalike name · P5 Install-time code · P7 Dormant then released.

Add RepoGates to Chrome Pricing

Sources for this page: the check's rules and weights from the product's own roster and scoring tables; the OSV id for lodahs as read on 29 October 2026; the testmetest record on its intel page.