Check P4 · provenance family · severity HIGH · automatic · one of the 12 npm and PyPI package checks
Maps to OWASP LLM03 ATLAS AML.T0073 A package whose declared repository names another package: the borrowed reputation of a repository the package may not have been built from.
The question this check asks: was this package built from the repository it points at? The registry cannot say, but the repository can come close: its own package.json or pyproject.toml, at the place the package says it lives, names a package. This check reads that name and compares.
Pointing a package at a famous repository costs nothing, and the famous repository's stars then appear beside the package on every page that shows them. That is starjacking: the repository is fine, and the package is not its. P2 would pass such a package, because the repository it names is genuinely good; this check is the one that asks whether the repository agrees.
On npm the manifest is read at the repository's repository.directory when the package names one — how a monorepo says which folder is the package — and at the root otherwise. On PyPI the repository's root pyproject.toml is read for its [project] name. Names are compared as the registry compares them (case-folded; on PyPI _ and . read as -).
pkg-name-mismatch — the manifest names another package — is HIGH and 15 points on a new package (first published less than 90 days ago) and MEDIUM and 5 points on an established one. pkg-name-unconfirmed covers the cases where no name could be compared, each stated: a declared directory that is not a plain path (HIGH new, MEDIUM established; nothing is read there); no manifest naming a package at that place (MEDIUM new, a note established — naming a famous repository with nothing at the place must not pass); a repository root that is a workspace while the package names no directory in it (MEDIUM new, a note established); a source not on GitHub, whose manifest is not read (MEDIUM new, a note established); and no repository at all (a note). A read GitHub could not answer is a partial scan, and P4 is listed as not checked.
A package renamed after publishing, or one whose repository renamed it later, reads as a mismatch until the two agree again. A Python project that keeps its metadata in setup.py or setup.cfg rather than pyproject.toml has nothing at the place read, and is unconfirmed — a note once the package is established. The finding prints the path read and the name found, so the reader can see which case it is.
Whether the published files match the repository. Two names agreeing is not the same as the package being built from that commit; nothing here compares the package's contents with the repository's. A setup.py or setup.cfg is not read. A source off GitHub is not read for its manifest. The package's code is not read.
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.
npm view NAME name repository
gh api repos/OWNER/REPO/contents/DIRECTORY/package.json --jq '.content' | base64 -d | jq .name
On PyPI, open the repository's pyproject.toml and read [project] name. The two names should be the same package.
What is starjacking? Publishing a package that names a popular repository as its source, so the repository's stars and reputation appear beside a package that was not built from it. The repository is genuine; the package is not its. Reading the repository's own manifest is how this check asks whether the repository agrees.
How are monorepos handled? Through npm's repository.directory, which is how a package in a monorepo says which folder it lives in. The manifest there is read. When a package names no directory and the repository's root manifest is a workspace, the names are not compared and the row says so; on a new package that is a medium finding, because a famous monorepo's root is the easiest repository to borrow.
Why is a missing manifest a finding? Because otherwise naming a famous repository with nothing at the declared place would pass the check. On a new package it is a medium finding; on an established one it is a note.
P2 Source repository · P10 Lookalike name · C4 Fork and lookalike.
Add RepoGates to Chrome Pricing
Sources for this page: the rule and weights from the product's own roster and scoring tables; the starjacking shape as recorded in the roster's design record of 29 October 2026.