Collect the lockfiles from every repo, extract each package name and version, and compare that list with your approved list. Anything left over is unapproved, and the repo that introduced it tells you who to ask. Lockfiles, not manifests, are the right source because they include transitive packages.
Why lockfiles, not manifests
A manifest such as package.json or requirements.txt lists what a developer asked for. A lockfile records what was actually resolved, including every transitive package. npm's documentation describes the lockfile entry field called resolved as the place the package was actually resolved from, and integrity as a string for the artifact that was unpacked. Those two fields are what you compare against policy.
If you only check manifests you will miss most of the tree.
Step 1: build the list of lockfiles
If your repos are checked out locally or mirrored, search for lockfile names across them. Git can search a specific revision or tree without checking it out, and it supports pathspecs to limit the search to matching paths.
git ls-files -- '*package-lock.json' '*yarn.lock' '*pnpm-lock.yaml' '*poetry.lock' '*Pipfile.lock' '*Cargo.lock' '*go.sum'
Run it per repository and write the output to a file with the repo name. Keep the default branch only to begin with.
Step 2: extract names and versions
Each ecosystem has its own format, so use the tool that ecosystem provides or a software composition scanner that reads all of them. A small script that prints one line per package in the form ecosystem, name, version is enough. Keep the repo name on every line.
Step 3: decide what counts as approved
Your approved list can be strict (name and version) or loose (name only, plus a rule such as "no package younger than N days"). Be explicit about which you mean, because the first run will flag thousands of lines on a strict list. For how to keep such a list from rotting, see keep an approved package list from going stale.
Step 4: compare and sort
Compare the extracted list with the approved list. Then sort the leftovers three ways:
- By number of repos using them. A package in 40 repos needs a policy decision, not 40 conversations.
- By direct versus transitive. Direct additions have a clear human owner.
- By source. Packages resolved from outside your approved registry, such as git URLs, deserve a closer look. See how to find git URL dependencies in npm and pip projects.
Step 5: turn findings into decisions
For each cluster, choose one of three outcomes: approve it and add it to the list, replace it with an approved alternative, or remove it. Record the decision and the owner. If a package is widely used already, approving it with a pinned version range is often the practical answer.
Step 6: stop new ones at the door
A one-time sweep ages quickly. Add a check on pull requests that flags a new package not on the list, so the review happens when the change is fresh and the author is still around.
Try it yourself
Open the pull request gate demo and watch how a change that introduces a new package is stopped before merge. Look for where the policy decision is shown to the author.
Click through it at your own pace, or open it full screen.
Quick check
Do dev dependencies count?
They run on developer machines and in CI, where credentials often live, so include them. You can use a lighter rule for them if you prefer.
How often should we run the sweep?
Weekly is realistic once it is automated. If you are doing it by hand, monthly is more honest than a quarterly plan that slips.
Safeguard offers SBOM and dependency scanning across ecosystems, plus policies and gates for pull requests. A free scan is available at gold.safeguard.sh/scan.
Sources
Last reviewed: 19 October 2026.