RoastMyOpsec

Vulnerabilities

Public package.json vs Lockfile Advisories on Production

May 11, 2025

Public package.json vs lockfile advisories is two ways your dependency story leaks. A 200 on /package.json with a JSON name field is an inventory gift on the marketing origin — versions, scripts, and sometimes private package names. An OSV hit on package-lock.json inside a repo you deepen is a known-advisory queue, not a public file. You can have a locked-down GitHub and still ship package.json next to index.html. RoastMyOpsec's path check looks for a usable package.json signature on a bounded GET. It does not download node_modules or run npm audit against your CDN.

The practical difference

package.json on the web root is a leftover from a static export or a mis-synced dist folder. Attackers use it as a shopping list; defenders should treat it like robots.txt that lists internal names. The lockfile in git is the exact pins. OSV cares about those pins. The public JSON is the brochure of the same story, often stale or incomplete.

Removing /package.json does not patch CVEs. Patching CVEs does not hide a file you still serve.

How to choose what to fix first

If the roast shows package.json on the origin: deny that path at the CDN, stop copying the repo root into the deploy bucket, rotate nothing unless secrets were in scripts (they should not be). If deepen shows OSV IDs: triage reachability and bump the lockfile. If both fire, do the public file the same day — it is a one-line edge rule — then schedule the advisory work.

SignalWhere it livesWhat it provesTakeaway
200 /package.json with namePublic originInventory of declared depsBlock at the edge; fix the publish pipeline
OSV match on lockfileAuthorized GitHub deepenKnown advisory for a pinTriage; see the OSV vs URL guide
Secret in public JSBundled client codeCredential-shaped string shippedDifferent finding; rotate
package.json in .git on the CDNVCS dumpWorse than the one fileSee exposed .git vs .env

What the scanner will not do

No recursive npm install from your site. No exploit of a listed package. Soft-404 HTML that looks like a homepage is not counted as a hit. A missing file is a pass for this check, not a claim your lockfile is clean.

Common mistakes

The first mistake is 'it is only metadata' while private registry package names sit in dependencies.

The second mistake is blocking package.json and still serving package-lock.json.

The third mistake is treating a public package.json as equivalent to a completed npm audit.

Free audit the URL you own

RoastMyOpsec is a defensive public-surface roast: headers, cookies, sensitive paths, and more — no exploit payloads. Start with the free audit, then open the vault if the blurred findings look expensive.

Free audit now

FAQ

Is a public package.json a vulnerability?
It is an information leak. Treat it as a finding. Block it. It is not the same as a remote code execution.
Should I also block package-lock.json on the site?
Yes if it is on the origin. Lockfiles belong in git and CI, not the CDN. Deepen the repo for OSV; do not publish the lockfile as a static asset.
How does RoastMyOpsec detect package.json?
A bounded GET and a JSON body with a name field — not a full npm parse. No exploit payloads.

Sources

Related guides