Check P2 · provenance family · severity CRITICAL · automatic · one of the 12 npm and PyPI package checks
Maps to OWASP LLM03 ATLAS AML.T0010 Where the published package came from. A declared source repository that is BLOCK or campaign-listed is the compromise ATLAS names; a source outside GitHub and gitlab.com is stated as not assessed.
The question this check asks: what does the repository this package says it comes from look like? A package declares a source — npm's repository field, a PyPI project's links — and this check runs the 22 repository checks on that repository, on the same pass, and carries the answer onto the package.
The package is what installs; the repository is where people look. A reader deciding whether to trust a package opens its repository, sees the stars and the maintainers, and reads that trust back onto the package. When the repository is a days-old account's or one the 22 checks block, the package inherits that problem whatever its own record says. The rule is the one the skill roster has used since 27 September 2026: a package whose source repository is BLOCK is BLOCK, with that repository's own findings beside it. Whether the package was actually built from that repository is a separate question, P4's.
The declared repository is resolved from the registry's record. On GitHub it is assessed through the 22 checks; on gitlab.com through the 22 checks' GitLab adapter. The result is one row, pkg-source:owner/repo: CRITICAL and 45 points when the repository is campaign-listed or its own verdict is BLOCK — the package is BLOCK, and the row carries the repository's findings so your policy profile acts on it exactly as it acts on a git clone of that repository (a repository that is BLOCK only for its devcontainer warns there, and so here); a note at 0 points otherwise, reading the repository's verdict, its score and the findings that drove it. The full source verdict travels with the response as a source object.
Two further rows are notes at 0 points. A source declared on another host is pkg-source-external: named, and not assessed. No source declared at all is pkg-source-none, and P3 grades what that means. A repository that was declared but could not be read in time is a partial scan: P2 is listed as not checked, never passed.
Whatever the 22 checks misread on a repository, the package carries. A first project on a new account is BLOCK on its owner's age, here as on its own page; a large old repository picks up REVIEW findings the package has nothing to do with. The row names the repository's own drivers, so the reader can see that the finding is about the repository's age or its devcontainer and not about the package, and an override records the reason. A note on a REVIEW repository does not move the package's verdict; only a BLOCK does.
Whether the package was built from that repository. A package can name any repository; P2 assesses the one named, and P4 asks whether that repository's own manifest names the package. A repository on another host is named and not assessed. The package's code and the repository's code: the 22 checks read a repository's metadata and file list, never run it, and nothing here reads the published package.
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.
Read what the package declares, then look at that repository:
npm view NAME repository
curl -s https://pypi.org/pypi/NAME/json | jq '.info.project_urls'
Then open the repository: its owner's age, its own age, and whether its releases and files look like the package you are about to install.
Why does a BLOCK on the repository block the package? Because the repository is where the package's trust comes from. A reader who opens a package's repository and sees a well-kept project trusts the package; if the 22 repository checks block that repository, the trust the package borrows is the problem. The package gets the repository's own findings and the same action your profile takes on a git clone of it, never stricter and never looser.
What happens when a package declares a repository on another host? The row names the address and says it was not assessed. The 22 checks read GitHub and gitlab.com; a source anywhere else is a note, and the package is judged on its own record by the other checks.
Does P2 check that the package was built from that repository? No. Any package can name any repository. P2 assesses the repository named; P4 asks whether that repository's own manifest names the package at the place it says it lives, which is the closest the registry's record comes to that question.
P3 Source declared · P4 Name matches its source · S1 Source repository · C1 Owner account age.
Add RepoGates to Chrome Pricing
Sources for this page: the rule and weights from the product's own roster and scoring tables; the S1 rule of 27 September 2026 as recorded on its own page.