ankur@sec:~$

$ cat owasp/a03.md

A03:2025

Software Supply Chain Failures

The code you did not write - packages, images, actions - is most of what you ship.

## 1 · why it happens

A typical app has hundreds of dependencies, each with their own dependencies. Loose version ranges (^, ~, latest) mean the code you deploy tomorrow may not be the code you tested today.

Attackers know this. They publish malicious versions from compromised maintainer accounts, typo-squat popular names, or upload a public package with the same name as your internal one (dependency confusion) and a higher version number.

# JavaScript

✗ vulnerable
// package.json
"dependencies": {
  "express": "^4.18.0",
  "@acme/auth-utils": "*"     // internal package, no registry scope
}
// CI
npm install                    // resolves whatever is newest today
✓ fixed
// package.json
"dependencies": {
  "express": "4.21.2",
  "@acme/auth-utils": "2.3.1"
}
// .npmrc - internal scope only from your private registry
@acme:registry=https://npm.internal.acme.example/
// CI
npm ci                         // installs exactly what the lockfile says

# C#

✗ vulnerable
<!-- .csproj -->
<PackageReference Include="Newtonsoft.Json" Version="13.*" />
<PackageReference Include="Acme.Internal.Auth" Version="*" />
✓ fixed
<!-- .csproj -->
<PropertyGroup>
  <RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
</PropertyGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<!-- nuget.config: packageSourceMapping sends Acme.* only to the private feed -->

## 2 · how attackers find it from outside

public sourcewhat it tells them
Public GitHub repospackage.json / .csproj files list your exact dependencies and internal package names.
Job postings"Experience with Angular 12, .NET 6, Elasticsearch 7" - your stack and how old it is.
JavaScript bundlesLibrary names and versions in comments and banners, e.g. jQuery v1.12.4.
HTTP headersFramework and server versions, matched against public CVE lists.

→ all OSINT sources · run them on yourself

## 3 · how it's abused

⚠ Recon your own assets, or targets you have written permission to test. Passive OSINT reads public data, but using it to target someone else's systems can still be illegal or against their terms. Examples on this site use example.com placeholders.

npm publish  # name: "@acme/auth-utils", version: "99.0.0"

Dependency confusion: a public package with your internal name and a higher version wins if your registry config allows it.

"postinstall": "node collect.js"

Install scripts run on every developer machine and CI runner that installs the package.

FROM node:latest

A mutable tag: whatever is published under "latest" next week goes straight into your build.

Payload examples adapted from PayloadsAllTheThings (MIT, © Swissky). Full lists:Dependency Confusion

## 4 · fix

## 5 · detect

fix at source

Trivy

Vulnerabilities and misconfigurations in images, dependencies and IaC.

fix at source

Gitleaks

Find secrets in your git history before someone else does.

Official description: OWASP A03:2025 Software Supply Chain Failures