Setting up Docker image scanning with Grype/Syft

Vulnerabilities in image base layers often survive until release and surface only in production. We set up turnkey Docker image scanning with Grype: we analyze the registry, embed checks into the build pipeline, and define blocking thresholds. The share of unscanned images drops severalfold.

Our competencies:

Frequently Asked Questions

Latest works

  • Development of a web application for FEEDME
    Development of a web application for FEEDME
    1359
  • Development of an online store for the company FURNORO
    Development of an online store for the company FURNORO
    1330
  • B2B Advance company logo design
    B2B Advance company logo design
    776
  • Development of a web application for Enviok
    Development of a web application for Enviok
    1077
  • AIDER company logo development
    AIDER company logo development
    1022
  • CRM development for Chasseurs
    CRM development for Chasseurs
    1113

Scanning images with Grype: where vulnerabilities are lost

Image analysis proceeds layer by layer, and the base layer is almost always fixed at build time. Syft captures an inventory — a list of operating system packages and application dependencies with their versions.

Using this list, Grype matches versions against vulnerability databases and returns findings with severity scores and an indication of the layer they came from.

The gap arises between build and rebuild. The application is updated every release, while system libraries in the base layer remain unchanged for months.

The vulnerability has already been published, the database has been updated, but the image still contains the previous version of the package — and container scanning at deployment does not show it if it runs against the finished image rather than at the build stage.

The second loss point is filters. Filtering by severity level or disabling checks for an outdated base layer removes noise, but at the same time hides the most common class of findings: high impact with a low formal score.

The third is the result format. A flat list is convenient to read and useless for management: it is impossible to see whether a finding repeats from release to release and whether it was closed after an update.

A component inventory ties each entry to a specific package and layer, so it is clear what exactly needs to be updated.

We break down this path step by step: inventory capture, threshold configuration, automatic rebuild of base layers — and show exactly where vulnerabilities in images are lost.

What regular Docker image scanning provides

Automated scanning at the build stage turns container security from a manual check before release into a standard pipeline step.

The tool parses image layers, compares packages and their versions against vulnerability databases, and returns findings before the image reaches the registry. Below are three effects visible after just two or three releases.

The vulnerability window shrinks to one build cycle

While an image sits in the registry and is not rebuilt, a vulnerability in it lives for months: the finding is discovered during the next audit or after an incident review.

With scanning at build time and on a schedule, the time from vulnerability publication to its closure in the production environment drops from weeks to one or two cycles — usually within a day.

Manual release acceptance goes away

A policy based on severity levels (“critical — stop the build, high — warning and record in the report”) provides a formal verdict instead of eyeballing the list.

The release either passes or fails with an indication of the specific package and layer — acceptance stops being a bottleneck and no longer depends on who is on duty today.

A unified list of findings across all registries

Scanning all repositories with a single configuration provides a unified report format and a single threshold.

It is clear whether a vulnerability came from the base layer or from application dependencies: it is clear who fixes it — the base image maintenance team or the developer. Base layer control becomes regular rather than one-off.

We configure Grype together with generating the image component inventory — using it, findings can be rechecked and compared between releases.

Approaches to image scanning: comparing options

A single scanning mode almost always leaves a hole. Build-time scanning knows nothing about what has been running in the cluster for weeks, while a regular sweep of deployed images will not stop the deployment of a vulnerable build.

The reason is asymmetry: an image is built once, while the database of known vulnerabilities is updated daily — yesterday's clean image contains problems today.

Below are four modes that are actually chosen between, and the boundaries of applicability for each.

Scanning mode When it fits Limitations
At build time, blocking New services and active development; need to prevent vulnerabilities from moving further through the pipeline Catches only what is known at build time; false positives slow down releases if the threshold is strict
Before deployment, by manifest Regular releases to multiple environments; need control at the entrance to production Requires registry access and rights to stop deployment; does not cover images deployed bypassing the pipeline
Periodic sweep of deployed images Existing running environment, long-lived services, compliance requirements Does not prevent — only records; requires triage of findings and an update plan
Checking against a saved component inventory Closed environments without access to images; retrospective incident analysis The inventory must be generated in advance and stored with the release

In practice, the modes do not compete but complement each other: blocking scanning at build time cuts off obvious defects, periodic scanning surfaces what became vulnerable after deployment, and a saved component inventory lets you answer in minutes the question “where else does this library appear” when a critical advisory is issued for it.

Grype and Syft work with the same component inventory, so all modes rely on a single source of truth rather than three inconsistent reports.

Implementing Grype in the image build pipeline: work stages

We embed image scanning into the build pipeline rather than running it as a separate scheduled job: the check occurs before the image is published to the registry, otherwise the defect is already in production.

Syft collects the package composition by layers, Grype compares it against vulnerability databases, and the build receives a return code that determines whether to let the image proceed or stop it.

The work order is structured so that by the time blocking is enabled, the team understands every trigger.

  1. Image inventory. We collect a list of services, base layers, and external dependencies — without it, blocking thresholds are set at random and stop the build on the first change.
  2. Integration scheme. We determine the call point in the pipeline (after build, before publication), the method for storing reports and a local mirror of vulnerability databases, and behavior on nodes without external network access.
  3. Grype configuration. We define the set of vulnerability sources, output formats — human-readable for logs, machine-readable for triage — and exceptions for clearly inapplicable triggers with a review date.
  4. Blocking thresholds and security policies. We separate severity levels: the build fails on vulnerabilities with an available fix and high risk, while the rest goes to the report and the remediation queue. We calibrate thresholds against the actual image composition so as not to get a wall of false stops.
  5. Testing on production builds. We run it on existing services: we measure the time added by the step, the share of triggers, and the cost of maintaining databases in a closed environment.
  6. Handover of procedures. We provide policy descriptions, instructions for triaging triggers, and the procedure for a stopped build — the team changes thresholds and exceptions independently.

After handover, we provide support: database updates, exception reviews, and threshold adjustments as the service composition changes.

Scanning policies, procedures, and blocking thresholds

Scanning without procedures quickly becomes background noise: reports are generated, findings accumulate, and decisions on them are made anew each time.

By the time Grype is enabled in the pipeline, the team receives a package of artifacts where each rule has an owner, a deadline, and a clear way to challenge it — otherwise the first build block teaches engineers to bypass the check rather than fix the cause.

  • Scanning configuration: a policy file with thresholds by severity level, a list of scanned layers, and an operating mode for each branch — where a warning is sufficient and where the build stops.
  • Priority matrix: which findings are closed in the next release, which go into the planned order, and which can be accepted as a known risk.
  • Vulnerability exception list: each entry with justification, owner, and review date — an exception stops being permanent and automatically returns to work.
  • Response procedures: who receives the notification, within what time they confirm the finding, how a fixed image is released, and under what conditions the block is lifted.
  • Scanning documentation: where the image composition captured by Syft is stored, how to reproduce the check locally with the same rules, and how to read the report during incident analysis.
  • Image reporting: a summary by repositories and tags — the share of images without critical findings, week-over-week dynamics, and a list of overdue exceptions.
  • Review procedure: scheduled review of thresholds and exceptions, as well as unscheduled — after a base image change or the appearance of a fix from the component vendor.
  • Roles and escalation point: who owns the policy and who makes the decision when a finding conflicts with the release deadline.

Such a package remains with the team, not the contractor: the check can be rerun, thresholds justified, and any exception removed with a single configuration edit.

Case study: reduced the share of unchecked images severalfold

Before the work, images were built manually, and scanning was run sporadically — usually before a major release. The registry grew faster than anyone could review its contents, and findings surfaced already in production: after an incident or a request.

What it was like before implementation

A baseline measurement gave concrete numbers: about a tenth of images were under regular scanning, while the rest lived in the registry without control.

The response time to a new vulnerability in a used package was measured in weeks, and determining which image contained the problematic library required manual analysis.

What we changed

Two steps were added to the build pipeline. Syft parses the image into a list of packages with versions, Grype compares this list against vulnerability databases and returns findings with a severity level.

The report became a mandatory artifact: without it, the image does not reach the registry, and critical findings block promotion to the production environment. We separately ran through the accumulated registry — old findings were triaged by priority rather than “someday”.

What the result was

The share of unchecked images dropped to a few percent — only local builds that never leave developers' machines remain outside control. The response time to a critical finding shrank to hours: it arrives with the build result rather than after a production incident.

Security metrics are collected automatically, and registry growth no longer means growth of the blind spot.

How does layer scanning differ from file system checking?

An image is not a monolithic snapshot but a stack of layers: each adds to or overlays the files of the previous one.

Layer scanning reads the manifest and the collected package inventory, so it sees which package manager installed the component, in which layer it appeared, and what pulled it in as a transitive dependency. The answer comes with provenance, not just a version number.

Checking the container file system works with what is actually mounted and available to the process: unpacked binaries, libraries, files placed by copying bypassing the package manager.

But it does not know the lineage — from a finding, it is not visible which layer it came from or whether it was updated later.

The difference between approaches is visible in two classes of errors. Layer checking will show a component from a lower layer even if a higher layer replaced or deleted it — a version that no longer exists surfaces in the report.

The file system does not account for deletion markers and describes the final state, but it misses everything that did not make it into the running container.

Therefore, coverage is assembled from two sources: the package inventory is generated by layers at build time, and the finished file system is checked afterward — as insurance against manual copying and unpacking.

Grype matches findings against the vulnerability database, but the completeness of the report depends on what the inventory was collected with and from which source — the whole image, a directory, or a separate layer. We configure both modes and separate findings so the report does not drown in false positives.

Technical limitations and questions about image scanning

Image scanning is embedded into the build and immediately raises four engineering questions: how much time it adds, what to do with vulnerabilities without a fix, how to filter out false positives, and whether a rebuild is needed after database updates. Below is how we answer each.

Will scanning slow down the build?

Syft parses the image layers and compiles a package inventory, Grype compares it against the vulnerability database.

Most of the time is spent reading layers, not searching, so the check runs in parallel with other steps and on a typical image does not change the total release time.

What to do with vulnerabilities that have no fix?

Some findings are in packages where the vendor has not yet released an update, and they cannot be closed by installing a new version. Such cases do not block the release: rules are configured by severity levels, and unfixable items go to the accepted risk list with a review date.

How to filter out false positives?

A false positive occurs when the match is by package name rather than by the actually built code. It is treated with exceptions that include justification and are tied to a vulnerability ID — the rule lives in the repository, is visible during review, and can be revoked.

Is a rebuild needed when databases are updated?

No. The vulnerability database is stored separately from the image: rescanning already built tags provides a fresh picture without releasing new versions. A rebuild is required only when the base image or the rules themselves change.

Let's discuss the task: scanning your images and blocking thresholds

To make the task assessment rely on your build scheme rather than average figures, we start the analysis with how images appear and live in your environment.

Send build files, a manifest export from the registry, a list of base images, and the release procedure — from them it is clear at which step Grype and Syft scanning can be embedded without stopping releases.

After the analysis, you receive:

  • a map of the current flow: from commit to image publication in the registry and further to the staging environment;
  • a list of base images and layers with a vulnerability assessment for each;
  • proposed blocking thresholds by severity level and a rule for reviewing them;
  • a false positive suppression scheme with an exception log and expiration dates for each entry;
  • an embedding option — at build time, in pre-merge checks, or in the registry — with justification for the choice;
  • a staged work plan indicating at which steps the release can be stopped and at which it cannot;
  • a list of what is needed from your engineers: access, service accounts, change windows.

Describe the task in whatever way is convenient: a paragraph in an email or a short call with your engineer. We will return with an assessment, a work plan, and a clear picture of what will change in the release process after container security is implemented.