Dependency Scanning in GitLab CI: Setup and Configuration

Published:

Skipping dependency scanning in CI is like shipping a release with a door left wide open, and teams still do it.
This post shows how to set up dependency scanning in GitLab CI, what it needs, and how to make the scan actually block bad packages.
You’ll see the quick include to enable the built-in scanner, how manifest detection and analyzer images work, and a small script to fail pipelines on high or critical findings.
Follow along to catch transitive CVEs early and stop risky deps from reaching production.

Implementing Dependency Scanning in GitLab CI Pipelines

8Ret7gUDXtqpxjP6RXCrDw

You’ll need GitLab Ultimate tier (or equivalent licensing for self-managed and dedicated installations) to set up dependency scanning. Your project needs a test stage in .gitlab-ci.yml, plus at least one runner configured with the docker or kubernetes executor. Shared runners on GitLab.com already meet this requirement. Scanner images are built for Linux/amd64 architecture.

Dependency scanning kicks in automatically when it spots manifest files like requirements.txt, yarn.lock, or Gemfile.lock within two directory levels of your repo root. The analyzer pulls an image (something like gitlab.com/security-products/gemnasium-python:5), runs /analyzer run, and spits out gl-dependency-scanning-report.json as a pipeline artifact. Every dependency gets analyzed against GitLab’s vulnerability database, including transitive ones.

The fastest way to enable scanning is through GitLab’s built-in template. Add this to your .gitlab-ci.yml:

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

This include needs to come before any job overrides. The template automatically creates a dependency scanning job in the test stage, so you don’t need to define it yourself. If you’re redefining stages in your config, make sure you declare a test stage or the scanning job won’t show up in your pipeline.

GitLab CI Configuration and Dependency Scanner Job Behavior

Zje6scRxVp20n84zu9HtMw

When you include the dependency scanning template, GitLab creates a job called gemnasium-dependencyscanning (or a language-specific variant like gemnasium-python-dependencyscanning) in the test stage. This job pulls the right analyzer image from gitlab.com/security-products, runs /analyzer run, and uploads gl-dependency-scanning-report.json to pipeline artifacts. Your runner has to support the docker or kubernetes executor. Without it, image pulls and container-based analysis won’t work.

Manifest detection only goes two directory levels deep from your repo root. Files nested deeper get ignored. Keep requirements.txt, package-lock.json, and similar manifests at or near the top of your project. When you’ve got multiple manifest files, GitLab runs all matching analyzers in parallel and auto-detects your language stack without extra config.

The scanner job works like this:

  1. Pulls the analyzer container image from the template (example: gitlab.com/security-products/gemnasium-python:5).
  2. Scans the repository for manifest files within the two-directory depth limit.
  3. Runs /analyzer run to parse manifests and query the vulnerability database.
  4. Generates gl-dependency-scanning-report.json with CVE details, affected packages, and severity levels.
  5. Uploads the JSON report as a pipeline artifact and pushes it to the merge request UI.

Supported Languages and Package Manager Coverage for GitLab Dependency Scanning

6cylOM8JWO6fE1QjUym2oA

GitLab’s dependency scanner covers multiple ecosystems through manifest-based auto-detection. When the analyzer finds a recognizable package file, it runs the corresponding scanner. No per-language configuration required. JavaScript projects with package.json, Ruby projects with Gemfile.lock, and Python projects with requirements.txt all trigger their respective analyzers automatically.

Here’s what’s commonly supported:

Language Manifest File Analyzer Behavior
JavaScript / TypeScript package.json, yarn.lock Scans npm and Yarn dependencies; includes transitive packages
Python requirements.txt, Pipfile.lock Analyzes pip and pipenv installs; uses gemnasium-python analyzer
Ruby Gemfile.lock Scans bundler dependencies and nested gems
Java / Kotlin pom.xml, build.gradle Parses Maven and Gradle dependencies; covers direct and transitive

If you’re running a multi-language project (Node.js frontend, Python backend), GitLab runs all applicable analyzers in the same pipeline and merges findings into a single report.

Reading and Interpreting Dependency Scanning Results in GitLab

jwK3OU4pWCW2dt_6vE8DKg

Once the dependency scanning job finishes, GitLab uploads gl-dependency-scanning-report.json to pipeline artifacts and displays findings in the merge request security widget. Each vulnerability includes a CVE identifier, package name, installed version, fixed version (when available), severity level, and a description. You can download gl-dependency-scanning-report.json from the pipeline artifacts page to run custom analyses or integrate with external tools.

Vulnerabilities show up in the merge request UI as a list organized by severity. GitLab gives you recommended mitigation steps for each finding, usually pointing to the package version that patches the CVE. Click a vulnerability to see detailed metadata, including the affected dependency path and links to upstream CVE databases.

The report JSON contains an array of vulnerabilities, each with fields like id, severity, name (CVE), and location (package and version). This makes it easy to parse programmatically if you want to build custom gates or alerts.

Severity Levels and Prioritization

GitLab uses four severity tiers: low, medium, high, and critical. Critical findings represent actively exploited vulnerabilities with public exploits and widespread impact. High-severity issues are serious flaws that could allow unauthorized access or data leakage under common conditions. Medium and low findings are lower-priority issues that depend on specific configurations or attack scenarios.

Prioritize critical and high findings first. Upgrade the vulnerable package or apply the recommended patch, then rerun the pipeline to confirm the CVE no longer appears in the report.

Failing GitLab CI Pipelines Based on Dependency Vulnerabilities

OsPPD7RDXxOKlU5KxAlxJA

By default, the dependency scanning job won’t fail your pipeline even when high-severity vulnerabilities turn up. GitLab generates the report and uploads it, but the job exits with status 0. If you want to block merges or deployments when critical CVEs are present, you need to override the job’s allow_failure setting and add custom logic to parse the JSON report.

Set allow_failure: false on your dependency scanning job and install jq to parse gl-dependency-scanning-report.json. This snippet counts high-severity findings and fails the job if any are found:

gemnasium-python-dependency_scanning:
  allow_failure: false
  before_script:
    - sudo apt-get update -y && sudo apt-get install -y jq
  script:
    - /analyzer run
    - HIGH_COUNT=$(jq '[.vulnerabilities[] | select(.severity == "High")] | length' gl-dependency-scanning-report.json)
    - |
      if [ "$HIGH_COUNT" -gt 0 ]; then
        echo "Found $HIGH_COUNT high-severity vulnerabilities. Failing pipeline."
        exit 1
      fi

This runs the analyzer, parses the output, checks for high-severity entries, and exits non-zero when vulnerabilities are detected. You can adjust the severity threshold by changing “High” to “Critical” or adding medium-severity checks. Pair this with a deploy job that depends on the test stage. When the dependency scanning job fails, the deploy stage won’t run, gating production releases on clean security scans.

Troubleshooting Dependency Scanning in GitLab CI Pipelines

1bYRVVJoXCOj7qowUUzkyw

When dependency scanning jobs fail, the most common culprit is missing or inaccessible manifest files. Analyzers search only within two directory levels of the repo root. If your requirements.txt or package.json is nested deeper, the scanner will report no dependencies found. Move manifest files closer to the root or commit them to the repository if they’re in .gitignore.

Runner configuration issues also cause frequent failures. If your runner doesn’t support the docker or kubernetes executor, the job can’t pull the analyzer image. Verify executor settings in your runner configuration and confirm network access to gitlab.com/security-products registry. Python projects sometimes hit an “exit status 1” error with no clear message. This often means a required package is unavailable during analysis. Install missing dependencies in the beforescript block of the gemnasium-python-dependencyscanning job.

Common troubleshooting checks:

  • Confirm manifest files (requirements.txt, yarn.lock) are committed and within two directory levels of the repo root.
  • Check that your GitLab Runner uses docker or kubernetes executor. Shell or SSH executors can’t run the analyzer containers.
  • Verify network access to gitlab.com/security-products images. Firewall rules or registry mirrors can block pulls.
  • For Python projects with ambiguous failures, add package installation steps to before_script.
  • Ensure jq is installed if you added custom severity-parsing logic. Without it, JSON parsing will silently fail.

Best Practices for Managing Vulnerabilities and Using GitLab Security Tools

Xu2ubM_QWL2O5DSNqOYBhg

Run dependency scanning in the test stage early in your pipeline to catch issues before deploy or build stages. Keep manifest lock files (yarn.lock, Pipfile.lock, Gemfile.lock) committed in version control. Lock files ensure repeatable scans and prevent dependency drift between local development and CI. Configure severity thresholds that match your risk tolerance: fail pipelines on critical and high findings, but allow medium and low issues to pass while you plan fixes.

Use gl-dependency-scanning-report.json as a durable record of vulnerabilities. Archive this artifact with your pipeline and correlate findings with merge request discussions or issue trackers. When you fix a vulnerability by upgrading a package, rerun the pipeline to confirm the CVE no longer appears. This workflow creates an audit trail showing when the issue was detected, patched, and verified.

Set deploy stage dependencies so deployment jobs won’t run if the dependency scanning job fails. This gates production releases on security approval and prevents vulnerable code from reaching live environments. Combine this with branch protection rules that require security scans to pass before merge.

Organizational Enforcement and Monitoring

For organization-wide enforcement, use GitLab’s scan execution policies and security dashboard. Scan execution policies automatically enable dependency scanning across all projects in a group without requiring per-project .gitlab-ci.yml edits. This is useful when teams forget to add the template or need consistent standards.

The security dashboard aggregates vulnerability trends over time, showing how many high-severity issues exist across your organization and which projects have unresolved findings. Review the dashboard weekly to identify persistent vulnerabilities and track remediation progress. Monitor the number of new vulnerabilities introduced per merge request, and investigate spikes that suggest outdated dependency practices or missing pre-commit checks.

Final Words

Set up Ultimate-tier prerequisites, use Docker or Kubernetes runners, and include Security/Dependency-Scanning.gitlab-ci.yml in the test stage to add the gemnasium job and produce gl-dependency-scanning-report.json.

Use manifests like package.json or requirements.txt so analyzers run automatically, parse the JSON for gating when you need to fail pipelines, and fix issues then rerun.

You’re in a good spot to iterate and tighten rules. dependency scanning in gitlab ci will catch new issues so you can fix them before they reach production.

FAQ

Q: What are the prerequisites and license needed for dependency scanning in GitLab CI?

A: The prerequisites and license needed for dependency scanning in GitLab CI are GitLab.com Ultimate (or equivalent self‑managed), runners with docker/kubernetes executors, and manifest files reachable within two directory levels.

Q: How do scanners detect manifest files and run analyzers?

A: Scanners detect manifest files up to two directory levels, auto-select analyzers, and run the analyzer image (for example gitlab.com/security-products/gemnasium-python:5) using /analyzer run to produce gl-dependency-scanning-report.json.

Q: How do I enable dependency scanning via .gitlab-ci.yml?

A: You enable dependency scanning by adding include: – template: Security/Dependency-Scanning.gitlab-ci.yml to .gitlab-ci.yml; the template creates a job in the test stage. You can also write a custom job if needed.

Q: What does the dependency scanning job do and what artifact is produced?

A: The dependency scanning job (gemnasium-dependencyscanning or gemnasium-python-dependencyscanning) pulls the analyzer image, detects manifests, runs /analyzer run, produces gl-dependency-scanning-report.json, and uploads it as an artifact.

Q: Which languages and manifest files does GitLab dependency scanning support?

A: Supported languages include Java, Kotlin, JavaScript, TypeScript, Ruby, and Python; manifests include requirements.txt, Gemfile.lock, package.json, and yarn.lock — analyzers auto-run when those manifests are found.

Q: How do I read and interpret dependency scanning results in GitLab?

A: You read results from gl-dependency-scanning-report.json and the merge request UI, which display vulnerabilities with severity levels, CVE metadata, and remediation suggestions to guide triage and fixes.

Q: What are the severity levels and how should I prioritize fixes?

A: Severity levels are low, medium, and high; prioritize high and exploit-prone findings first, then medium, then low. Start with fixes that have CVEs or known public exploits for fastest risk reduction.

Q: How can I fail pipelines based on dependency vulnerabilities?

A: By default pipelines don’t fail on vulnerabilities; to gate them set allow_failure:false or add a job that uses jq to count high-severity items in gl-dependency-scanning-report.json and exit non‑zero when thresholds are exceeded.

Q: What are common troubleshooting steps for dependency scanning failures?

A: Common issues include missing manifests, depth-limit misses, runner failing to pull the analyzer image, and analyzer exit errors; fix by moving manifests, verifying executor type, ensuring network access, and adding required packages in before_script.

Q: What are best practices for managing vulnerabilities and using GitLab security tools?

A: Best practices are to triage and fix findings, rerun pipelines to confirm, use the Security Dashboard for tracking, and enforce scan execution policies or org rules to prevent vulnerable dependencies reaching production.

curtisharmon
Curtis has spent over two decades guiding hunters and anglers through the backcountry of Montana and Wyoming. His expertise in elk hunting and fly fishing has made him a sought-after voice in the outdoor community. Curtis combines traditional woodsmanship with modern techniques to help readers succeed in the field.

Related articles

Recent articles