SCA: Software Composition Analysis
In plain terms#
Modern software is mostly other people's code. A typical application is 80–90% open-source
dependencies, meaning libraries you pulled in with npm install, go get, pip install, and so
on,
each of which pulled in its dependencies. Software Composition Analysis (SCA) is the
control that inventories all of that and checks it against databases of known vulnerabilities.
Think of it as checking every ingredient in a recipe against a recall list, and not because you made a mistake, but because someone upstream might have.
Why it matters#
You didn't write the vulnerable code, but you shipped it. Most real-world breaches that trace
back to "a library" are known, already-patched vulnerabilities that were never upgraded,
the Log4Shell/log4j incident is the famous example, but it happens quietly all the time. SCA
is often the highest-value control to adopt first, because the fix is usually just "upgrade
to the patched version," and the vulnerabilities are publicly cataloged as
CVEs.
Where it fits#
- Artifact: your dependency manifests and lockfiles (
package-lock.json,go.sum,poetry.lock,pom.xml, …). - Stage: early and often. It runs on a pull request with no deployment needed, and again continuously (a dependency that was clean yesterday can have a new CVE today).
How it works#
An SCA tool resolves your full dependency tree (direct and transitive), identifies each package and version, and matches them against vulnerability databases, chiefly the OSV (Open Source Vulnerabilities) database and the National Vulnerability Database (NVD). Good tools tell you not just what's vulnerable but whether a fixed version exists and how far you'd have to upgrade. Many also flag license risk from the same dependency tree, since a copyleft license that is incompatible with how you distribute. That's a different kind of problem with a different owner, so it's worth treating separately. See software licenses.
Popular & reputable tools#
| Tool | Notes |
|---|---|
| Trivy | OSS, fast, scans filesystems/images/repos; very common default |
| OSV-Scanner | OSS, from Google; built directly on the OSV database |
| Grype | OSS, from Anchore; pairs with the Syft SBOM tool |
| retire.js | OSS; fingerprints JavaScript files themselves, so it sees what no lockfile lists |
| Dependabot | Built into GitHub; opens upgrade PRs automatically |
| govulncheck | OSS, from the Go team; call-graph reachability for Go modules |
| Snyk, Mend, Sonatype | Commercial platforms with reachability across more languages, plus policy. Draugr can run Mend for this control if you already have it |
Common pitfalls#
- Transitive noise. Most findings are in dependencies-of-dependencies you can't directly upgrade, because you're waiting on a direct dependency to bump its version.
- Not all vulnerabilities are reachable. A CVE in a code path you never call is real but low-priority. Reachability analysis separates the two by building a call graph from what is in the build. Coverage varies sharply by language, and the claim is worth only as much as the evidence behind it, which reachability covers.
- Severity ≠ priority. A wall of "high" CVEs is not a plan. See prioritization.
- The lockfile is not the whole inventory. Front-end code routinely ships JavaScript no
package manager installed, such as a library pulled from a CDN, a vendored file under
static/, bundled output shipped without its manifest. Lockfile-based SCA answers for what was installed, so a repository serving a five-year-old jQuery scans clean. The control runs, reports, and passes. The gap matters because of its shape rather than its size, since nothing in that output suggests there is anywhere left to look.
sca control runs Trivy in filesystem mode over each of your component's repositories to find dependency vulnerabilities, normalized to SARIF alongside every other control. Because Draugr knows each component's exposure and criticality, it ranks those CVEs into a short, ordered list instead of a flat wall. See quickstart in the docs.A second scanner can serve the same control, and both sets of findings arrive in the same report ranked by the same risk model. Grype is free and one command to install; where it and Trivy disagree, that difference is itself worth reading, because it is a statement about coverage neither tool makes on its own. retire.js answers that pitfall by identifying a library from a fingerprint of the file itself, so the vendored jQuery that appears in no manifest is reported with a name, a version and the version that fixes it, which the lockfile scanners cannot produce, because the evidence they read was never written. On Go modules, govulncheck answers a different question again, not which dependencies are vulnerable but which of those vulnerabilities your code can reach, with the call path as evidence. Its verdicts fold onto the findings already there rather than arriving as a second set, and a finding nothing can reach is ranked down rather than removed. See reachability. If your organization already pays for Mend, Draugr can run that on this control too. It is opt-in and requires consent for the effect it has, because a Mend scan uploads your dependency inventory and creates a project in your Mend account, which outlives the scan.
Keep learning#
- SAST, the same idea for code you write
- SBOM, the inventory SCA depends on
- CVE & CVSS, where vulnerabilities are cataloged and scored