How to start with Dependency Scanning

Dependency scanning is a practice of scanning software projects and computer systems in order to enumerate all dependencies, notify users about available updates, vulnerabilities, and security fixes. We focus mainly on GitLab CI/CD, but the principles can be applied to other CI/CD environments as well.

25 Sep 2025 Adam Chovanec Matěj Smyčka DevOps

No description

Dependency Scanning


Introduction


Modern software is composed of numerous components, each component having its own dependencies. It is not uncommon for a project to have hundreds of dependencies. A security vulnerability affecting a single component could endanger the whole product. Regular updates of dependencies prevent accumulation of technical debt and keep users and their data secure.

How it works


Dependency scanners employ several techniques for enumerating all components used in a software project, such as parsing lock files (e.g., package-lock.json, poetry.lock, or Cargo.lock) or scanning the filesystem and looking for known binaries or git submodules. When enumerating software components present in a Docker container, packages installed through the distribution package manager are enumerated as well.

The resulting document describing software components is called a Software Bill of Materials (SBOM). There are several well known SBOM formats, such as CycloneDX or SPDX, and several tools that generate them, such as syft or sbom-tool.

There are many use cases for SBOMs. For instance, SBOMs can be used to check for outdated components that are missing security fixes. Grype can be used to generate a vulnerability report from an SBOM with ease (and we write more about it in the following sections).

Security: GitLab's Dependency Scanning


Dependencies should be scanned regularly and frequently. It is not feasible or practical to do it manually. For this reason it is recommended to include dependency scanning in existing CI/CD workflows.

GitLab has a built-in Dependency Scanning feature. To enable it, add the following few lines to your .gitlab-ci.yml file:

1. Dependency scanning is available on gitlab.muni.cz. It requires Ultimate tier subscription for use on gitlab.com.

 

include:
  - template: Jobs/Dependency-Scanning.gitlab-ci.yml

The Dependency Scanning job generates an SBOM with detected dependencies. The Dependency list is located under the Security tab of the GitLab project. It showcases the dependencies and their potential vulnerabilities. You can see the overview of detected vulnerabilities in the Vulnerability Report tab where you can triage the results. You can see the results in the pictures below.

Screenshot of a software Bill of Materials (SBOM) showing a list of dependencies with details including the component, packager, location, license, and the number of vulnerabilities detected for each.
Screenshot of a Vulnerability Report interface showing results of security scans, summarizing vulnerabilities by severity levels such as critical, high, medium, low, and unknown, and listing specific detected vulnerabilities with their status and severity.

It is important to handle the findings methodically, as the findings have differing severity. We recommend prioritizing findings based on the risk they pose to the application. Most vulnerabilities can be fixed by updating the vulnerable component to a secure version. In come cases, update is not feasible and it may be needed to choose a different dependency or mitigate the issue by other means.

GitLab's Dependency Scanning provides a simple way to implement dependency scanning with pleasant out-of-the-box experience. Tight integration with GitLab security features is unmatched. Learn more about the features of GitLab's Dependency Scanning in the official documentation, where you can find all configuration options, tutorials, and other helpful tips.

GitLab offers more useful security features besides Dependency Scanning, such as scanning accidentally committed secrets, scanning containers in registry, or performing a static analysis of the source code for potential vulnerabilities. Many of them are as easily configurable as Dependency Scanning, we highly encourage you to check them out!

Updates: Renovate


One feature missing from GitLab's Dependency Scanning are notifications about new versions. After all, it is much easier to patch critical vulnerabilities if the dependency versions are recent and the technical debt is kept within reasonable limits. Renovate helps developers by notifying them about new versions of software dependencies. It also provides information about vulnerabilities, so it is best to use it together with GitLab's dependency scanning.

Renovate is not limited to GitLab as it supports 9 platforms and tracks dependencies in over 90 package managers. Renovate typically runs periodically on your repository within a CI/CD pipeline. It creates an issue called Dependency dashboard that tracks identified dependencies. It is able to open merge requests with updated dependencies, including updating lock files of various formats. It is also highly configurable to suite specific needs. You can see a merge request created by Renovate on the picture below or in the Demo Renovate Standalone Project on our GitLab.

There are two options how to set up Renovate on GitLab (and on gitlab.ics.muni.cz specifically):

  1. Set up Renovate for a whole group
  2. Set up Renovate on a per-project basis

In the paragraphs below we describe the recommended configuration setup.

How to set up Renovate for a group

Setting up Renovate for every new project can be somewhat cumbersome. For this reason it is very convenient to set it up once and use the Renovate bot for a whole group. You can see a working example on our GitLab: Demo Renovate Group.

Warning

Renovate requires a group access token with role Developer and API scope. Providing Renovate bot to untrusted parties is not secure due to GitLab's lacking API design. Namely, a malicious maintainer could in specific scenarios manipulate package and container registries and read Terraform states (with secrets) of other projects sharing the Renovate token, even if the said maintainer doesn't have a direct access to these projects. For this reason, we recommend having a separate Renovate bot, with a separate token, for each group. As long as all maintainers within the group are trusted, the risk is somewhat lower. To learn more, consult the documentation and the accompanying article.

We need to create a new project in the group that will host Renovate's configuration and the CI/CD pipelines. Let's call it renovate-bot. Create renovate.json file with the following contents. It is the default configuration file extended by a preset that updates the Renovate's bot itself:

{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": [
    "config:recommended",
    "gitlab>renovate-bot/renovate-runner"
  ]
}

Let's configure the CI/CD pipeline by creating .gitlab-ci.yml file with the following contents. Don't forget to change the value of the RENOVATE_EXTRA_FLAGS variable. The variable is an additional safeguard to make sure that the Renovate bot will not touch projects outside of the group you configure it in.

# renovate should update the release tag `v24.0.0` to the latest version by itself
include:
  - remote: https://gitlab.com/renovate-bot/renovate-runner/-/raw/v24.0.0/templates/renovate.gitlab-ci.yml

# instead of 'dependency-scanning-demo' use the path of your group
variables: RENOVATE_EXTRA_FLAGS: '--autodiscover=true --onboarding=false \
--autodiscover-filter=dependency-scanning-demo/*'
# required changes for gitlab.ics.muni.cz compatibility renovate: image: pull_policy: if-not-present

The configuration above makes sure that Renovate only processes projects with a renovate.json file in the default branch. This enables you to gradually set up renovate in your group. If you want to set up Renovate for all projects in the group right away, set --onboarding=true instead of --onboarding=false. Renovate will create a merge requests in all projects it sees adding the renovate.json file. Renovate will not merge it, that's up to you to decide. Close the merge request if you want to exclude some project.

We need to create a group access token for Renovate. Open the group Settings, Access tokens, and create a new access token called RENOVATE_BOT 2. The token requires Developer role with api scope. Next, open the renovate-bot project created earlier and go to Settings, CI/CD, Variables, and create a CI/CD variable called RENOVATE_TOKEN with the group access token created previously as the value. Set the masked and hidden option for it to hide it from CI/CD logs.

2. You can, of course, choose whichever name you want. The token name will be used as the author of GitLab issues, merge requests, and (by default) commits.

Do not use a personal token

Some Renovate guides recommend using a personal token instead of project or group access token. If you use a personal token, then you run into risk of affecting all repositories you have access to and creating many issues and merge requests at once. It is therefore better to use project and group access tokens.

For Renovate to work correctly, its needs an API token for GitHub to check releases and release notes of the public dependencies. The token does not require any permissions, so it is safe to use your personal account. Log in to GitHub, go to Settings, Developer settings, Personal access tokens, and Fine-grained tokens. Create a token called RENOVATE_TOKEN with access to public projects and no additional permissions. Then create a new CI/CD variable in the renovate-bot project called GITHUB_COM_TOKEN with value of the token you've just created. Set the masked and hidden option for it to hide it from CI/CD logs.

Renovate's CI/CD does run only in scheduled pipelines. Create a pipeline schedule to run the pipeline periodically. In the renovate-bot project, go to Build, Pipeline schedules and create a new schedule. Run the scheduled pipeline right away.

If everything went well, you should see a new issue in the renovate-bot project titled Dependency Dashboard. The dashboard lists all identified dependencies, hints on configuration problems, and includes a list of opened merge requests for updated dependencies.

If you used --onboarding=true in the RENOVATE_EXTRA_FLAGS variable, then Renovate should automatically open merge requests in the projects in your group. If not, create renovate.json with the default configuration in projects you want to enable Renovate on:

{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": [
    "config:recommended"
  ]
}

How to set up Renovate for a single project

The following tutorial sets up Renovate for a single project. It is useful for testing and for security-sensitive environments, as the bot is local only to the project itself and isn't shared with a group. Check out the example project we created to see the configuration for yourself.

Open the project you want to configure Renovate for. Create a project access token and the CI/CD variables. The names and required permission are the same as if setting it up for a group. Now let's create a new branch that will contain the CI/CD configuration. We do this to keep the Renovate pipeline separate from the main pipeline (we want only Renovate to run and skip other jobs that would run on the default branch, such as tests and builds). Create a new empty branch:

git switch --orphan renovate-bot

Create .gitlab-ci.yml in the renovate-bot branch with the following contents:

# renovate should update the release tag `v24.0.0` to the latest version by itself
include:
  - remote: https://gitlab.com/renovate-bot/renovate-runner/-/raw/v24.0.0/templates/renovate.gitlab-ci.yml
    
variables:
  RENOVATE_EXTRA_FLAGS: '--autodiscover=true --onboarding=false'

# required changes for gitlab.ics.muni.cz compatibility
renovate:
  image:
    pull_policy: if-not-present

Commit the files and push the renovate-bot branch to GitLab. Set the branch as protected, as it holds the CI/CD configuration with API access token.

Now go to the default branch of your project (usually main or master) and create a renovate.json file within with the following contents. It is the same as above with an addition of the baseBranchPatterns option. By default, Renovate runs only on the default branch. We want it to also update the Renovate runner itself in the renovate-bot branch. Hence the change.

{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": [
    "config:recommended",
    "gitlab>renovate-bot/renovate-runner"
  ],
  "baseBranchPatterns": ["$default", "renovate-bot"]
}

Commit the file. Now create a pipeline schedule on the renovate-bot branch and trigger the pipeline. You should see the Dependency Dashboard appear.

Advanced configurations and other sources

Consult the documentation for more configuration options. You can, for example, add a default assignee, add merge request labels, or group all minor updates together.

Modern programming languages


Modern languages have their own ecosystem, which usually includes a package manager with a built-in dependency scanning tool. Some examples are:

The last two are not yet fully integrated and are not as mature as the others.

Other tools to consider


GitHub has its own built-in dependency scanning tool called Dependabot. It is a bot that automatically creates pull requests to update dependencies in your repository and sends you notifications about vulnerabilities in your dependencies.

Syft is a tool for creating SBOMs from software projects and containers. Grype is a security-focused tool for checking vulnerabilities in dependencies, containers, and file systems. Grype supports 13 operating system packages and many programming language specific packages. You can either generate the SBOM with Syft and pass it to Grype, or just run Grype, as it generates the SBOM internally. The integration between Syft/Grype and CI/CD pipelines is lacking, so it is best to use them locally. Below are a few common use cases:

# check out dependencies
syft .

# save the SBOM to a file
syft . -o cyclonedx-json > sbom.json

# scan the SBOM for vulnerabilities
grype sbom:sbom.json

# scan project in the local directory directly with Grype
grype .

# scan a container
grype docker:docker.io/debian:latest --only-fixed

Trivy is an alternative to the aforementioned Grype and fulfills a similar use case. In addition to vulnerabilities, it is also able to scan exposed secrets and common misconfigurations in infrastructure as code (IaC) repositories. Here are the commands:

# scan project in the local directory
trivy filesystem .

# scan a container
trivy image docker.io/debian:latest --ignore-unfixed

OSV-Scannner by Google and Dependency-Check by OWASP are other security-focused tools that can be used for dependency scanning.

Summary


In this guide we showcased GitLab's Dependency Scanning which is very easy to set up and provides alerts about vulnerable software components in certain projects. We then covered Renovate, which is a bit harder to set up first time, but covers much more languages and helps you update your dependencies easily. Finally, we showed a few additional manual tools to consider.

If you have any questions regarding the tutorial or want help with configurating it, feel free to contact us at csirt@muni.cz.

This result was supported by the SOCCER project, funded under Grant Agreement No. 101128073, with the support of the European Cybersecurity Competence Center (ECCC).

You are running an old browser version. We recommend updating your browser to its latest version.

More info