Join our Newsletter — 33% off our NHI Course
Home› Guides› Container Image Scanning vs SCA: Where They Overlap…
Guide Application Security

Container Image Scanning vs SCA: Where They Overlap and When You Need Both

← All guides
By NHI Mgmt Group, edited by Lalit Choda Updated 14 November 2026 15 min read
On this page

Teams that run both an image scanner and a software composition analysis (SCA) tool usually get the same CVE reported twice by two tools in two queues, while the gaps between the tools go unnoticed. Image scanning reads what is installed inside a built container image: operating system packages from the base, language runtimes and the application packages that ended up on disk. SCA reads what the source repository declares and resolves: manifests and lockfiles, before anything is built. They overlap on application dependencies and diverge everywhere else, including what they can see, when they run, how they prioritise and what they miss at runtime. This guide compares the two on coverage, reachability, pipeline timing, false positives and runtime drift, then shows how to deduplicate findings and decide when one tool is enough. It is for application security, platform and DevSecOps engineers who own the CI pipeline. Image scanning operations are covered in the Container Image Vulnerability Management Guide and SCA mechanics in the Software Composition Analysis (SCA) Guide; this page covers how the two fit together. Open source tools are named only to illustrate documented behaviour (Grype, govulncheck, OSV-Scanner, Syft and Trivy, listed alphabetically); naming is not a recommendation.

Key takeaways

  • They read different evidence. SCA reads pre-build files such as package-lock.json and go.mod; image scanners read post-build evidence such as installed package metadata, JARs and Go binaries, plus the OS package database.
  • Only the image scanner sees the base. OS packages inherited from the base image (glibc, OpenSSL, zlib) never appear in a repository manifest, so SCA alone cannot report them.
  • Only SCA sees the source context. Lockfiles, dev dependencies, pull request diffs and code-level reachability live in the repository, where developers can fix them before a build.
  • Deduplicate on package identity, not on CVE. Key findings on package URL, version and CVE, attribute each to an owner (base, runtime layer or application) and send it to one queue.
  • Neither covers runtime drift. Packages installed into a running container, images pulled outside the pipeline and old digests still running need runtime inventory and admission controls.

The short answer

If you ship software as containers, you need image scanning, because it is the only one of the two that sees the operating system layer and what actually landed in the artefact. You also want SCA in the repository, because it finds dependency problems at pull request time, with the lockfile and code context a developer needs to fix them. One tool can be enough when the image is built from scratch or a minimal base and contains only a single compiled binary that the image scanner can read, or when the team is small and a single scanner covers both the repository and the image. In every other case, run both and design the overlap deliberately: SCA owns application dependencies before merge, the image scanner owns the base and runtime layers after build, and both feed one deduplicated backlog.

What each one sees

The clearest statement of the difference comes from scanner documentation itself. Trivy's language coverage page splits targets into pre-build (a code repository, where it analyses lock files) and post-build (a container image, where it analyses installed package metadata and binaries). Its coverage table shows the effect:

Evidence fileRead in repository (SCA view)Read in image (image scan view)
package-lock.json (Node.js)YesNo: installed package.json files are read instead
go.mod (Go)YesNo: Go binaries with embedded module information are read instead
requirements.txt, poetry.lock (Python)YesNo: installed egg and wheel metadata are read instead
Gemfile.lock (Ruby)YesNo: installed gemspec files are read instead
JAR, WAR, EAR (Java)NoYes
Cargo.lock (Rust)YesYes; Rust binaries are read only if built with cargo-auditable
OS package database (dpkg, rpm, apk)NoYes

Three consequences follow. First, a build that fetches dependencies outside the lockfile, vendors code or copies in a prebuilt binary produces packages SCA never saw. Second, a multi-stage build discards everything not copied into the final stage: Docker's documentation describes the final image as containing only what the last stage includes, so dev dependencies and build tools flagged by SCA may not ship at all. Third, some software is invisible to both. Trivy's documentation states that it does not support third-party or self-compiled binaries, skips packages with unspecified versions unless a lockfile supplies them, and does not check files installed by an OS package manager (such as a JAR installed through apt) against upstream language advisories.

The image scanner's view

An image scanner unpacks the layers and reads the OS package database, then looks for language artefacts on disk. For OS packages it should use the distribution's own advisories: Trivy documents sources including the Debian Security Bug Tracker, Ubuntu CVE Tracker, Red Hat OVAL, Alpine secdb and Amazon Linux ALAS, because vendors backport fixes without changing the upstream version. Matching OS packages against upstream versions alone produces the false positives covered in the Backported Security Fixes Guide. Image scanners can also attribute each package to a layer: OSV-Scanner's image output includes "IN BASE IMAGE" and "INTRODUCED LAYER" columns, which is the data you need to route a finding to the platform team or the application team. MITRE D3FEND names this defensive technique Container Image Analysis; see D3-CIA Container Image Analysis.

The SCA view

SCA resolves the dependency tree from manifests and lockfiles, ideally including transitive dependencies, and runs where developers work: on the pull request, in the IDE and on a schedule against the default branch. It knows which manifest declared a package, whether it is a direct or transitive dependency, whether it is a dev or test dependency, and which line to change. Repository-native tools work the same way: GitHub's Dependabot documentation says updates can be configured for repositories that contain a dependency manifest or lock file for a supported package manager, and its docker ecosystem keeps image tags current, including tags in Kubernetes manifests. That keeps base image references fresh, but it does not inspect the contents of the image.

Side-by-side comparison

DimensionContainer image scanningSCA (repository)
InputBuilt image layers (or an SBOM generated from them)Manifests, lockfiles, sometimes source code
OS packages from base imageYes, against distribution advisoriesNo
Application dependenciesWhat was installed in the final imageWhat was declared and resolved, including dev and test
Pipeline timingAfter build, on push to registry, continuous registry rescanPull request, merge, scheduled rescan
Fix contextLayer and base image; developer must trace to sourceManifest file and line; automated pull requests
ReachabilityPackage presence; binary symbol analysis for some languagesCall graph analysis where the tool supports it
Main false positive sourceBackported OS fixes; packages present but unusedDev dependencies and packages that never ship
OwnerPlatform team for base, application team for app layerApplication team
Runtime relevanceHigh: scans the artefact that runsIndirect: scans the intent, not the artefact

Reachability: where precision comes from

Most findings in both tools are "the vulnerable version is present", not "the vulnerable code can run". The two tools approach reachability from different evidence.

  • Source call graph (SCA side): the Go project's govulncheck analyses the call graph and reports only vulnerabilities where your code transitively calls a vulnerable function, using a database that records affected symbols. Its documentation lists limits: calls made through reflection are invisible, the unsafe package may cause false negatives, and interface calls are analysed conservatively.
  • Binary symbols (image side): the same tool's binary mode reads the symbol table of a compiled binary. The documentation says this is less precise: it cannot show call stacks, may report code that is present but unreachable, and falls back to reporting every dependency module when symbol information cannot be extracted.
  • Presence only: for OS packages, the practical reachability questions are whether the package is in the final image at all, whether the vulnerable feature is used, and whether the workload is exposed. Record the answer as a VEX statement rather than a local ignore; see the VEX Guide and the Reachability Analysis Guide.

The practical rule: use source reachability to deprioritise application findings before merge, and use image presence plus runtime exposure to prioritise OS and runtime findings after build. Neither replaces exploitation signals such as CISA KEV listing and EPSS.

Timing in the pipeline

StageToolWhat to gate onWhy here
Pull requestSCANew critical or KEV-listed dependency findings introduced by the diff; malicious package advisoriesCheapest point to fix; developer has context
BuildImage scanner plus SBOM generationNew findings in the built image above policy thresholdFirst time the real artefact exists
RegistryImage scanner (continuous rescan)Newly published CVEs in stored imagesCatches disclosures after build
DeployAdmission controlUnscanned or out-of-policy digestsStops images that bypassed the pipeline
RuntimeRuntime inventoryVulnerable digests actually running, by exposureTurns findings into a deployed-risk view

Generate the SBOM once at build time from the final image and store it with the digest. Syft generates SBOMs in CycloneDX and SPDX formats from images, filesystems and archives, and can create signed SBOM attestations using the in-toto specification; Grype can scan an SBOM instead of the image. Rescanning the stored SBOM against fresh vulnerability data is faster than pulling every image again. See the SBOM vs SCA guide for the inventory side. Admission policies are covered in the Kubernetes Admission Control Guide.

Deduplication and ownership

When both tools report the same CVE in the same application package, you have one problem and one owner. When the image scanner reports a CVE in an OS package, the owner is usually the platform team. Build the merge logic around this:

  1. Normalise identity: map every finding to a package URL (purl), version and vulnerability ID, with aliases (CVE, GHSA, OSV) resolved to one record.
  2. Attribute layer: tag each finding as base image, runtime layer (interpreter, JRE) or application, using the layer attribution from the image scanner and the manifest path from SCA.
  3. Collapse duplicates: where SCA and image findings share purl, version and vulnerability, keep one record, link both sources, and route it to the application repository where the fix belongs.
  4. Drop what does not ship: SCA findings in dev or test dependencies that the image scan confirms are absent from the final image can be downgraded, with the evidence recorded.
  5. Flag the gaps: packages in the image with no SCA record (vendored, fetched at build, copied binaries) and SCA packages missing from the image both indicate a build process the team does not fully understand.
  6. Fix once, at the lowest layer: a base image CVE across 200 services is one platform ticket and an automated rebuild, not 200 application tickets.

Runtime drift: what both miss

Both tools assess an artefact at a point in time. Production can diverge from it in ways neither sees:

  • In-container changes: a package installed with a package manager inside a running container, or a file written by a compromised process, is not in the scanned image. Setting the Kubernetes container securityContext field readOnlyRootFilesystem to true, with writable volumes only where needed, reduces this drift. See the Container Runtime Security Guide.
  • Images outside the pipeline: public images deployed directly, sidecars injected by operators and third-party Helm charts never pass your CI scanners. ATT&CK tracks adversary use of Deploy Container (T1610); admission control is the matching defensive gate.
  • Stale digests: a fixed image in the registry does not help if an old digest still runs in a forgotten namespace. Runtime inventory has to map running digests back to scan results.
  • Disclosure after deployment: a CVE published today affects images scanned clean last month. Continuous registry or SBOM rescanning closes this gap.

Where identity fits

Every stage above uses machine credentials: CI tokens that pull dependencies and push images, registry credentials used by scanners and clusters, and the signing keys behind SBOM attestations. A scanner with write access to the registry or broad repository scope is a high value non-human identity. Scope scanner credentials to read access, keep signing keys in a managed store and rotate CI tokens. The supply chain worms that harvested publishing tokens show why: see the Software Supply Chain Security Guide.

Decision criteria

SituationRecommended approach
Containerised services on a full distribution base (Debian, Ubuntu, RHEL family)Both: image scanning for the OS layer, SCA for pull request gating
Single static binary on scratch or a minimal baseImage or binary scan may suffice if the scanner can read the binary's embedded module data; keep SCA if you want pull request feedback
Libraries and SDKs published to package registries, no imagesSCA only
Third-party images you deploy but do not buildImage scanning, plus admission control
Small team, one scanner that covers repositories and imagesOne tool in two modes, with one backlog
Regulated product needing an SBOM per releaseBoth, with the SBOM generated from the final image and SCA evidence for the development process

Worked scenario: a Python API on a Debian base

A team ships a Python API in an image built from a Debian slim base with a multi-stage build. SCA on the repository reports 41 findings across requirements files; the image scanner reports 63 on the final image.

  • Overlap: 18 findings are the same purl, version and CVE in both. They collapse to 18 records owned by the application team, fixed by lockfile updates.
  • SCA only: 23 findings are in test and lint dependencies. The image scan confirms none are installed in the final stage; they are downgraded with that evidence.
  • Image only, OS layer: 39 findings are in Debian packages. Checked against Debian's own advisories, several are fixed by backports or marked unimportant. The remainder go to the platform team as one base image rebuild.
  • Image only, application layer: 6 findings are in a wheel the Dockerfile installs directly with pip, outside the requirements file. The team moves it into the lockfile so SCA sees it next time.

The result is 18 application tickets, one base image rebuild and one build fix, instead of 104 alerts in two queues.

Detection and measurement

  • Duplicate rate: share of findings reported by both tools that are collapsed into one record (should approach 100 percent of true overlaps).
  • Coverage gap count: packages present in the image with no SCA record, by repository; trend towards zero.
  • Base image rebuild latency: time from a fixed base digest being available to all dependent images running it.
  • Running-vulnerable digests: number of running digests with KEV-listed or critical findings, from runtime inventory.
  • Unscanned admissions: deployments admitted without a scan result, which should be zero where admission control is enforced.

Common failure patterns

  • Two queues, one problem: developers receive the same CVE from two tools with different severities and close both as noise.
  • SCA-only container programmes: no image scanning, so base image vulnerabilities are never reported. When the XZ Utils backdoor (CVE-2024-3094) was disclosed, the affected liblzma versions were OS packages from development and rolling distribution releases, which only an OS-aware image or host scan would list.
  • Upstream matching of OS packages: treating distribution packages as upstream versions, producing backport false positives that bury real findings.
  • Treating CVE scanning as malware defence: neither tool's CVE matching catches a freshly trojanised package. The Shai-Hulud npm worm ran through a preinstall script on install, before any image existed; malicious package advisories and install-time controls are needed in SCA.
  • Scan once, never again: gating at build and never rescanning the registry or SBOM, so newly disclosed CVEs in running images go unreported.
  • Ignoring copied binaries: downloading a tool with curl in the Dockerfile, which neither SCA nor the image scanner can identify reliably.

Framework mapping

FrameworkReferenceHow the two tools contribute
NIST SP 800-53 Rev. 5RA-5 Vulnerability Monitoring and Scanning; SI-2 Flaw Remediation; CM-8 System Component Inventory; SA-11 Developer Testing and EvaluationImage scanning and SCA both implement RA-5; SBOMs support CM-8; SCA in pull requests supports SA-11
NIST CSF 2.0ID.RA-01; PR.PS-02Identify and record vulnerabilities; maintain and replace software by risk
CIS Controls v8.1Control 7 Continuous Vulnerability Management; Control 16 Application Software SecurityImage scanning under 7, SCA and third-party component management under 16
MITRE ATT&CKT1195.001 Compromise Software Dependencies and Development Tools; T1610 Deploy ContainerSCA and malware advisories address dependency compromise; admission control addresses unscanned container deployment
MITRE D3FENDD3-CIA Container Image AnalysisThe defensive technique image scanners implement
NIST SP 800-190Application Container Security GuideImage vulnerabilities as a risk of the image itself

Practitioner checklist

  • Run SCA on every pull request and image scanning on every built image; do not drop either for containerised services on a full distribution base.
  • Configure the image scanner to use distribution advisories for OS packages.
  • Generate an SBOM from the final image at build, attest it and store it with the digest.
  • Normalise findings to purl, version and vulnerability ID and merge them into one backlog.
  • Route base image findings to the platform team as rebuilds, application findings to repositories.
  • Rescan stored images or SBOMs continuously against new vulnerability data.
  • Enforce admission control for unscanned or out-of-policy digests and map running digests to findings.
  • Remove ad hoc downloads from Dockerfiles so every component is declared and scannable.

Standards and references

Related NHI Mgmt Group resources: Container Image Security Guide · Container Security Guide · Container Image Vulnerability Management Guide · Software Composition Analysis (SCA) Guide · SBOM Guide

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Researched and written by the NHI Mgmt Group editorial team using AI tools, under the editorial direction of Lalit Choda. Facts are drawn from the sources listed on this page and checked by our automated quality process. Last updated 14 November 2026. Spotted an error? Use our contact page.
NHI Mgmt Group, the independent authority on Non-Human Identity, IAM and Agentic AI security. nhimg.org