lpm audit
Scan installed packages for vulnerabilities, behavioral risks, and (optionally) hardcoded secrets.
lpm auditWalks every installed package and reports:
- Confirmed vulnerabilities — npm packages are cross-referenced against OSV.dev;
@lpm.dev/*packages get vulnerability data from the registry's per-version metadata. - Behavioral flags — static analysis reports risky behaviors such as
eval, child processes, network access, filesystem access, and native code. LPM.dev Registry metadata and local findings use the same severity policy. See the full tag list underlpm query. - Quality score — for
@lpm.dev/*packages. Scores below 40 surface as moderate; below 20 surface as high. - Dependency-confusion warnings — when an installed
@lpm.dev/*package's bare name collides with a popular npm package (react,lodash, etc.), the audit warns about the registry-confusion risk. - Optional secret scan — with
--secrets, scans the installed source for hardcoded API keys, tokens, and private keys.
Works in any project, not just LPM.dev Registry-published ones. Discovery walks lpm.lock, package-lock.json, pnpm-lock.yaml, yarn.lock, or bun.lock (text form). Without a supported lockfile, it recursively walks nested node_modules/ package directories without following symlinks and reports that inventory as degraded.
The vulnerability scan fails closed. If OSV.dev is unavailable, returns an incomplete batch, or omits advisory details that cannot be hydrated, lpm audit exits non-zero and never reports a clean audit. The same applies when the LPM.dev Registry cannot return exact metadata for an installed @lpm.dev/* version. Under --json, an incomplete OSV scan returns the audit envelope with success: false, osv_degraded: true, and osv_degraded_reason; other registry failures use the standard error envelope.
The signatures subcommand is a focused check for npm registry package signatures. It verifies the installed package set against npm-compatible dist.signatures metadata and exits non-zero when any registry package cannot be verified.
Foreign lockfiles
lpm audit reads one fixed snapshot of each selected foreign lockfile. It rejects malformed files and unsupported versions instead of using a degraded inventory.
The audit supports npm lockfile versions 1, 2, and 3. It supports pnpm lockfile major versions 5, 6, and 9.
Each foreign lockfile has these limits:
- The file size limit is 64 MiB.
- The package-entry limit is 200,000.
npm lockfiles have these additional limits:
- The package-path limit is 32 KiB.
- The package nesting limit is 256 levels.
- The dependency limit for one package is 10,000.
- The total dependency-edge limit is 1,000,000.
If a lockfile exceeds a limit, the audit exits non-zero. It does not use an ancestor lockfile or the node_modules/ fallback.
For bun.lockb, LPM CLI copies the selected file before conversion. The Bun converter has these limits:
- The time limit is 30 seconds.
- The converted output limit is 64 MiB.
- The diagnostic-output limit is 64 KiB.
If Bun exceeds a limit, the audit stops the converter and exits non-zero.
Examples
lpm audit
lpm audit --level high # only show high-severity findings
lpm audit --secrets # also scan for hardcoded credentials
lpm audit --fail-on vuln # CI: exit non-zero only on confirmed vulns
lpm audit --fail-on behavior # CI: exit non-zero on critical or high behaviors
lpm audit --secrets --fail-on secrets # CI: exit non-zero only on hardcoded secrets
lpm audit --fail-on all # CI: strict union of all failure categories
lpm audit signatures # verify npm registry package signatures
lpm audit signatures --json # machine-readable signature report
lpm audit fix # bump vulnerable direct deps and reinstall
lpm audit --fix --dry-run # plan the same fixes without writing files
lpm audit --json # structured output for toolingJSON package identity
lpm audit --jsonEach object in packages includes name, version, instance_id, and path.
For an LPM CLI-managed package, instance_id identifies the exact lockfile instance. It is null when the selected inventory does not contain an exact instance ID.
The path value identifies the directory that the audit analyzed. It points to the exact installed package materialization when that path is available.
For a file: or link: dependency, path identifies the original live source directory. The value is null when discovery cannot resolve an analyzed directory.
Two rows can have the same name and version. Their instance_id, path, and findings can differ.
Use instance_id as the row key when it is not null. Otherwise, use path. Do not use only name and version as a unique key.
CI gating
lpm audit exits non-zero when its findings trip the active --fail-on policy. The implicit default is conservative — high-severity behavioral signals like eval don't fail CI unless you ask for them explicitly with --fail-on all.
An incomplete vulnerability scan always exits non-zero, regardless of --fail-on. A network or advisory-data failure is not evidence that the installed tree is clean.
| Policy | Exit code 1 when |
|---|---|
| (no flag, implicit default) | Vulnerabilities or critical behavioral flags (obfuscation and protestware). Excludes high behaviors so existing pipelines that tolerate eval do not break. |
vuln | Any confirmed vulnerability — OSV (npm) or registry-side advisory (@lpm.dev) |
behavior | Any critical or high behavioral flag |
secrets | Any hardcoded-secret finding from lpm audit --secrets |
all (explicit) | Vulnerabilities + critical behaviors + high behaviors + secrets — the strict union |
For finer control, use lpm query — its CSS-like selectors target individual flags or combinations.
Fixing vulnerabilities
lpm audit fix
lpm audit --fix
lpm audit fix --dry-runlpm audit fix is the canonical form; lpm audit --fix is an alias for npm-compatible muscle memory. Both read the package exposed at each direct root node_modules path and match its exact name and version to the lockfile, so transitive copies cannot be selected merely because they have a higher matching version. If the lockfile contains multiple source identities for that same installed name and version, the dependency is reported as source-ambiguous and skipped rather than guessing or sending its name to a metadata endpoint. They support dependencies, devDependencies, optionalDependencies, npm aliases such as npm:lodash@^4, and registry advisories for @lpm.dev/* packages.
For npm packages, the fixer evaluates every relevant OSV affected range against available registry versions and chooses the lowest newer version proven unaffected. This preserves maintained release lines when a patch exists instead of jumping to the highest fixed version from another major line. On apply, the manifest entry is pinned to that exact planned version (npm aliases retain their npm: identity), and verification rejects any different installed version; dry-run and apply therefore report the same target. Complex or non-registry source protocols such as catalog:, workspace:, file:, git, and JSR are reported as skipped rather than rewritten into semver dependencies. Transitive-only findings are not changed.
The fix pass currently operates only in LPM CLI-managed projects. It does not rewrite npm, pnpm, Yarn, or Bun lockfiles.
Fix and dry-run planning hold the project's install transaction lock against other LPM CLI operations. Before the first write, a real fix compares the exact package.json and lpm.lock bytes used for planning.
If either file changed, the fix exits without an overwrite. It also exits if a different lpm.lock became active.
The fix then snapshots package.json, lpm.lock, and lpm.lockb. It invalidates the install cache, runs a silent install, and checks the exact installed version.
The version check uses OSV.dev or exact LPM.dev Registry metadata. Thus, --json emits one audit-fix document without nested install output.
A failed install or version check restores the snapshotted files. The transaction does not copy node_modules/.
If the installed tree differs after a failed fix, run lpm install to make it match the restored lockfile.
--dry-run reports the same plan without mutating package.json, lpm.lock, or node_modules.
Registry signatures
lpm audit signaturesThe command verifies npm registry package signatures for the installed tree. LPM CLI reads stored signatures and publication times from lpm.lock when available.
If stored evidence is incomplete, LPM CLI gets exact metadata from the authorized registry. A signature with an expiring key requires a publication time.
For foreign lockfiles, the recorded tarball URL must match an authorized registry path. This path can match npm or LPM.dev Registry.
The path can also match a registry that is configured in .npmrc.
LPM CLI keeps the configured registry path and its authentication. It never trusts an unconfigured origin from a foreign lockfile.
Human output is intentionally compact:
! Registry signatures · 1 verified · 1 not verified
unsigned-pkg@1.0.0 missing dist.signaturesA clean tree exits zero:
✓ Registry signatures verified · 247 verifiedUnder --json, the envelope includes aggregate counts and one row per package:
{
"success": false,
"scanned": 2,
"verified": 1,
"not_verified": 1,
"skipped": 0,
"packages": [
{ "name": "signed-pkg", "version": "1.0.0", "status": "verified", "signatures_verified": 1 },
{
"name": "unsigned-pkg",
"version": "1.0.0",
"status": "not_verified",
"reason": "missing_signatures",
"reason_detail": "missing dist.signatures",
"signatures_verified": 0
}
]
}Statuses are verified, not_verified, or skipped. Skipped rows cover packages outside this signature surface, such as non-registry sources and @lpm.dev/* packages. Any not_verified row makes the command exit with code 1.
Severity levels
lpm audit --level highSuppresses anything below the threshold. Ladder from most-to-least severe: critical → high → moderate (alias medium) → info (alias low). Default is info (show everything). Any other value is rejected as a usage error before the audit starts.
Info results include behavioral metadata such as environment-variable access, URL literals, and high-entropy strings. Human output puts these results under Behavioral metadata. The final summary does not count them as suspicious packages or security issues. These results do not make the command fail by themselves.
Critical behavioral results mean high-confidence obfuscation or protestware. Scores above 0.3 through 0.7 are Info-level possible obfuscation. Scores above 0.7 are Critical.
The scanner detects capabilities, not data flow or command intent. Environment access plus network access does not prove exfiltration. A detected rm -rf shell command remains a High shell and child-process signal.
For @lpm.dev/* packages, the human report includes registry and local findings. Registry advisories and security findings keep their published severity, including Critical.
Secret scanning
lpm audit --secretsScans the installed source tree under node_modules/ for hardcoded API keys, access tokens, private keys, and similar credentials — the same scanner that runs as part of lpm publish. Useful as a final check before shipping a Docker image or deploying.
Requires node_modules/ to exist (errors with a run \lpm install` firsthint otherwise).--secretsstill runs as its own scan mode, but it participates in--fail-on`:
lpm audit --secretsuses the command's default gate policy (all), so a detected secret exits non-zero.lpm audit --secrets --fail-on secretsgates on secret findings only.lpm audit --secrets --fail-on vulnor--fail-on behaviorkeeps the secret scan informational.--levelis still ignored in secrets mode.
Flags
| Flag | Effect |
|---|---|
--level <critical|high|moderate|info> | Minimum severity to report (default: info; aliases: medium, low) |
--fail-on <vuln|behavior|secrets|all> | CI exit-code policy (secrets applies to --secrets; all includes secret findings too) |
--secrets | Scan installed source for hardcoded secrets (separate scan mode; consults --fail-on, still ignores --level) |
--fix | Alias for lpm audit fix |
--dry-run | With --fix, show the fix plan without changing files |
Plus the global flags — --json is especially useful for piping into CI gates.
Subcommands
| Subcommand | Effect |
|---|---|
fix | Update vulnerable direct dependency instances to verified unaffected versions, then reinstall |
signatures | Verify npm registry package signatures for the installed tree |
See also
lpm query— inspect packages by behavioral tag- Security audit — concept overview and tag reference
lpm publish— runs the same secret scanner before upload