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.
| Signal | Where it lives | What it proves | Takeaway |
|---|---|---|---|
| 200 /package.json with name | Public origin | Inventory of declared deps | Block at the edge; fix the publish pipeline |
| OSV match on lockfile | Authorized GitHub deepen | Known advisory for a pin | Triage; see the OSV vs URL guide |
| Secret in public JS | Bundled client code | Credential-shaped string shipped | Different finding; rotate |
| package.json in .git on the CDN | VCS dump | Worse than the one file | See 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 nowFAQ
- 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
Vulnerabilities
Dockerfile vs package.json on Production OriginsVulnerabilities
composer.json vs package.json on Production OriginsVulnerabilities
Exposed .git vs .env on Production Websites