Safeguard
Open Source Security

How Snyk Container parses apk, deb, and rpm package datab...

How Snyk Container reads apk, dpkg, and rpm databases inside image layers to detect OS package vulnerabilities without ever running the container.

Nayan Dey
Security Researcher
7 min read

A container image that says "python:3.11-slim" or "node:20-alpine" is really a stack of filesystem layers containing hundreds of OS packages that nobody explicitly asked for. Snyk Container's job is to figure out exactly which packages are in there, at which versions, without ever booting the container. It does this by pulling the image manifest and layers, statically extracting the filesystem, detecting which Linux distribution family produced it, and then reading that distribution's native package database directly off disk — Alpine's apk database, Debian/Ubuntu's dpkg status file, or the RPM database used by RHEL, CentOS, Fedora, and Amazon Linux. Each format stores package name, version, and architecture differently, so Snyk maintains a distinct parser per ecosystem before matching the results against its vulnerability feeds. Here is how that pipeline actually works.

What does Snyk Container actually scan inside an image?

It scans the package manager's own metadata files, not the binaries themselves. When Snyk Container (built on the snyk-docker-plugin, which Snyk has published as an open-source Apache-2.0 project on GitHub) analyzes an image, it pulls the layers via the registry or a local Docker/OCI daemon, flattens them into a single filesystem view, and looks for a small, fixed set of well-known file paths: /lib/apk/db/installed for Alpine, /var/lib/dpkg/status (plus the /var/lib/dpkg/status.d/ directory used by some minimal images) for Debian-family systems, and /var/lib/rpm/Packages or /var/lib/rpm/rpmdb.sqlite for RPM-based systems. Because this is static analysis of files that already exist inside the built image, no package manager command has to run and no container has to start — which matters for CI pipelines scanning thousands of images where spinning up each one would be far too slow.

How does Snyk decide which parser to use on a given image?

It fingerprints the base OS before it ever touches package data, typically by reading /etc/os-release (or fallback files like /etc/alpine-release, /etc/debian_version, or /etc/redhat-release on older images that predate the systemd-standardized os-release format). That file identifies the distribution ID and version — for example ID=alpine and VERSION_ID=3.19, or ID=ubuntu and VERSION_ID=22.04 — which tells Snyk both which parser to invoke and which vulnerability feed to match against, since the same package name can carry different patched versions across Alpine 3.18, 3.19, and 3.20, or across Ubuntu 20.04 and 22.04. Images with no recognizable OS release file at all, such as Google's distroless images or scratch-based builds, get routed to a different code path that looks for language-level dependency artifacts instead, since there is no OS package database to parse.

How does apk database parsing work on Alpine images?

Alpine's apk database is a flat, human-readable text file at /lib/apk/db/installed, and Snyk parses it as a sequence of newline-delimited key-value records grouped into blocks separated by blank lines. Each block describes one installed package using single-letter field prefixes — P: for the package name, V: for the installed version, A: for architecture, and o: for the origin package a subpackage was built from (relevant because Alpine splits things like openssl into openssl and libssl3, and a CVE fix might land in the origin package rather than the subpackage name shown in the manifest). Version strings follow Alpine's own comparison syntax, such as 3.1.4-r0, where the -rN suffix is a package-level revision independent of the upstream version — so accurately parsing that suffix is required to correctly determine whether an installed 3.1.4-r0 is older or newer than a fixed 3.1.4-r1.

How does Snyk parse dpkg status files on Debian and Ubuntu?

The dpkg status file uses RFC 822-style stanzas, and Snyk reads it as a series of Field: value pairs separated by blank lines, extracting Package:, Version:, Status:, and Source: for each entry. The Status: field matters because dpkg keeps records for packages that were removed but not purged (deinstall ok config-files), and Snyk has to filter those out so a package that's no longer actually present doesn't show up as a live vulnerability. Debian versions add real complexity: a version string like 1:2.4.49-2ubuntu1.11 has three parts — an epoch (1:), an upstream version (2.4.49), and a Debian/Ubuntu revision (-2ubuntu1.11) — and Debian's comparison rules (letters sort before the empty string, tildes sort before anything, digits compare numerically rather than lexically) are distinct enough from semantic versioning that a naive string comparison would misjudge whether a security patch has actually been applied.

How does RPM database parsing differ from apk and dpkg?

The main difference is that RPM's package database is a binary key-value store rather than plain text, which is why it needs a dedicated reader instead of a line-by-line text parser. Historically RPM used Berkeley DB format at /var/lib/rpm/Packages, but newer distributions have moved away from it — Fedora switched its default to the NDB format in Fedora 36 (2022), and RHEL 9 and recent Fedora releases default to SQLite at /var/lib/rpm/rpmdb.sqlite, so a parser that only understood the old Berkeley DB layout would silently miss packages on current RHEL-family images. Each installed package record in any of these formats stores a header of name, version, release, epoch, and architecture (for example httpd-2.4.57-2.el9.x86_64), and RPM's release field (-2.el9 in that example) plays a role similar to Alpine's -rN revision — it can carry a backported security fix without bumping the upstream version number at all, which is common practice for RHEL and Amazon Linux, where vendors backport patches into an older upstream version rather than rebasing to the latest release.

How does Snyk match a parsed package list to known CVEs?

It compares each extracted name-and-version pair against Snyk's own vulnerability database, which aggregates advisories from the upstream security trackers for each distribution — the Debian Security Tracker and Ubuntu Security Notices for dpkg-based images, Alpine's secdb feeds for apk-based images, and Red Hat's OVAL/errata data (also consumed by CentOS, Rocky, and Amazon Linux through their own downstream advisories) for RPM-based images — supplemented by Snyk's own security research team. Because OS vendors frequently backport fixes rather than shipping the latest upstream release, matching on the raw semantic version alone would produce false positives; Snyk instead relies on the vendor's own fixed-version metadata for that specific distro release, which is also why the same CVE can show as "fixed" on Ubuntu 22.04 but "vulnerable" on Debian 11 at what looks like an identical package version string. Snyk Container also attributes each finding back to the Dockerfile layer or base image where the package was introduced, so a finding in a 4-layer custom image built on debian:12-slim can be traced to whether the vulnerable package came from the base image or from a later RUN apt-get install step.

How Safeguard Helps

Understanding how a scanner like Snyk Container parses OS package databases is useful precisely because it shows both the strength and the boundary of that approach: it's excellent at telling you what's installed and whether a known CVE applies to that exact version, but it depends entirely on the accuracy and freshness of the package database it reads and the advisory feeds it matches against. Safeguard focuses on the layer above and around that scan — verifying that the artifacts flowing through your build and registry pipeline are what they claim to be, tracking build provenance so a package's origin is attributable beyond just its name and version string, and giving security teams a single place to correlate OS-level vulnerability findings from tools like Snyk with SBOM data, dependency provenance, and policy gates before an image is ever promoted to production. Rather than replacing OS vulnerability scanning, Safeguard makes the signal it produces more trustworthy and actionable across the rest of the software supply chain — from source commit to registry to runtime — so teams get full visibility into not just which packages are vulnerable, but how they got there and whether they should have been allowed to.

Never miss an update

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