lockfile-lint
v5.1.0
Published
A CLI to lint a lockfile for security policies
Readme
About
A CLI tool to lint a lockfile for security policies
Install
npm install --save lockfile-lintUsage
lockfile-lint can be installed per a project scope, or globally and exposes a lockfile-lint executable that should be practiced during builds, CIs, and general static code analysis procedures to ensure that lockfiles are kept up to date with pre-defined security and usage policies.
lockfile-lint --type <yarn|npm> --path <path-to-lockfile> --validate-https --allowed-hosts <host-to-match> --allowed-urls <urls-to-match>Supported lockfiles:
- npm's
package-lock.jsonandnpm-shrinkwrap.json - yarn's
yarn.lock
Example
An example of running the linter with debug output for a yarn lockfile and asserting that all resources are using the official npm registry as source for packages:
DEBUG=* lockfile-lint --path yarn.lock --type yarn --allowed-hosts npmExample 2: specify hostnames and enforce the use of HTTPS as a protocol
lockfile-lint --path yarn.lock --allowed-hosts registry.yarnpkg.com --validate-https--type yarnis ommitted since lockfile-lint can figure it out on it's own--allowed-hostsexplicitly set to match yarn's mirror host
Example 3: allow the lockfile to contain packages served over github and so need to specify github.com as a host as well as the git+https: as a valid URI scheme
lockfile-lint --path yarn.lock --allowed-hosts yarn github.com --allowed-schemes "https:" "git+https:"--allowed-hostsexplicitly set to match github.com as a host and specifiesyarnas the alias for yarn's official mirror host--allowed-schemesis used instead ofvalidate-httpsand it explicitly allows bothhttps:andgit+https:as the HTTP Scheme for the github URL. Note that--allowed-schemesand--validate-httpsare mutually exclusive.
Example 4: allow the lockfile to contain a package which resolves to a specific URL specified by the --allowed-urls option while all other packages must resolve to yarn as specified by --allowed-hosts
lockfile-lint --path yarn.lock --allowed-hosts yarn --allowed-urls https://github.com/lirantal/lockfile-lint#d30ce73a3e5977dede29450df1c79b09f02779b2--allowed-hostsallows packages from yarn only--allowed-urlsoverridesallowed-hostsand allows a specific Github URL to pass validation
CLI command options
| command line argument | description | implemented |
|----------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------|
| --path, -p | path to the lockfile but you can also provide a glob matching pattern as long as it isn't expanded by a shell like bash or zsh. If that's the case, you can provide it as a string, for example: -p '/Users/lirantal/repos/**/package-lock.json' to match multiple lockfiles | ✅ |
| --type, -t | lockfile type, options are npm or yarn | ✅ |
| --format, -f | sets what type of report output is desired, one of [ pretty, plain ] with plain removing colors & status symbols from output | ✅ |
| --validate-https, -s | validates the use of HTTPS as protocol schema for all resources in the lockfile | ✅ |
| --allowed-hosts, -a | validates a list of allowed hosts to be used for all resources in the lockfile. Supported short-hands aliases are npm, yarn, and verdaccio which will match URLs https://registry.npmjs.org, https://registry.yarnpkg.com and https://registry.verdaccio.org respectively | ✅ |
| --allowed-schemes, -o | allowed URI schemes such as "https:", "http", "git+ssh:", or "git+https:" | ✅ |
| --allowed-urls, -u | allowed URLs (e.g. https://github.com/some-org/some-repo#some-hash) | ✅ |
| --empty-hostname, -e | allow empty hostnames, or set to false if you wish for a stricter policy | ✅ |
| --validate-package-names, -n | validates that the resolved URL matches the package name | ✅ |
| --validate-integrity, -i | validates the integrity field is a sha512 hash | ✅ |
| --validate-integrity-strict | requires complete SHA-512 integrity, with exceptions for Git, local directory, linked and bundled dependencies | ✅ |
| --allowed-package-name-aliases, -l | allow package name aliases to be used by specifying package name and their alias as pairs (e.g: string-width-cjs:string-width) | ✅ |
| --integrity-exclude | exclude packages from the --validate-integrity check | ✅ |
Strict integrity validation
Use --validate-integrity-strict to require a complete, base64-encoded SHA-512
digest for each dependency in npm lockfiles (versions 1, 2 and 3) or Yarn Classic
lockfiles:
lockfile-lint --path package-lock.json --validate-integrity-strictThe flag works on its own and takes precedence over --validate-integrity when
both are passed. The existing --validate-integrity behavior is unchanged.
--integrity-exclude applies to either mode.
Git dependencies, local directories (file:), workspace links and bundled
dependencies are exempt because they may not have an integrity field. Local
tarballs (.tgz or .tar.gz) and HTTP(S) tarballs still require integrity,
including tarballs hosted on GitHub. Registry entries require complete integrity regardless of whether resolved
is present. Missing or incomplete integrity is reported in either case.
This validates the recorded hash's presence and format; it does not download packages or establish that their contents are trustworthy. Yarn Berry uses a different checksum format and is not supported by this SHA-512 integrity policy.
In a configuration file, set validateIntegrityStrict: true.
For npm v2/v3, bundled entries require a verified bundler ancestor. The parser
walks up the package path, skipping ancestors marked inBundle/bundled, to the
nearest non-bundled ancestor. That ancestor must exist and declare
bundleDependencies as a non-empty array or true. It must also have a complete
SHA-512 integrity value or qualify independently as a commit-pinned Git source,
local directory or workspace link. Transitive bundled dependencies are covered
even when their names are absent from the declaration.
For npm v1, the nearest enclosing non-bundled ancestor must meet the same
integrity/source requirement. The v1 dependency tree does not record the parent's
bundleDependencies, so the parser cannot confirm the declaration itself.
Missing or unverified ancestors leave children subject to the integrity check;
excluding a parent from validation does not verify its bundle.
Raw link, bundled or inBundle flags do not exempt HTTP(S) sources or local
.tgz/.tar.gz files; the Git source exceptions below still apply.
Git-protocol URLs and Git-host shorthands require a 7-40-character hexadecimal
commit fragment to qualify for an exemption. Branches, tags, semver ranges and
missing refs require complete SHA-512 integrity. Link/bundle flags cannot bypass
this pin requirement. Local file URLs are classified using their decoded path:
percent-encoded .tgz/.tar.gz extensions still require integrity, and malformed
URL escapes do not qualify as local directories.
Yarn Classic GitHub sources are also exempt when the URL is exactly
https://codeload.github.com/<owner>/<repo>/tar.gz/<40-hex-commit-sha>,
without a query string or fragment. Codeload URLs using tags, branches or short
SHAs, and archive URLs that do not match this shape, still require integrity.
HTTPS GitHub, GitLab and Bitbucket repository URLs of the form
https://<host>/<owner>/<repo>#<commit> are exempt when the commit is 7-40
hexadecimal characters and there is no query string. This separate Git-remote
exception accepts abbreviated commits; archive/download paths remain subject
to the tarball rules above.
Strict mode rejects Yarn Berry with one unsupported-format message and exits
non-zero. When this is the only failure, the CLI reports
Error: unsupported lockfile format for --validate-integrity-strict without
claiming security issues. If other validators also fail (for example,
--validate-https), it retains Error: security issues detected! for those
findings. This applies to both plain and pretty output.
File-Based Configuration
Lockfile-lint uses cosmiconfig for configuration file support. This means you can configure the above options via (in order of precedence):
- A "lockfile-lint" key in your package.json file.
- A .lockfile-lintrc file, written in JSON or YAML, with optional extensions: .json/.yaml/.yml (without extension takes precedence).
- A .lockfile-lintrc.js, .lockfile-lintrc.cjs, or .lockfile-lintrc.mjs file that exports an object.
- A lockfile-lint.config.js, lockfile-lint.config.cjs, or lockfile-lint.config.mjs file that exports an object.
ESM syntax is supported in .mjs files. For example:
export default {
path: 'yarn.lock',
type: 'yarn',
allowedHosts: ['npm', 'yarn'],
validateHttps: true
}The configuration file will be resolved starting from the current working directory, and searching up the file tree until a config file is (or isn't) found. Command-line options take precedence over any file-based configuration.
The options accepted in the configuration file are the same as the options above in camelcase (e.g. "path", "allowedHosts").
References
- This package aliasing article explains the rational for error reporting on package aliases in lockfiles.
- Why npm lockfiles can be a security blindspot for injecting malicious modules
Contributing
Please consult CONTRIBUTING for guidelines on contributing to this project.
Author
lockfile-lint © Liran Tal, Released under the Apache-2.0 License.
