GitLab pipeline integrity: image digests and pinned dependencies

Pin CI images by digest, lock dependencies, verify tool versions and vendor remote includes so a changed upstream artifact cannot silently alter your builds or deployments.

On this page

Why GitLab pipeline integrity starts with pinned inputs

Pipeline integrity means every input a CI job uses is fixed and verifiable. On a self-managed GitLab instance, a job is only as trustworthy as what it pulls at run time: container images referenced by tag, package installs that resolve to the newest version, tool binaries downloaded from a URL, and include: entries that fetch YAML from another project or remote location. Any of these can change between two runs of the same commit without anyone reviewing the change. A tag can be moved to a different image, a package can be republished, and a remote include can point at content that no longer matches what the release team approved. The pipeline then passes or fails on code nobody reviewed, and the logs may not show it.

Teams need this control first when releases are regulated, when a shared runner fleet executes jobs for several projects with different trust levels, or when auditors ask for evidence that a build could be reproduced from recorded inputs. In those settings the question is not only whether the build works but whether you can show which image, which dependency versions and which pipeline definition produced an artifact. GitLab's pipeline security guidance advises pinning these inputs and checking them, and this page turns that advice into decisions for your instance. Before changing anything, list every image, include and downloaded tool your pipelines use, and confirm which of them are referenced by mutable tags today. Confirm also with your security and release owners which projects are in regulated release paths, since those should be handled first.

Which pinning method fits each pipeline input

Image references in image: keys and service definitions are the most common place where a pipeline silently changes. A tag such as latest or even a version tag can be repointed to different content, so the job that ran yesterday may not run the same bytes today. Pinning to a digest (a sha256: value that identifies the exact image manifest) makes the reference content-addressed, so a changed image fails to match rather than running unnoticed.

  • What is pinned: the image digest, usually written as image@sha256:... alongside the human-readable tag for reviewers.
  • What it protects against: a tag being moved, a compromised registry account publishing over an existing tag, and drift between runner hosts.
  • Maintenance it adds: digests must be refreshed on a schedule, through a bot or pipeline job that opens a merge request with the new value and the upstream changelog.
  • Where it breaks: a digest pins one platform build, so multi-architecture images need care, and a base image rebuilt for a security fix will not reach you until someone updates the digest.
  • Registry support: confirm with your registry vendor whether it returns stable digests, supports immutable tags and offers signature verification, because these features vary and should not be assumed.

Check that every image in the pipeline, including services and helper images, resolves to a digest, and that your update process records who approved each change.

Pinning options and when each one fits

This table compares five ways to pin pipeline inputs: image tags, image digests, lock files with checksums, pinned tool versions and vendored includes. Read each row as a trade-off between how tightly the input is fixed and how much work it takes to keep it current. Most teams combine several options, with digests and checksums protecting what runs and a scheduled update process keeping pins from going stale.

OptionProtection gainedUpkeep and update workflowTeams most likely to need it
Tag pinning (for example, a version tag on a base image)Stops floating to the latest build of a minor tag, but the tag can be moved by the publisher or a compromised registry accountLow effort: edit the tag in the CI file and let a bot or the team bump it on releaseTeams early in hardening that need a fast improvement with little change to existing pipelines
Image digest pinning (SHA256 digest of the image)Each job runs exactly the image bytes that were reviewed, so a moved or replaced tag does not change the buildModerate effort: resolve the digest at update time, record it, and refresh it on a schedule; tag remains readable for humansRegulated teams and release engineers who must show which image produced an artifact
Lock files with checksums (for example, dependency lock files and hash-verified installs)Pins transitive dependencies and rejects packages whose content no longer matches the recorded hashModerate effort: regenerate lock files deliberately, review the diff, and commit them alongside codeTeams with large dependency trees in Node, Python, Java, Go or Rust builds
Pinned tool versions (CLI tools, scanners and build helpers installed by jobs)Keeps the behavior of linters, deployers and signing tools stable and makes version drift visible in reviewLow to moderate effort: set explicit versions in variables or the image, then update them in a planned changePlatform teams whose pipelines depend on several shared CLI tools across many projects
Vendored remote includes (copying shared CI templates into the repository)Removes the runtime fetch from an external project, so pipeline logic changes only through your own merge requestsHigher effort: sync upstream changes by hand or with a tooling step, and review each import before mergingOrganizations with strict change control or air-gapped instances without reliable access to external template projects
Pinned remote includes by ref (referencing a specific commit or tag of a template project)Fixes the template version used, but the code still comes from another project and needs trust in its ownerLow effort: update the ref in the include, which is visible in reviewTeams sharing internal templates across groups who accept a trusted source but want version control

How to roll out pipeline pinning without breaking builds

This sequence moves a GitLab estate from floating image tags and remote includes to pinned, verified inputs one layer at a time, so each change is tested before the next one lands. The output is a pipeline inventory, pinned references that resolve, vendored includes and lock files, and a scheduled review of digest updates.

  1. Inventory every image, include and install step

    Search every .gitlab-ci.yml file, included template, component reference and script block for image names, remote include URLs, package install commands and downloaded binaries. Record each one in a table with its file path, the project that owns it and the tag or URL it currently uses. The step is done when the table covers every project in scope, including shared templates in group-level repositories, and a second reviewer can trace each entry back to a line in the code.

  2. Pin the highest-risk inputs first

    Rank the inventory by what each input can reach: images used by deploy jobs, runners with access to production credentials, and anything that runs with protected variables comes first. Replace mutable tags such as latest or a bare major version with a digest reference for those images, keeping the human-readable tag in a comment. The check is a pipeline run on a branch that confirms each pinned reference resolves and that the job logs show the expected image digest.

  3. Vendor remote includes into the repository

    Copy remote include files that the pipeline depends on into the repository, or into a dedicated project that only maintainers can change, and point the include path at the local copy. Record the source URL and the version or commit it came from in a header comment so future updates are deliberate. The check is a diff of the vendored file against its upstream source at the recorded version, plus a pipeline run that uses only the local path.

  4. Add lock files and verify checksums

    Commit lock files for every package manager the jobs use, and change install commands to fail when the lock file does not match the manifest. For binaries downloaded during a job, store the expected checksum next to the download command and verify it before the file is executed. The check is a deliberate failure test: change one checksum or remove a lock entry on a branch and confirm the pipeline stops before the affected job runs.

  5. Confirm builds and tool versions still behave

    Run the full pipeline, including test, scan and deploy stages on a non-production environment, against the pinned inputs. Compare test results, build outputs and tool versions with a run from before the change so that any behavior difference is traced to a specific pinned input rather than discovered in production. The step is done when the pinned pipeline passes the same stages as before and the differences, if any, are documented and accepted by the owning team.

  6. Schedule digest refresh and diff review

    Set a scheduled pipeline or a recurring task that checks pinned digests and lock files for upstream changes and opens a merge request with the proposed updates. Each merge request should show the old and new digest, the changed vendored file or lock entries, and the test results from a pipeline run before merge. The check is that the most recent scheduled run produced a reviewable merge request, and that no digest changed without a reviewer approving the diff. Confirm the refresh cadence with the team that owns the pipeline.

Risks that pinning does not remove

Pinning images and dependencies fixes what your pipeline pulls, but it does not vouch for the content behind a digest or the machines that run your jobs. The cards below cover the residual risks that remain after pinning, and the checks that close the gap.

Malicious content behind a pinned digest

A digest proves that you received the same bytes twice, not that those bytes were safe the first time. If an upstream image was compromised before you pinned it, the malicious digest stays locked in place and every job keeps pulling it. Before you pin, review the image's build provenance and publisher, and confirm that the image was built from a source you can inspect. Record who approved each digest in your change process.

Stale digests that miss fixes

A pinned digest never changes on its own, so it also never receives security patches from the publisher. Over time, pipelines can run on images with known vulnerabilities while everyone assumes they are current. Set a scheduled job that rebuilds or re-pins base images, and have a scanner report on the pinned digests your projects use. Ask who owns the update cycle and how quickly an advisory triggers a new pin.

Tampering with runner caches and layers

Pinning controls what the pipeline asks for, but the runner stores and reuses caches, build layers and local images between jobs. A job on a shared or poorly isolated runner can write to those caches, and a later job can then consume the altered content without any change in the pipeline file. Use ephemeral runners for sensitive builds, avoid sharing caches across trust levels, and verify artifacts against their expected digests before deployment.

Secrets exposed to unverified jobs

A correct digest does not stop a job from reading secrets it should never see. If a merge request or an unreviewed branch can run a job that has access to deployment credentials or registry tokens, a tampered dependency can exfiltrate them. Keep sensitive variables protected so they reach only protected branches, and use protected environments for production deploys. Confirm which jobs can read which variables before you rely on pinning as a control.

Unreviewed changes to remote includes

Remote CI includes and templates fetched at run time can change without a commit in your project. Pinning the image does not pin the pipeline definition that calls it. Vendor the included files into your repository, or pin them to a specific commit, and review changes through merge requests. Confirm which includes your pipelines fetch and who can change the source they point to.

Questions teams ask before pinning pipelines

How much effort does pinning GitLab pipelines take?

Effort depends mostly on how many images, remote includes and downloaded tools your pipelines use, and how many projects share them. The one-time work covers inventorying each reference, resolving it to a digest, rewriting .gitlab-ci.yml and shared templates, vendoring remote includes into a controlled project and adding lock files for language package managers. The recurring work is reviewing and applying digest updates when you decide to move to a newer image. Effort rises with many independent repositories, custom build images, private registries and tools fetched at runtime with no version check. It falls when a central template project supplies shared jobs and a small set of base images. Ask any provider for an itemized inventory, the effort per item and a split between one-time and recurring work. No duration is given here because it depends on that inventory.

How long does a first pinning pass take?

The duration depends on the size of the inventory, so no general figure is safe to quote. A first pass usually moves through four stages: discovery of every image, include and downloaded tool across the pipelines in scope, resolution of each reference to a digest and a version your team has reviewed, changes to pipeline files tested on a non-production project, and handover of the update procedure. Discovery is often the longest stage in organizations with many repositories, because teams add references informally over time. Test runs take longer when jobs depend on external services or on runners you cannot reproduce. Ask the provider to state the duration of each stage in the written scope, the assumptions behind it and what would extend it. Confirm the timeline with your own pipeline owners before accepting it.

What does our internal team need to provide?

Your team supplies the knowledge and access that an outside engineer cannot infer from the repositories. Expect to provide administrator or group owner access to the GitLab instance and the projects in scope, a list of container registries, package mirrors and artifact stores the pipelines use, and the owner of each shared template and protected branch. You will also need a non-production project and runner where changes can be tested, approval paths for which upstream sources are trusted, and a named person who approves digest updates after the first pass. Confirm the change window for pipeline edits and who signs off on production deployments that depend on the changed jobs. Unclear ownership can stall the work more than technical problems do, so settle these names before the work starts and record them in the scope.

Can our own team pin pipelines without a partner?

Yes, a team with CI/CD experience can do the work alone, provided it has time to inventory its pipelines and the skills to review changes to them. The technical steps are straightforward for experienced engineers: resolve references to digests, pin package versions with lock files, vendor remote includes and verify tool versions inside jobs. The harder parts are controlling scope across many repositories, keeping a test path that matches production runners and sustaining the update routine after the first pass. Many teams split the work, keeping routine digest updates in-house while asking a partner for the initial inventory, a template redesign or an independent review of the result. A partner works under a fixed-scope written agreement, and ongoing updates can run under a retainer. Decide based on how many pipelines you own and who will run the updates.

How do digest updates stay current without breaking builds?

Digest updates stay current through a scheduled process, not a one-off change. Run a job on a fixed schedule that checks each pinned reference against its registry, opens a merge request with the new digest and records the digest it replaces. Require a reviewer, run the pipeline on the change in a test project that uses the same runner images and read the release notes of the upstream image before merging. Keep a readable tag in a comment beside each digest so reviewers can see which version they are approving. Roll the change through a staging environment before production jobs use it. Decide in advance how far behind you accept falling behind, because a digest that never moves also leaves known fixes unapplied. The scheduling tool is your choice. Confirm that it works with your self-managed GitLab and registry setup before relying on it.

Does pinning affect upgrades of GitLab or Runner?

Pinning the images your jobs use does not change how the GitLab server is upgraded, but it does interact with Runner versions and with upgrade stops. GitLab requires upgrades to pass through required upgrade stops, and GitLab Runner should keep its major and minor versions aligned with GitLab. Treat the Runner binary and the images your jobs use as separate pins, because a Runner held on an old version can fall out of step with an upgraded server. Under GitLab's maintenance policy, bug fixes are backported only to the current stable release, while security fixes also reach the previous two monthly releases, so a long-standing pin on an old release carries the most risk. Plan each Runner upgrade alongside the GitLab upgrade stops, and test pinned pipelines on the new versions before the production window.

Does a digest pin protect us from a compromised image?

A digest protects against a tag that changes after you approved it, which is the main threat a tag alone leaves open. It does not prove that the content behind the digest is safe. Verify the publisher and source of each image before the first pin, use any signature or provenance data the publisher supplies and scan the image with tools your security team trusts. Vendoring remote includes into a project you control means that any change to them requires a merge request and review. Lock files give the same control over package managers. A pinned dependency can also develop a known flaw after you approve it, so pinning has to sit alongside scanning and the update routine described above. Confirm which verification methods your chosen images and registries support.

What should a partner put in a written scope?

A written scope should name what is changed, what is excluded and how success is checked. Ask for the list of repositories, pipelines, runners and registries in scope and an inventory of images, includes, packages and downloaded tools, with the method used to find them. The scope should also state the pinning approach for each category, where lock files and vendored includes will live and the deliverables, such as updated pipeline files, the update procedure, a runbook and handover notes. Acceptance tests should run on a non-production project. List exclusions explicitly, such as GitLab server upgrades, runner fleet changes or image rebuilds. Finally, request the schedule with each stage's assumptions and the options for ongoing updates under a retainer. Engagements are fixed-scope, with scope, deliverables and timelines agreed in writing before work starts. DeployOpen does not publish a price list, so a quote follows from the written scope.

Which GitLab edition and tier you need for these controls

The controls in this topic, pinning images by digest, locking dependency versions, verifying tool downloads and vendoring remote includes, are built from .gitlab-ci.yml syntax, the CI/CD configuration of your project and the runners that execute it. GitLab Free, Premium and Ultimate are all available for self-managed installations, according to the GitLab pricing page. Nothing in the core pipeline work described here depends on buying a separate licence, so the tier decision should be made on the other controls your organization needs, not on these pipeline settings alone.

The tier question matters at the next layer. The pricing page places software supply chain security features, along with application security testing, vulnerability management and compliance features, in the Ultimate tier, and lists advanced CI/CD and priority support under Premium. If your pipeline integrity plan depends on scanning dependencies, producing SBOMs or enforcing security policies centrally, those capabilities are the ones to check against your chosen tier. Pricing is quoted per user per month for Premium, while Ultimate is custom priced, so ask for both figures in writing if you are comparing tiers for a large user base.

Confirm the exact feature availability per tier on the pricing page before you scope the work, because feature placement changes between releases and the table is the authority for your contract. Ask your GitLab account contact or reseller to confirm in writing which tier includes each feature you plan to rely on, and record the answer in the scope document. DeployOpen can help map each control in this topic to the tier that provides it, but the final entitlement comes from GitLab.

How DeployOpen scopes and delivers pipeline integrity work

DeployOpen plans, implements and hands over pipeline integrity controls on self-managed GitLab inside your own infrastructure. The work starts from a written scope that names which pipelines, images and tool dependencies are in play, then moves through build, verification and documented handover.

How we scope

  • We inventory every image reference, remote include and tool download used by your CI/CD pipelines.
  • The written scope names which projects, runners and registries the digest and pinning work covers.
  • Engagements are fixed-scope, with deliverables and timelines agreed in writing before any work starts.

How we build

  • We replace mutable image tags with SHA digests and record the resolution process for each image.
  • We commit lock files for language dependencies and check that CI installs only from those locked versions.
  • We vendor remote includes into the repository and verify tool versions against checksums before jobs run.

How we hand over

  • You receive a written inventory of pinned images, includes and tool versions with their owners.
  • We document the procedure for updating a digest, regenerating a lock file and re-vendoring an include.
  • Your team runs a pipeline from a clean state to confirm the pinned configuration works without DeployOpen.

How we support

  • Ongoing support, upgrades and continuous testing are available as a retainer after handover.
  • Retainer work can cover scheduled digest refreshes, reviews of new includes and pipeline changes.
  • Ask any provider how they will track upstream image changes and security updates before signing.

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.