Safeguard
Open Source Security

How to set up software composition analysis (SCA)

A practical, step-by-step guide to setting up software composition analysis: choosing a tool, setting policy, and integrating scans into CI/CD.

Priya Mehta
DevSecOps Engineer
7 min read

Open source now makes up the majority of most application codebases, and every dependency you pull in is code you didn't write but are still responsible for securing. A single vulnerable transitive package — think Log4Shell or the xz-utils backdoor — can sit undetected for months until an attacker finds it first. If you're trying to set up software composition analysis for the first time, the goal is straightforward: get continuous, automated visibility into every open source component your applications use, know which ones carry known vulnerabilities or risky licenses, and catch problems before code ships rather than after. This guide walks through the practical steps — from scoping your dependency inventory to wiring scans into your build pipeline — so you end up with a working SCA program, not just a one-off scan report sitting in a folder no one reads.

Step 1: Scope What You Need to Set Up Software Composition Analysis Successfully

Before touching any tooling, define the boundaries of what you're scanning. Pull together a list of every repository, service, and build artifact that ships to production, including internal libraries that get consumed by other teams. For each one, note the language ecosystems in play (npm, PyPI, Maven, Go modules, RubyGems, container base images) because tool coverage varies significantly by ecosystem.

Also decide upfront what "risk" means for your organization. Most teams care about three things:

  • Known vulnerabilities (CVEs) in direct and transitive dependencies
  • License compliance (GPL, AGPL, or other copyleft licenses that create obligations)
  • Package provenance and supply chain integrity (typosquats, maintainer takeovers, malicious updates)

Writing this scope down matters because it drives every decision after it, including which tool you pick and what you set as a build-breaking threshold.

Step 2: Run an SCA Tool Comparison

There is no shortage of options, and an honest sca tool comparison will save you a painful tool migration six months in. Broadly, you're choosing between:

  • Open source scanners like OWASP Dependency-Check, Trivy, or Grype — free, good for CVE matching against public databases, but limited on license policy, remediation guidance, and prioritization signals like reachability or exploitability.
  • Commercial/platform SCA tools (Snyk, Safeguard, GitHub Advanced Security, Black Duck) — add dependency graphs, automated fix PRs, license policy engines, and integration with broader supply chain security programs like SBOM generation and SLSA attestation.

When comparing, test each candidate against your actual codebase rather than trusting vendor benchmarks. Things worth checking directly:

  • Does it resolve transitive dependencies accurately for your package managers?
  • Does it deduplicate and prioritize findings, or dump every CVE match regardless of exploitability?
  • Can it ingest a Software Bill of Materials (SBOM) you already generate, or does it force its own format?
  • How fast does the scan run at your repo size — this determines whether it can live in CI without slowing every PR?

For a quick local comparison, you can run the same repository through two open source scanners side by side:

# Trivy filesystem scan
trivy fs --severity HIGH,CRITICAL .

# Grype scan against the current directory
grype dir:.

Diff the output. You'll often find meaningful gaps in transitive resolution or CVE database freshness between tools — that gap is exactly what you're trying to surface before committing to one.

Step 3: Install and Run Your First Scan Locally

Once you've picked a tool, get a baseline scan running locally before you touch CI. This confirms the tool actually resolves your manifests correctly and gives you a sense of your current exposure.

For a Node.js project using the built-in ecosystem tooling:

npm audit --audit-level=high

For a broader, multi-ecosystem scan with Trivy:

trivy fs --scanners vuln,license --format table .

For Python:

pip install pip-audit
pip-audit -r requirements.txt

Run this against two or three representative repositories, not just your smallest one. You want to see how the tool behaves against a large monorepo with hundreds of transitive dependencies, since that's where scan time and noise become real problems.

Step 4: Set Policy Thresholds Before You Automate

This step gets skipped constantly, and it's why so many SCA rollouts get disabled within a month. If every scan fails the build on any medium-severity finding, engineers will bypass or mute the check within weeks. Before automating anything, define:

  • A severity threshold that blocks merges (commonly: fail on Critical, warn on High, ignore Low/Medium initially)
  • A grace period for newly discovered vulnerabilities in existing dependencies (e.g., 14 days to remediate a new Critical CVE in production code)
  • An exceptions process for false positives or accepted risk, with an expiry date on the exception

Most SCA tools support this as a policy file. A Trivy example that only fails on critical severity:

# trivy.yaml
severity:
  - CRITICAL
exit-code: 1
ignore-unfixed: true

Step 5: Wire SCA CI/CD Integration Into Your Pipeline

With policy defined, the scan needs to run automatically on every pull request and on a schedule against your default branch — sca ci/cd integration is what turns a one-time audit into an ongoing control. Here's a GitHub Actions example running Trivy on every PR:

name: SCA Scan
on:
  pull_request:
  schedule:
    - cron: '0 6 * * *'

jobs:
  sca:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run Trivy vulnerability scan
        uses: aquasecurity/trivy-action@master
        with:
          scan-type: 'fs'
          scan-ref: '.'
          severity: 'CRITICAL,HIGH'
          exit-code: '1'

For GitLab CI, the equivalent stage looks like:

sca_scan:
  stage: test
  image: aquasec/trivy:latest
  script:
    - trivy fs --severity CRITICAL,HIGH --exit-code 1 .
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"

Run the scan on pull requests to catch new dependency additions early, and again on a schedule against your main branch to catch newly disclosed CVEs in dependencies that were already merged and considered clean at the time.

Step 6: Triage and Route Findings to Owners

A pipeline that produces findings nobody looks at is not a working program. Route results to the team that owns the affected repository, not to a central security inbox that becomes a graveyard. Most SCA platforms support ticket creation (Jira, GitHub Issues) or Slack notifications tied to a repo's CODEOWNERS. Set an SLA per severity tier and track it — Critical in 48 hours, High in two weeks, and so on — the same way you'd track any other production incident class.

Verification and Troubleshooting

Once the pipeline is live, verify it actually catches something before trusting it:

  • Seed a known-vulnerable dependency in a test branch (an old lodash or log4j version works well) and confirm the pipeline flags it and blocks the merge as configured.
  • Check transitive resolution. If a scan reports zero findings on a large project, that's a red flag, not good news — confirm the tool is actually walking your full lockfile (package-lock.json, poetry.lock, go.sum) rather than only top-level manifests.
  • Watch scan duration. If CI scan time creeps past a few minutes, cache the vulnerability database locally (trivy image --download-db-only) rather than re-downloading it on every run.
  • Audit false-positive volume monthly. If more than a small fraction of findings are dismissed as not applicable, revisit your severity thresholds or consider a tool with better reachability analysis, which filters out vulnerabilities in code paths that are never actually called.
  • Confirm license scanning is actually enabled — it's often a separate flag or module from vulnerability scanning and gets missed during initial setup.

How Safeguard Helps

Safeguard builds open source dependency scanning directly into a broader software supply chain security platform, so SCA isn't a bolted-on step disconnected from everything else you're already tracking. Instead of just a CVE list, Safeguard correlates dependency findings with SBOM data, build provenance, and package reputation signals to tell you which vulnerabilities are actually reachable in your running code — cutting through the noise that causes most SCA rollouts to get muted. Policy thresholds, exception workflows, and CI/CD gating are configurable per repository out of the box, and results route straight to the owning team with context instead of a raw CVE ID. If you're evaluating how to set up software composition analysis at scale across dozens or hundreds of repositories, Safeguard is built to get that program running in days rather than the months it typically takes to stitch together open source tools and internal policy engines by hand.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.