Search your manifests and lockfiles for git, git+https, git+ssh, tarball URLs and file paths where a version range should be. In npm these appear in package.json and package-lock.json. In pip they appear as git+https lines in requirements files. Each hit is a dependency that bypasses your registry controls.
Why these deserve their own search
A registry package has a name, a version and a published artifact. A git dependency points at a repository and a ref. Whoever controls that repository controls what you install, and a branch name can change under you.
npm's documentation shows that dependency specs can be a git URL, a tarball URL, a GitHub shorthand such as user/repo, or a local path. It also notes that a git dependency gets built if the repo defines scripts such as build, prepare or install, so install-time code can run.
What to search for in npm
In package.json, the value is a URL or shorthand instead of a version range. In package-lock.json, the resolved field tells you where each package actually came from. For registry packages it is a tarball URL; for git dependencies it is a git URL with a commit SHA.
git grep -nE '"(git\+https?|git\+ssh|git|file|https?)://' -- '*package.json'
git grep -nE '"resolved": "(git\+|github:|file:)' -- '*package-lock.json'
The first pattern also matches fields such as homepage, so expect some noise. The first pattern also matches fields such as homepage, so expect some noise. Shorthand like user/repo is harder to catch with a pattern. Look for dependency values that contain a slash but no version-like characters, or list them with a small script that parses the JSON.
What to search for in pip
pip's documentation gives the direct URL form and notes that a git ref can be a branch, tag, commit hash or ref, added after an at sign.
git grep -nE 'git\+(https?|ssh)://| @ (https?|git)' -- '*requirements*.txt' '*pyproject.toml'
The documentation also says to prefer git+https, and it discourages the git, git+git and git+http schemes because they lack authentication or TLS encryption. It recommends pinning with a full commit hash.
Reading the results
| What you find | Risk level | Reasonable action |
|---|---|---|
| Full commit hash, internal repo | Lower | Record it and set an owner |
| Full commit hash, external repo | Medium | Check the repo, consider vendoring or publishing an internal package |
| Branch or tag name | Higher | Pin to a commit hash |
| No ref at all | Higher | The default branch is used, so pin it |
| Plain HTTP URL | Highest | Replace it, since it has no transport protection |
A pinned hash is better than a branch, but the dependency still does not get registry-side checks such as malware scanning or advisories attached to a package name. Your own scanner may not match it to an advisory either.
Make it stick
Decide your policy once: for example, "git dependencies only from our own organization, pinned to a commit hash". Then enforce it in a pull request check so the search does not need to be repeated by hand. See find unapproved dependencies across all repos for the wider sweep.
Try it yourself
Open the dependency inventory demo and look for packages whose source is not the usual registry. Note how the inventory makes the source visible per package.
Click through it at your own pace, or open it full screen.
Quick check
Is a git dependency always bad?
No. Forks of a fixed library and internal packages are common. The problem is not knowing they exist, so list them and pin them.
Do local file paths matter?
npm says local paths are meant for offline development and testing, not for published packages. If one reaches a production build, ask why.
Safeguard offers SBOM and dependency scanning across ecosystems, plus policies and gates for pull requests. Try a free scan at gold.safeguard.sh/scan.
Sources
Last reviewed: 19 October 2026.