GitLab container scanning with Trivy: what it checks and when teams need it
Enable GitLab container scanning in the build pipeline of any team that ships container images from self-managed GitLab, so known vulnerabilities are visible before an image is promoted to production. The analyzer is built on Trivy, an open source scanner from Aqua Security licensed under Apache-2.0. Trivy's README describes a wider scope (container images, filesystems, remote Git repositories, virtual machine images and Kubernetes), but the GitLab job is aimed at the images your pipeline builds. A scan answers a narrow question: what the scanner's vulnerability data says about the image's packages at the moment the job runs. Treat each result as a snapshot and plan for repeat checks.
Trivy's scanners look for OS packages and software dependencies, known CVEs, infrastructure as code issues and misconfigurations, exposed secrets and software licenses, and it can also produce or read an SBOM. Confirm in the GitLab analyzer documentation for your version which of these findings appear in the container scanning report, because the GitLab wrapper defines what reaches the merge request and the vulnerability report. Container scanning overlaps with other GitLab scanners only partly. It covers the packages inside the image, while SAST and dependency scanning inspect your source and lock files. Check the GitLab pricing page and the feature documentation to confirm which tier includes container scanning and which tier includes the policy and vulnerability management features you plan to use.
The decisions that matter are which images to gate, what severity blocks a merge or deployment, and who approves an accepted vulnerability. Allowlisting should have a named owner, a reason and a review date, so that an accepted CVE does not quietly stay accepted after a fix ships. For air-gapped instances, Trivy's vulnerability databases must be mirrored to an internal registry or copied into the offline cache, and the mirror must be refreshed on a schedule. Ask your team to confirm how often that refresh runs, because a stale database produces clean-looking results that are out of date. The Trivy self-hosting documentation describes both mirroring and offline cache steps.
Which container scanning results Free shows versus Ultimate
Free is the baseline for container scanning in pipelines. A container scanning job that runs on each build can produce findings for the image it built, and developers can read those findings in the job output and the report artifact. Free also lets you write your own Trivy reports in table, JSON or SARIF format, so you keep machine-readable evidence even if you never buy a higher tier.
- Per-build findings: Each pipeline run reports vulnerabilities for the image it produced, which suits developers who fix issues before merge.
- Portable report formats: Trivy's table, JSON and SARIF outputs can be stored as pipeline artifacts and fed to other tools.
- No cross-project view: Free does not give you a consolidated vulnerability view across projects, which the pricing page places in Ultimate.
- No security-based enforcement: Blocking merges or requiring security approvals is not listed for Free, so enforcement depends on your own pipeline rules.
Confirm which container scanning outputs your installed version exposes on the Free tier before you design reports around them.
Premium is priced per user and adds capabilities for delivery operations rather than for the security features in Ultimate. The GitLab pricing page lists advanced CI/CD and priority support for Premium, and it lists Geo as available for self-managed Premium and Ultimate. For container scanning, the practical question is whether the scanning stage itself changes at this tier, and the pricing page does not spell that out at the level of individual scanner outputs.
- Advanced CI/CD: Premium's listed pipeline features can help you structure scan stages, gates and reusable pipeline logic across many projects.
- Priority support: Support priority matters when a scanner upgrade or registry issue blocks your release pipelines.
- Geo for disaster recovery: Geo is available in Premium and Ultimate, so a secondary site can hold the same projects and pipeline configuration if you run it.
- Security features not listed: Application security testing, supply chain security and vulnerability management are listed for Ultimate, so do not assume Premium includes them.
Ask for the Premium feature list in writing and check whether any container scanning output changes on this tier.
Ultimate is where the GitLab pricing page places application security testing, software supply chain security, vulnerability management and compliance features. For container scanning, this is the tier that turns individual image findings into a managed workflow across groups and projects. Pricing for Ultimate is custom, so the cost depends on the quote you receive for your user count and feature needs.
- Vulnerability management: Findings from container scans can be tracked, triaged and reviewed across projects, which gives security teams a single queue.
- Supply chain security: Software supply chain features listed for Ultimate sit alongside container scanning, which helps when you need to trace components in an image.
- Compliance features: Compliance capabilities are listed for Ultimate, which can support evidence collection for change management reviews.
- Custom pricing: Ultimate is quoted individually, so ask the vendor or DeployOpen for a written quote tied to your scope.
Before you rely on an Ultimate feature for evidence, confirm in your installed version that the specific view or policy works as you expect.
The tier boundaries for container scanning are set by GitLab's pricing page and by the release you run, and both can change. Your decision should rest on a feature matrix you have checked yourself, not on a summary in this article. Plan a short verification in a staging instance that matches your self-managed deployment, including any offline or air-gapped constraints.
- Pricing page matrix: Compare the Free, Premium and Ultimate columns against the container scanning, vulnerability management, policy and compliance items you need.
- Installed version: Check the features in the GitLab version you will run, since the matrix may differ from the public page.
- Written quote: Ask for each tier's price, what it covers, whether it is per user, and what renews each year.
- Staging test: Run a container scan on a representative image and confirm the outputs your auditors and developers will use.
Record the results with the release version and the date, so your tier decision can be reviewed when GitLab changes its matrix.
Enabling Trivy container scanning in a self-managed GitLab pipeline
This sequence takes a self-managed GitLab instance from a confirmed tier and analyzer image source to a working container scan that produces reports in the merge request and the vulnerability report. Each step ends with a check you can run before moving on.
Confirm tier and analyzer image source
Before editing any pipeline, confirm which GitLab tier your instance runs and which features your team is licensed for. Container scanning is available in Free, but the full set of security reporting and policy features depends on Ultimate, so check the scope against the GitLab security scanning in Free vs Ultimate guidance and your subscription. Then decide where the Trivy-based analyzer image will be pulled from: the public registry for a connected instance, or an internal registry mirror for an offline one. Done when the team has written down the tier, the analyzer image location and the owner of that registry path.
Include the container scanning template
Add GitLab's container scanning CI/CD template to the project's
.gitlab-ci.ymlwith an include directive, rather than copying the job definition into the file. Keep the include inside the stage layout your pipeline already uses so the scanning job runs after the image build job that produces the artifact it scans. Commit the change on a branch. Check: the pipeline editor or linter reports a valid configuration and the new job appears in the pipeline graph.Set image variables and registry credentials
Point the scanning job at the exact image the build produced, using the image name and tag variables the template reads, typically tied to the commit SHA or the pipeline's predefined registry variables. Store registry credentials as masked, protected CI/CD variables scoped to the project or group, never as literal values in the YAML. If the analyzer image comes from a mirror, set the analyzer prefix variable to that mirror. Check: a job log line shows the expected image reference and the tag matches the build output, not
latestunless that is intentional.Run the pipeline on a feature branch
Push the branch so the pipeline runs without merging to the default branch. Watch the build job first to confirm the image is pushed to the registry, then watch the scanning job. Trivy will read the vulnerability databases the analyzer downloads, so a failure to reach those sources or the mirror usually shows up here. Check: the scanning job finishes, and the job log records which database version it used and how many targets it scanned.
Review the generated report artifacts
Open the job's artifacts and confirm the container scanning report file was written. This file is what GitLab parses for the merge request widget and the vulnerability report, so its presence is the main proof that the job did its work. Review a sample of findings for package names, installed versions, fixed versions and severities to confirm they match the image. Check: the report exists, is not empty for an image you know contains packages, and lists the base image layers you expect.
Verify the merge request widget
Open a merge request from the feature branch into the default branch and check the security widget. It should show the container scanning results from the branch pipeline, with counts by severity that match the artifact. Compare a few entries in the widget against the raw report to confirm the mapping is correct. Check: the widget shows the scan as complete, and a deliberately introduced test finding, if your team uses one, appears with the expected severity.
Verify the vulnerability report
After the change reaches the default branch, open the project's vulnerability report and confirm the findings are listed with their state, such as detected. Confirm the scan is attributed to the correct pipeline and branch, so triage decisions can be traced back to a build. Document the tier-dependent features your team relies on, such as triage workflows or policies, and confirm them against your subscription. Check: findings appear in the report with links to the pipeline that produced them, and the team has recorded which tier each feature needs.
Scanning registry images on latest tags and what that changes
Scanning an image once at build time tells you little about the same tag a week later. Tags such as latest move, and the vulnerability databases Trivy relies on keep changing, so the scan results for a registry image depend on when and how often it runs. The cards below cover what that changes and the governance questions to settle before you schedule anything.
Mutable tags and what a scan covers
A scan records what an image contained on the day it was scanned. A tag such as latest can point to a different digest tomorrow, so a clean result for latest may describe an image nobody is running. Record the digest alongside every result, and confirm how your GitLab pipelines reference images before you treat a tag-level result as evidence for a release.
Rescans as the vulnerability database updates
Trivy's results depend on its vulnerability databases, which are published as OCI images and updated over time. An image scanned clean last month can show new CVEs today without any change to the image. Plan scheduled rescans of registry images, and confirm how often your mirrored databases are refreshed so the scanner is not reading stale data.
Existing images versus newly built ones
Scans in a build pipeline cover the image produced by that job, while registry scans cover images already in use, including those built before your current pipeline existed. Decide which population each report covers and label findings so reviewers can tell a new build failure from an old image that became vulnerable. Confirm which of these views your GitLab tier surfaces and how it groups findings.
Which tags are authoritative
Teams need an agreed list of tags that represent releases, such as versioned tags or digests recorded by the pipeline, and a rule for which tags are scanned on a schedule. Mutable tags used for development can be scanned for information but should not be the basis for release sign-off. Write this list down and confirm it with the teams that push images.
Owners of rescan schedules
Someone must own the schedule, the database mirror, the allowlist and the response when a rescan finds a new critical issue. Name a platform owner for the schedule and mirror, and an application owner for each image who decides whether to rebuild, patch or accept the risk. Confirm who receives alerts outside working hours, since a scheduled job can fail silently.
Allowlists must expire
Accepted vulnerabilities in an allowlist should carry a reason, an owner and a review date, so a risk accepted for one rebuild does not persist across every later rescan. Without a review point, a registry scan will keep passing for images that have quietly become exposed. Check how your chosen GitLab tier records and reports accepted findings before you rely on the list for audit evidence.
Configuration options and when each fits
This table compares the main Trivy settings for GitLab container scanning, from database sourcing and scan triggers to report formats and fail rules. Read each row for the fit it suits and the cost it carries, then confirm exact variable names in your GitLab and Trivy versions before you standardize.
| Decision | Option | Trade-off | When to choose it |
|---|---|---|---|
| Vulnerability database source | Default online database download | Simplest setup, but the runner must reach the public database endpoints on every fresh scan | Connected runners with internet egress allowed by your network policy |
| Vulnerability database source | Internal mirror of trivy-db and trivy-java-db | Needs a sync job, a registry and repository settings (such as --db-repository and --java-db-repository); a stale mirror silently misses recent CVEs | Air-gapped or egress-restricted networks, or when you want one approved database copy across all runners |
| Offline database loading | Archive copied into the Trivy cache directory | Manual transfer on a connected machine; you must repeat it on a schedule to stay current | Fully disconnected systems with no internal registry available |
| Scan trigger | Every merge request pipeline | Fast feedback on new code, but scans only the image built in that pipeline, not images already running | Blocking vulnerable images before they are merged or deployed |
| Scan trigger | Scheduled scans of registry images on latest tags | Catches vulnerabilities published after a build, but runs on a schedule and may flag images no one is deploying | Ongoing exposure tracking for images that stay in use for long periods |
| Report format | Table or console output | Easy for humans to read in job logs, but not suitable for automated gating or import | Developers reviewing results during a merge request |
| Report format | JSON output | Full detail for scripts and custom dashboards; you must maintain the parsing logic yourself | Feeding custom reporting, audit evidence or your own policy checks |
| Report format | SARIF output | Standard format for code-scanning tools that accept it; confirm how your GitLab version displays imported findings | Sending results to a tool that already consumes SARIF |
| Severity threshold and fail rule | Fail the job on selected severities | Enforces a hard gate, but a strict rule can block urgent fixes when no patched package exists | Protected branches and production-bound images where policy requires a stop |
| Severity threshold and fail rule | Report only, no failing exit | Keeps pipelines moving and builds visibility, but findings can be ignored over time | Early rollout, when teams are still tuning allowlists and remediation paths |
Allowlisting accepted vulnerabilities without hiding risk
Some findings will be accepted rather than fixed, and the allowlist is where that decision becomes visible. Teams usually accept a CVE for one of three reasons: no fixed package version exists yet, the vulnerable code path is not reachable from how the service runs, or a compensating control such as network isolation or a restricted runtime reduces the exposure. Each accepted CVE should be recorded in the allowlist file with its identifier, the scope it applies to (ideally a specific image, path or package rather than the whole project), a named owner, a written reason and an expiry date. Without an expiry, a temporary exception quietly becomes permanent. Confirm in your GitLab version and Trivy configuration whether the allowlist format supports an expiry field and how the scanner treats entries after they lapse, because that behavior decides whether expiry is enforced automatically or only by your review process.
A broad allowlist erases the signal the scanner exists to provide. Entries that cover a whole project, match a CVE across every image, or carry no reason make later findings invisible to reviewers, and nobody can tell whether an exception still reflects the situation it was written for. Route each allowlist change through a documented approval process: a security reviewer signs off on the scope and reason, and the owner confirms the compensating control in writing. Store the file in version control so every change has an author, a reviewer and a history that auditors can read. Treat it as code under the same merge request controls as the pipeline configuration.
Allowlists also go stale. A base image rebuild, a dependency upgrade or a change to the runtime can make an accepted CVE unreachable, fixed, or newly relevant through a different package. Review the allowlist whenever the base image tag changes, when dependency manifests change, and at each expiry date, and remove entries whose reason no longer holds. Ask your team to confirm how the pipeline reports entries that match nothing, since unused exceptions are a common sign that the file needs cleanup.
Security and operational risks to plan for
Trivy scanning in GitLab pipelines creates risks in four places: the vulnerability data it reads, the credentials and runners it uses, the reports it writes, and the alerts it raises. Each card below pairs one risk with one control to decide before the first scan runs.
Stale vulnerability databases offline
On air-gapped systems, Trivy only knows about vulnerabilities in the database copy it was given. The Trivy documentation describes downloading the trivy-db or trivy-java-db archive on a connected machine and copying it into the cache db directory on the offline system. Confirm who performs that copy, how often it happens, and how the team will know the database is older than its last successful update.
Mirror maintenance drift
Trivy's databases are published as OCI images that can be mirrored to an internal registry and selected with --db-repository, --java-db-repository and --checks-bundle-repository. The Trivy documentation warns that mirrors must be kept updated. Assign an owner for the mirror job, alert when it fails, and record which database version each scan used so findings can be reproduced later.
Registry credentials in scan jobs
A scan of images in a private registry needs read credentials, and those credentials sit in CI/CD variables that any job on the project may reach. Use a read-only pull account scoped to the images being scanned, mask the variable, and protect it so only protected branches receive it. Rotate the account on a fixed schedule and confirm which jobs can print or echo its value.
Scan job privileges and runner isolation
Image scanning reads layers, caches data and writes files, and a job that runs on a shared runner with a Docker socket or privileged mode can affect other projects. Run scan jobs on a dedicated runner pool with the least privilege that works, and avoid privileged containers. Confirm which executor the runner uses and whether untrusted merge request pipelines can reach that pool.
Sensitive package data in reports
Trivy reports list installed OS packages, software dependencies and versions for each image, and the JSON, SARIF and template formats keep that detail in artifacts. Those artifacts can expose internal component names and unpatched versions to anyone with access to the pipeline. Set artifact visibility and retention to match your classification rules, and restrict download access to the teams that triage findings.
False positives and alert fatigue
Scanners report vulnerabilities in base image packages that a running service never loads, and teams that see many unfixable findings stop reading the job output. Agree a triage rule for each severity, record accepted findings in an allowlist with an owner and an expiry date, and review the list when the base image changes. Confirm the allowlist format and review cadence before enforcing failures on the pipeline.
Questions teams ask before enabling container scanning
Does GitLab Free include container scanning in pipelines?
Container scanning is part of the security testing that GitLab's Free tier covers, so teams can add a scan job to pipelines without a paid license. What changes between tiers is how far the results travel. The pricing page places application security testing, software supply chain security and vulnerability management in the paid tier above Premium, so check the current comparison before assuming a feature is included. List the result views, registry scanning options and reporting your security team needs, then match each one against the tier table on GitLab pricing. Get the tier decision confirmed in writing before rollout.
What drives the cost of container scanning?
Cost has four parts, and the license is only one of them. Licensing depends on the tier you need: Free costs nothing, Premium is listed at 29 US dollars per user per month billed annually, and the paid tier above it is custom priced. Runner capacity is recurring compute for scan jobs, and it grows with the number of images and how often they build. An internal mirror of Trivy's vulnerability databases needs someone to keep it updated on a schedule. Triage time, spent reviewing findings and recording accepted risk, is often the largest recurring cost. Ask for a quote that separates one-time setup from these recurring items.
Is Premium enough for the scanning features security teams expect?
It depends on what your security team expects to see. The pricing page lists advanced CI/CD and priority support for Premium, and it assigns application security testing, software supply chain security, vulnerability management and compliance features to the paid tier above it. Premium is listed at 29 US dollars per user per month billed annually, so the cost scales with the number of users who need access. Teams that only need scan jobs and pipeline results should test that path first. Teams that need organization-wide dashboards, policy enforcement or compliance evidence should confirm those features against the current tier table before budgeting.
How long does container scanning setup take?
The duration depends on how many registries, projects and pipeline patterns you have, so no single figure applies to every estate. A single project that builds one image in a standard GitLab pipeline is the simplest case. Effort grows when images come from several registries, when jobs run on custom runners or inside restricted networks, when scans must cover the latest tags across many projects, and when security wants a triage process before findings can block merges. Ask for a written timeline tied to a named list of registries, projects and runners, and confirm which phases it includes: pilot, rollout, allowlist tuning and handover.
What does our team need to provide for the work?
Three inputs decide whether the work moves quickly, and each one needs a named owner.
- Registry access: read access to the images to be scanned, plus service credentials that the scan job can use.
- Runner access: runners with the tags, network path and privileges that the chosen executor requires, including a route to your registry and to the internal vulnerability database mirror.
- A security triage owner: one person who reviews findings, sets severity thresholds, decides which vulnerabilities are accepted and signs off on allowlist entries.
Without the triage owner, findings pile up in the dashboard and the pipeline either blocks everything or ignores everything. Agree these three owners before the work starts.
Can our own team set up container scanning without a partner?
Yes, many teams do. GitLab documents its scanning templates, and Trivy's documentation covers how the scanner is configured, so a platform engineer who knows GitLab CI can enable a scan job in one pilot project. A partner adds the most value when the work spans several registries, air-gapped mirrors, policy design and handover to operations. Compare the cost of your team's time, including triage, with a written, fixed-scope proposal. DeployOpen plans, implements, documents and hardens self-hosted platforms inside your own infrastructure, and offers ongoing support as a retainer if you want help after handover.
Can container scanning run in an air-gapped network?
It can, but the vulnerability data has to be brought in from outside. Trivy publishes its databases (trivy-db, trivy-java-db and trivy-checks) as OCI images that you can mirror to an internal registry and select with the repository settings. On a disconnected system, you can also download the database archive on a connected machine and copy it into the cache directory. Mirrors must be kept updated, so the transfer process needs an owner and a schedule. Confirm the scanner image mirroring steps with GitLab's offline guidance before you finalize the design. The Trivy self-hosting documentation covers the database steps.
How should we record vulnerabilities the team accepts as risk?
Use an allowlist with a written record for every entry. Each entry should name the vulnerability, the affected image, the reason it is accepted, the owner who approved it and a review date. Keep the file in version control so changes go through merge requests and leave an audit trail. Set expiry or review dates so accepted findings return for review when the base image or dependency changes. Ask your security team to define who can approve entries and what severity levels need a second approver. Review the allowlist on a fixed schedule, and treat it as evidence for change management and vulnerability handling.
How DeployOpen scopes a container scanning rollout
DeployOpen scopes container scanning as a fixed-scope engagement, with the deliverables, the images covered and the handover agreed in writing before any pipeline is changed. The work starts with an inventory of the images your teams build and run, the registries they are pushed to, and the base images they inherit from. That inventory decides how much of the rollout is pipeline work and how much is governance. A team that builds twenty images from one base needs a different plan from a team with hundreds of images across several registries, and the quote should reflect which situation you are in. Ask for the inventory to be listed as a named deliverable so you can check what was covered.
The pipeline work covers the Trivy-based scanning jobs in GitLab CI/CD, the report formats each job produces, and how results appear in merge requests. Where your GitLab instance or runners cannot reach the public vulnerability databases, DeployOpen also plans the offline path: mirroring the trivy-db and trivy-java-db images into an internal registry, pointing the scanners at them with --db-repository and --java-db-repository, and setting a schedule that keeps the mirror current. That schedule is a recurring cost to name in the scope, because an outdated mirror produces a false sense of coverage. Allowlist governance is the other half of the work: who may add an accepted vulnerability to a .trivyignore file, what justification and expiry each entry needs, and how the file is reviewed. Confirm the reviewers and the review cadence with your security team before the build starts.
Handover is where most of the value of the scope is either kept or lost. Expect written runbooks for the pipeline configuration, the database mirror, the allowlist process and the steps to rotate the mirror. Ongoing support, upgrades of the scanner and continuous testing are available as optional retainers, separate from the fixed scope. Your team should confirm which of those services it needs after handover, and whether an independent auditor will ask for evidence that the allowlist was reviewed. DeployOpen prepares that evidence but does not issue audit reports or certifications.
How DeployOpen delivers and supports this
DeployOpen plans, implements, hardens, documents and supports self-hosted open-source platforms inside your own infrastructure, including air-gapped networks. For GitLab container scanning with Trivy, we start with a written scope that fixes which pipelines, registries and tiers are covered, then build and test the scanning path before handing it over.
How we scope
- We confirm which GitLab tier you run and which container scanning features that tier includes
- We list the image registries, branches and tags in scope, including whether latest tags are scanned
- We agree in writing how accepted vulnerabilities are allowlisted, reviewed and expired
How we build
- We add the Trivy scanning job to pipelines and test it against representative images
- For offline sites, we mirror Trivy vulnerability databases to an internal registry and keep them updated
- We check scan output formats and failure thresholds against the team's merge and release rules
How we hand over
- We document the pipeline configuration, allowlist process and database update schedule for your engineers
- We record which findings block a pipeline and which are reported for review only
- We walk your security and platform teams through the runbook before handover is closed
How we support
- Ongoing support, upgrades and continuous testing are available as a retainer
- We can review Trivy and GitLab version changes and update the scanning job and mirrors
- We confirm after each GitLab upgrade stop that scanning jobs and reports still run as expected

