Snyk Container Image Scanning: Find and Fix CVEs
Snyk Container’s primary function is to discover and report Common Vulnerabilities and Exposures (CVEs) within your container images, and then guide you on how to fix them.
Here’s how it works in action. Imagine you have a Dockerfile that builds an image for a Node.js application.
FROM node:18-alpine
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
CMD ["npm", "start"]
After building this image, you’d run Snyk to scan it:
snyk container test --file=Dockerfile --exclude-app-dependencies
Snyk will then analyze the layers of your image, identify the base image and installed packages, and cross-reference them against its vulnerability database. The output might look something like this:
Testing ./Dockerfile...
✗ High severity vulnerability found in node:18-alpine
CVE-2023-XXXX
Description: A buffer overflow vulnerability in the libxml2 library...
Info: https://snyk.io/vuln/SNYK-UBUNTU-LIBC6-XXXXXX
Introduced through: node:18-alpine@18.18.0 (via libc6)
From: node:18-alpine@18.18.0
Remediation: Upgrade node:18-alpine to a newer version. See method below for details.
[... more vulnerabilities ...]
Organization: my-org
Package manager: Docker
The core problem Snyk Container solves is the blind spot containerized applications create. Unlike traditional applications where package managers explicitly list dependencies, a container image is a filesystem snapshot. You might know your app’s Node.js version, but what about the C library it’s built on, or the OpenSSL version shipped with the Alpine base image? These hidden dependencies are prime real estate for vulnerabilities. Snyk Container unpacks this complexity, treating the entire image as a dependency tree.
The snyk container test command is your entry point. It takes the image (either by reference or by analyzing a Dockerfile) and performs a multi-stage analysis. First, it identifies the operating system and its package manager (e.g., apk for Alpine, apt for Debian/Ubuntu). Then, it enumerates all installed packages and their versions. For each package, it checks for known CVEs. Crucially, it also analyzes application-level dependencies if you omit the --exclude-app-dependencies flag, by looking for package.json, pom.xml, requirements.txt, etc., within the image.
The "Introduced through" and "From" fields in the Snyk output are key to understanding the fix. They tell you how a vulnerable package ended up in your image. In the example above, libc6 (a fundamental C library) was brought in by the node:18-alpine base image. This means updating your Node.js version is the most direct path to a fix.
To remediate the CVE-2023-XXXX in the example, you’d typically update your base image. For an Alpine-based Node.js image, this means pulling a newer version of node:18-alpine.
# Update the base image tag to a newer, patched version
FROM node:18.19.0-alpine # Example: updated to a specific patched version
After updating the Dockerfile, you rebuild the image and re-scan. Snyk will then confirm if the vulnerability is gone. If the vulnerability was introduced by a package installed via the OS package manager (e.g., RUN apk add --no-cache some-package), you’d update that specific package:
# Example for an OS package update
RUN apk update && apk upgrade some-package && rm -rf /var/cache/apk/*
And if it was an application dependency (e.g., a vulnerable npm package), you’d update package.json and run npm install (or npm ci if you’re using package-lock.json for reproducibility) within your build process.
The --exclude-app-dependencies flag is useful when you only want to focus on the OS and base image vulnerabilities, often during initial image hardening or when you have a separate process for managing application dependencies. Omitting it allows Snyk to perform a more comprehensive scan, including your application’s direct and transitive dependencies.
The power of Snyk Container lies in its ability to map abstract software components to concrete, exploitable vulnerabilities. It doesn’t just list packages; it understands the entire lineage of code within an image, from the OS kernel up to your application’s libraries, giving you a clear path to security.
A common point of confusion is when Snyk reports a vulnerability in a package that’s part of a multi-stage build or a build tool. Snyk analyzes the final runtime image, so packages present only in intermediate build stages are typically ignored. However, if a build tool itself has a vulnerability that affects the final image’s integrity or runtime, Snyk will flag it.
The next step after ensuring your images are secure is to integrate this scanning into your CI/CD pipeline to catch vulnerabilities before they reach production.