Skip to content

Security

Risks

CI/CD is the automation of most (if not all) process in your software lifecycle going from building to running the application in production. With so many things happening, attackers have a wide range of capabilities in case of a compromise:

  • introduce dubious components (i.e. backdoor) in the application,
  • leak (to the Internet) credentials granting access to internal services or infrastructures,
  • access said services or infrastructures,
  • impersonate an employee,
  • leak intellectual property,
  • ...

Every CI/CD job is executed inside a container image which contains various tools required by the job. When you are executing the job, you are trusting the people building the image and the tools.

In some cases, the image may have been corrupted by an attacker. This is what we call a supply chain attack. There are famous cases like the Codecov incident in which hackers managed to leak credentials from several services and cloud platforms.

Supply chain attacks can also occur when installing application dependencies in your CI/CD pipeline (Shai-Hulud).

Mitigations

Variables scoping

To prevent leakage, CI/CD variables has to be present only in jobs that need them. By example in the Maven template, only the mvn-sonar job actually needs the SONAR_TOKEN environment variable so others jobs (mvn-build, mvn-release...) should not access this secret.

You can find more info about how to protect your CI/CD variables in the official GitLab documentation.

Image selection

As much as we can, we try to select either official images (ex: Maven, Python), or at least images maintained by an active community. Each of those images can be freely overridden with the appropriate configuration variable to select fixed versions (more info here) or any alternative that would suit you more.

By default, to be continuous templates mostly use the latest tag from upstream images since it is a maintenance-less default that works for nearly everyone. However latest images are prone to supply chain attacks and are also likely to introduce breaking changes.

to be continuous is not responsible of any possible security issue from a default container image.

To mitigate the risks of using latest images, you should always use a fixed version tag (maven:3.9.1 instead of maven:latest) or build your own image.

Additional dependencies

However, the direct counterpart of using official images is that many default image do not ship all the required tools used by the template (think about git and curl utilities). For this reason, many templates check the presence of these additional dependencies and install them on the fly (see maybe_install_pkg function).

This is a good practice to avoid bloating the image with unnecessary tools, but it also means that you are trusting the upstream repositories of your distribution (i.e. Debian, Alpine, etc.) to not be compromised and requiring network access to download packages.

Every project is encouraged to maintain his own Docker image in order to fit to their needs, avoid extraneous downloading for additional dependencies and simplify the work of security team (it's easy to scan a Docker image). While doing so, we recommend to use a minimal distribution and root-less images to prevent some container escalation vulnerabilities against your runner provider.

Tip

Whenever building your own image or using an upstream image, you can use Renovate to watch updates for your tools, test the new version and integrate them seamlessly.

Application dependencies

Using lock files

We highly recommend using lock files (package-lock.json, yarn.lock, poetry.lock, etc.) to list all direct and transitive dependencies. These lock files should be commited to your git repositories. This ensures consistent installs between machines (including CI/CD pipelines).

When using lock files, the CI/CD pipelines based on to-be-continuous always use the dependencies versions listed in the lock file, they will never try to install newer versions of your dependencies (they use npm ci instead of npm install for example).

To add new dependencies, a developper needs to update the lock file directly on his development machine (the developper should run npm install or a similar command). Once done, this new lock file needs to be committed to the git repository.

To upgrade dependencies, we recommend using Renovate in a Gitlab CI pipeline. It will handle lock files for you.

Keep in mind that some templates might install dependencies not covered by project lock file.

Limit the risk of supply chain attack

When a dependency is compromised (Shai-Hulud for example), it is generally detected and removed from the repositories (NPM, PyPI, etc.) in the first hours/days after it has been published. A good practice is to configure your package managers (npm, yarn, poetry, etc.) on your development machines so that they do not download dependencies that have been published very recently. pnpm and yarn already support such settings.

Renovate also has a similar option when updating dependencies.

Vulnerability Reports (Trivy)

Important

When reviewing vulnerabilities from containers, keep in mind the following considerations:

  • Containers are usually very short-lived in a CI/CD context.
  • No direct user access is possible.
  • Most job do not expose any external endpoint (i.e. HTTP server), making vulnerabilities relying on user interaction very hard if not impossible to exploit.

In short, even though risks are often reduced in a CI/CD context, this should not mean that vulnerabilities assessment are unnecessary. They remain an essential step in securing your pipeline.

Here are vulnerability reports for each default image used by to be continuous templates (generated every day):

Template Image Variable Default Image Vulnerabilities
AnsibleANSIBLE_IMAGEdocker.io/cytopia/ansible:latest-tools 5 High, 10 Medium, 6 Low, 6 Unknown
AnsibleANSIBLE_LINT_IMAGEdocker.io/haxorof/ansible-lint:latest 3 High, 7 Medium, 6 Low, 4 Unknown
Amazon Web ServicesAWS_CLI_IMAGEdocker.io/amazon/aws-cli:latest
AzureAZURE_CLI_IMAGEmcr.microsoft.com/azure-cli:latest 2 Critical, 2 High, 5 Medium
BashBASH_BATS_IMAGEdocker.io/bats/bats:latest 3 High, 7 Medium, 6 Low, 4 Unknown
BashBASH_SHELLCHECK_IMAGEdocker.io/koalaman/shellcheck-alpine:stable 2 Critical, 6 High, 31 Medium, 11 Low, 4 Unknown
BrunoBRU_IMAGEdocker.io/library/node:lts-alpine 8 High, 9 Medium, 6 Low, 4 Unknown
GitLab ButlerBUTLER_IMAGEregistry.gitlab.com/to-be-continuous/tools/gitlab-butler:latest 3 High, 9 Medium, 7 Low, 4 Unknown
Cloud FoundryCF_CLI_IMAGEdocker.io/governmentpaas/cf-cli 10 Critical, 51 High, 121 Medium, 5 Low, 4 Unknown
Cloud Native BuildpacksCNB_BUILDER_IMAGEdocker.io/paketobuildpacks/builder-jammy-base:latest 46 Critical, 494 High, 2350 Medium, 234 Low, 197 Unknown
Cloud Native BuildpacksCNB_SKOPEO_IMAGEquay.io/containers/skopeo:latest
Cloud Native BuildpacksCNB_TRIVY_IMAGEdocker.io/aquasec/trivy:latest not fetched
CypressCYPRESS_IMAGEdocker.io/cypress/included:latest 7 Critical, 81 High, 159 Medium, 258 Low, 33 Unknown
dbtDBT_IMAGEghcr.io/dbt-labs/dbt-core:latest 4 Critical, 286 High, 1261 Medium, 811 Low, 35 Unknown
Docker ComposeDCMP_IMAGEdocker.io/library/docker:latest 4 Critical, 33 High, 51 Medium, 9 Low, 20 Unknown
Docker ComposeDCMP_KICS_IMAGEdocker.io/checkmarx/kics:latest 1 Critical, 9 High, 19 Medium, 4 Low, 2 Unknown
DebianDEBIAN_BASE_IMAGEdocker.io/debian 7 High, 27 Medium, 75 Low, 6 Unknown
DebianDEBIAN_BUILD_IMAGE$DEBIAN_BASE_IMAGE not fetched
DebianDEBIAN_LINT_IMAGE$DEBIAN_BASE_IMAGE not fetched
DefectDojoDEFECTDOJO_BASE_IMAGEdocker.io/library/node:alpine3.11 1 Critical, 34 High, 4 Medium, 4 Low
Dependency TrackDEPTRACK_SBOM_SCANNER_IMAGEregistry.gitlab.com/to-be-continuous/tools/dt-sbom-scanner:latest 4 High, 12 Medium, 8 Low, 4 Unknown
DockerDOCKER_BUILDAH_IMAGEquay.io/containers/buildah:latest
DockerDOCKER_DIND_IMAGEdocker.io/library/docker:dind 4 Critical, 33 High, 51 Medium, 9 Low, 20 Unknown
DockerDOCKER_HADOLINT_IMAGEdocker.io/hadolint/hadolint:latest-alpine 2 Critical, 6 High, 31 Medium, 11 Low, 4 Unknown
DockerDOCKER_IMAGEdocker.io/library/docker:latest 4 Critical, 33 High, 51 Medium, 9 Low, 20 Unknown
DockerDOCKER_KANIKO_IMAGEregistry.gitlab.com/to-be-continuous/tools/kaniko:latest 2 Critical, 28 High, 25 Medium, 11 Low, 10 Unknown
DockerDOCKER_SBOM_IMAGEdocker.io/anchore/syft:debug 3 High, 3 Medium, 1 Low
DockerDOCKER_SKOPEO_IMAGEquay.io/containers/skopeo:latest
DockerDOCKER_TRIVY_IMAGEdocker.io/aquasec/trivy:latest not fetched
.NETDOTNET_IMAGEmcr.microsoft.com/dotnet/sdk:10.0 5 Medium, 4 Low
.NETDOTNET_INFERSHARP_IMAGEmcr.microsoft.com/infersharp:latest 10 Critical, 68 High, 146 Medium, 139 Low, 15 Unknown
.NETDOTNET_SBOM_IMAGEghcr.io/cyclonedx/cdxgen:master 3 Critical, 50 High, 68 Medium, 4 Low, 22 Unknown
.NETDOTNET_SEMGREP_IMAGEdocker.io/semgrep/semgrep:latest 4 High, 10 Medium, 7 Low, 4 Unknown
Google CloudGCP_CLI_IMAGEgcr.io/google.com/cloudsdktool/cloud-sdk:latest 12 Critical, 265 High, 984 Medium, 836 Low, 80 Unknown
GitleaksGITLEAKS_IMAGEdocker.io/zricethezav/gitleaks:latest 5 High, 14 Medium, 7 Low, 5 Unknown
GitOpsGITOPS_IMAGEdocker.io/alpine/git:latest 5 High, 11 Medium, 7 Low, 4 Unknown
GitLab PackageGLPKG_IMAGEdocker.io/curlimages/curl:latest
GoGO_CI_LINT_IMAGEdocker.io/golangci/golangci-lint:latest-alpine 25 High, 40 Medium, 6 Low, 28 Unknown
GoGO_IMAGEdocker.io/library/golang:bookworm 2 Critical, 167 High, 797 Medium, 668 Low, 36 Unknown
GoGO_SBOM_IMAGE$GO_IMAGE not fetched
GoGO_SEMGREP_IMAGEdocker.io/semgrep/semgrep:latest 4 High, 10 Medium, 7 Low, 4 Unknown
GradleGRADLE_IMAGEdocker.io/library/gradle:latest 1 High, 80 Medium, 29 Low
HelmfileHELMFILE_CLI_IMAGEghcr.io/helmfile/helmfile:latest 10 Critical, 71 High, 150 Medium, 17 Low, 12 Unknown
HelmHELM_CLI_IMAGEdocker.io/alpine/helm:latest 2 High, 7 Medium, 6 Low, 4 Unknown
HelmHELM_KUBE_SCORE_IMAGEdocker.io/zegl/kube-score 14 Critical, 85 High, 145 Medium, 8 Low, 3 Unknown
HelmHELM_YAMLLINT_IMAGEdocker.io/cytopia/yamllint 9 High, 13 Medium, 1 Low
HurlHURL_IMAGEghcr.io/orange-opensource/hurl:latest 2 Critical, 6 High, 27 Medium, 9 Low, 4 Unknown
k6K6_IMAGEdocker.io/grafana/k6:latest 6 High, 12 Medium, 6 Low, 6 Unknown
KubernetesK8S_KUBECTL_IMAGEdocker.io/alpine/k8s:MUST_SET_VERSION not fetched
KubernetesK8S_KUBE_SCORE_IMAGEdocker.io/zegl/kube-score:latest 14 Critical, 85 High, 145 Medium, 8 Low, 3 Unknown
LighthouseLHCI_IMAGEdocker.io/cypress/browsers:latest 2 Critical, 38 High, 119 Medium, 248 Low, 32 Unknown
GNU MakeMAKE_IMAGEdocker.io/alpinelinux/build-base
MavenMAVEN_IMAGEdocker.io/library/maven:latest 1 High, 70 Medium, 29 Low
MkDocsMKD_IMAGEdocker.io/squidfunk/mkdocs-material:latest 10 High, 9 Medium, 5 Low, 4 Unknown
MkDocsMKD_LYCHEE_IMAGEdocker.io/lycheeverse/lychee:latest 1 Critical, 7 High, 34 Medium, 76 Low, 7 Unknown
MobSFMOBSF_CLIENT_IMAGEdocker.io/badouralix/curl-jq 3 High, 7 Medium, 6 Low, 4 Unknown
MobSFMOBSF_CODE_IMAGEdocker.io/opensecurity/mobsfscan:latest 4 Critical, 133 High, 666 Medium, 582 Low, 23 Unknown
AngularNG_CLI_IMAGEdocker.io/trion/ng-cli-karma:latest 2 Critical, 181 High, 829 Medium, 797 Low, 63 Unknown
AngularNG_SEMGREP_IMAGEdocker.io/semgrep/semgrep:latest 4 High, 10 Medium, 7 Low, 4 Unknown
Node.jsNODE_IMAGEdocker.io/library/node:lts-alpine 8 High, 9 Medium, 6 Low, 4 Unknown
Node.jsNODE_SEMGREP_IMAGEdocker.io/semgrep/semgrep:latest 4 High, 10 Medium, 7 Low, 4 Unknown
OSS Review Toolkit (ORT)ORT_SCANNER_IMAGEghcr.io/oss-review-toolkit/ort:latest 25 Critical, 176 High, 1841 Medium, 153 Low, 12 Unknown
OpenShiftOS_CLI_IMAGEquay.io/openshift/origin-cli:latest 9 High, 10 Medium, 1 Low, 1 Unknown
PHPPHP_IMAGEdocker.io/library/php:latest 47 High, 341 Medium, 600 Low, 22 Unknown
PlaywrightPLAYWRIGHT_IMAGEmcr.microsoft.com/playwright:latest 27 High, 914 Medium, 177 Low
PostmanPOSTMAN_IMAGEdocker.io/postman/newman:latest 1 Critical, 37 High, 40 Medium, 11 Low
pre-commitPRE_COMMIT_IMAGEdocker.io/library/python:3-alpine 2 High, 7 Medium, 6 Low, 4 Unknown
PuppeteerPUPPETEER_IMAGEghcr.io/puppeteer/puppeteer:latest 112 Critical, 490 High, 1202 Medium, 1013 Low, 45 Unknown
PythonPYTHON_IMAGEdocker.io/library/python:3-slim 6 High, 21 Medium, 70 Low, 6 Unknown
RenovateRENOVATE_IMAGEdocker.io/renovate/renovate:latest 1 Critical, 6 High, 609 Medium, 53 Low, 1 Unknown
Robot FrameworkROBOT_BASE_IMAGEdocker.io/ppodgorsek/robot-framework:latest 1 Critical, 11 High, 5 Medium, 2 Low
RPMRPM_BASE_IMAGEdocker.io/fedora
RPMRPM_BUILD_IMAGE$RPM_BASE_IMAGE not fetched
RPMRPM_LINT_IMAGE$RPM_BASE_IMAGE not fetched
RustRUST_IMAGEdocker.io/library/rust:latest 3 Critical, 139 High, 522 Medium, 951 Low, 40 Unknown
Source-to-ImageS2I_DIND_IMAGEdocker.io/library/docker:dind 4 Critical, 33 High, 51 Medium, 9 Low, 20 Unknown
Source-to-ImageS2I_SKOPEO_IMAGEquay.io/containers/skopeo:latest
Source-to-ImageS2I_TRIVY_IMAGEdocker.io/aquasec/trivy:latest not fetched
S3 (Simple Storage Service)S3_CMD_IMAGEdocker.io/d3fk/s3cmd:latest 2 High, 6 Medium, 6 Low, 4 Unknown
Scala/SBTSBT_IMAGEdocker.io/sbtscala/scala-sbt:17.0.2_1.6.2_3.1.3 56 Critical, 307 High, 457 Medium, 841 Low, 32 Unknown
Scala/SBTSBT_SBOM_IMAGEdocker.io/anchore/syft:debug 3 High, 3 Medium, 1 Low
semantic-releaseSEMREL_IMAGEdocker.io/library/node:lts-slim 1 Critical, 12 High, 36 Medium, 74 Low, 7 Unknown
SonarQubeSONAR_SCANNER_IMAGEdocker.io/sonarsource/sonar-scanner-cli:latest 37 High, 4 Medium, 7 Low
SpectralSPECTRAL_IMAGEdocker.io/stoplight/spectral:latest 23 High, 32 Medium, 10 Low
SphinxSPHINX_IMAGEghcr.io/sphinx-doc/sphinx:latest 72 Critical, 209 High, 220 Medium, 214 Low, 9 Unknown
SphinxSPHINX_LYCHEE_IMAGEdocker.io/lycheeverse/lychee:latest 1 Critical, 7 High, 34 Medium, 76 Low, 7 Unknown
SQLFluff lintSQLFLUFF_IMAGEdocker.io/sqlfluff/sqlfluff:latest 3 Critical, 27 High, 68 Medium, 108 Low, 8 Unknown
Test SSLTESTSSL_IMAGEdocker.io/drwetter/testssl.sh:latest
TerraformTF_CHECKOV_IMAGEdocker.io/bridgecrew/checkov 2 Critical, 25 High, 57 Medium, 115 Low, 7 Unknown
TerraformTF_DOCS_IMAGEquay.io/terraform-docs/terraform-docs:edge 5 High, 5 Medium, 2 Low, 5 Unknown
TerraformTF_IMAGEdocker.io/hashicorp/terraform:latest 1 Critical, 7 High, 13 Medium, 6 Low, 5 Unknown
TerraformTF_INFRACOST_IMAGEdocker.io/infracost/infracost 88 Critical, 857 High, 827 Medium, 33 Low, 12 Unknown
TerraformTF_PUBLISH_IMAGEdocker.io/curlimages/curl:latest
TerraformTF_TFLINT_IMAGEghcr.io/terraform-linters/tflint:latest 2 Critical, 12 High, 14 Medium, 7 Low, 5 Unknown
TerraformTF_TFSEC_IMAGEdocker.io/aquasec/tfsec-ci 4 Critical, 28 High, 68 Medium, 16 Low, 5 Unknown
TerraformTF_TRIVY_IMAGEdocker.io/aquasec/trivy not fetched
ZolaZOLA_IMAGEdocker.io/jauderho/zola:latest
ZolaZOLA_LYCHEE_IMAGEdocker.io/lycheeverse/lychee:latest 1 Critical, 7 High, 34 Medium, 76 Low, 7 Unknown