Dependency Scanning Explained

Dependency Scanning Explained

I once inherited a project with over 400 dependencies, and when I ran a scan for the first time, it flagged 37 known vulnerabilities — several of them critical — sitting quietly in packages nobody on the team had looked at in over a year. That’s the value of dependency scanning in one sentence: it turns an invisible, accumulating risk into something visible and actionable.

What Is Dependency Scanning?

Dependency scanning is the automated process of analyzing every third-party library and package your application relies on — both direct and transitive — and checking each one against databases of known security vulnerabilities (CVEs), outdated versions, and sometimes license issues.

flowchart LR
    A[Project Manifest e.g. package.json] --> B[Dependency Resolution]
    B --> C[Direct Dependencies]
    B --> D[Transitive Dependencies]
    C --> E[Scanning Engine]
    D --> E
    E --> F[Vulnerability Database - NVD/OSV/etc.]
    F --> G[Report: Severity, CVE ID, Fixed Version]

Why Dependency Scanning Matters So Much

Modern applications are often 80% or more third-party code by volume. Every one of those dependencies is a potential entry point for a vulnerability that has nothing to do with code your team actually wrote. Without scanning, you’re relying entirely on individual developers happening to notice a security advisory — which, realistically, almost never happens at scale.

Direct vs. Transitive Dependencies

This distinction trips a lot of people up, so I want to be explicit about it:

The scary part is that most vulnerabilities live in transitive dependencies, not direct ones — because nobody chose them explicitly, nobody’s reviewing them either. A good dependency scanner surfaces the entire tree, not just the top level.

How Dependency Scanning Actually Works

  1. Resolve the dependency tree — the scanner reads your manifest and lock files to build a complete picture of every package and version in use, including transitive ones.
  2. Match against vulnerability databases — each package/version combination is checked against sources like the National Vulnerability Database (NVD), GitHub Advisory Database, or the Open Source Vulnerability database (OSV).
  3. Assign severity — findings are typically ranked using CVSS scores (Critical, High, Medium, Low).
  4. Suggest remediation — good tools tell you the minimum version bump needed to resolve the issue, not just that a problem exists.

Running a Dependency Scan: A Practical Example

Here’s a simple example using npm audit, which is built directly into Node’s package manager:

npm audit

Output typically looks something like:

found 12 vulnerabilities (2 low, 4 moderate, 5 high, 1 critical)
  run `npm audit fix` to fix 9 of them

For more comprehensive coverage across ecosystems, I typically reach for a dedicated SCA tool like Trivy or Grype instead of relying solely on built-in package manager auditing. I compare several of these in Top Software Composition Analysis (SCA) Tools.

# Trivy example, scanning the current directory
trivy fs .

Integrating Dependency Scanning Into CI/CD

The real value of dependency scanning comes from running it automatically on every build, not manually before a release. Here’s a GitHub Actions example that fails the build on critical or high severity findings:

name: Dependency Scan

on: [push, pull_request]

jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run Trivy scan
        run: |
          curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin
          trivy fs --exit-code 1 --severity CRITICAL,HIGH .

This turns dependency scanning into a hard gate — code with critical unpatched vulnerabilities simply doesn’t merge.

Dependency Scanning and SBOMs Work Together

Dependency scanning is far more effective when paired with a maintained SBOM, since the SBOM gives you a persistent inventory to re-check whenever a new vulnerability is disclosed, without re-scanning from scratch. See SBOM Explained for Beginners and How to Generate an SBOM Automatically for the setup side of this.

Scanning Container Images, Not Just Source Code

If you deploy via containers, scanning source dependencies alone misses OS-level packages baked into the base image. I always scan the final built image too:

docker build -t myapp:latest .
trivy image myapp:latest

This is especially important since container base images often carry outdated OS packages that source-level scans never see. For teams newer to this, Docker fundamentals and Kubernetes basics are worth reviewing alongside this practice.

Common Mistakes in Dependency Scanning

Best Practices Checklist

PracticeBenefit
Automate scanning in CI/CDContinuous, zero-effort coverage
Scan the full dependency treeCatches transitive vulnerabilities
Gate builds on critical/high findingsForces remediation before release
Scan both source and container imagesFull-stack coverage
Pair scanning with an SBOMFaster response to newly disclosed CVEs

FAQs

How is dependency scanning different from SBOM generation? An SBOM is the inventory — a list of what’s in your software. Dependency scanning is the action of checking that inventory against vulnerability databases to find actual security issues.

Does dependency scanning catch zero-day vulnerabilities? No. It can only detect vulnerabilities that have already been disclosed and added to a database. It won’t catch an unknown, undisclosed flaw.

How often should dependency scans run? Ideally on every commit or pull request, plus a scheduled daily or weekly scan to catch newly disclosed vulnerabilities in dependencies that haven’t changed.

What should I do when a scan flags a vulnerability with no available patch? Assess the actual exploitability in your context, consider mitigating controls (like network isolation), and evaluate whether an alternative package is viable if a fix isn’t imminent.

Conclusion

Dependency scanning is one of the highest-leverage security practices you can add to a pipeline, because it surfaces risk that would otherwise stay completely invisible until it’s exploited. Automate it, scan the full dependency tree including transitive packages and container images, gate your builds on serious findings, and pair it with a maintained SBOM. Once that loop is running continuously, vulnerable dependencies stop being a silent risk and start being a routine, manageable part of your workflow.

Exit mobile version