supply chain
GitLab Ultimate Supply Chain Security
This guide covers software supply chain security in GitLab Ultimate including SBOM generation and management, dependency tracking, license compliance, provenance and attestation, and supply chain risk mitigation. Supply chain security ensures the integrity and security of all software components.
Overview
GitLab Ultimate provides comprehensive supply chain security:
- SBOM Generation - CycloneDX Software Bill of Materials for all dependencies
- Dependency Tracking - Complete visibility into direct and transitive dependencies
- Vulnerability Management - Automated detection and remediation of vulnerable dependencies
- License Compliance - Track and enforce open source license policies
- Provenance & Attestation - Digital signatures and build artifact verification (planned 2026)
- Supply Chain Risk - Identify and mitigate supply chain attacks
Supply chain security protects against vulnerabilities, malicious packages, and compliance issues in third-party code.
Software Bill of Materials (SBOM)
Overview
A Software Bill of Materials (SBOM) is an "ingredient label" for software, listing all components, dependencies, and their metadata. GitLab automatically generates SBOMs in CycloneDX format.
SBOM Use Cases:
- Vulnerability management (identify affected components)
- License compliance (track all licenses)
- Risk assessment (understand dependency tree)
- Regulatory compliance (SBOM requirements in legislation)
- Incident response (quickly identify affected systems)
CycloneDX Format
CycloneDX SBOM Structure:
{ "bomFormat": "CycloneDX", "specVersion": "1.4", "version": 1, "metadata": { "timestamp": "2026-01-08T10:30:00Z", "component": { "name": "my-application", "version": "0.4.9", "type": "application" }, "tools": [ { "vendor": "GitLab", "name": "Dependency Scanning", "version": "0.4.9" } ] }, "components": [ { "type": "library", "name": "lodash", "version": "0.4.9", "purl": "pkg:npm/lodash@4.17.21", "licenses": [ { "license": { "id": "MIT" } } ], "hashes": [ { "alg": "SHA-256", "content": "fb14540d44423c4a9f66b9b8a0e1f6c1..." } ], "externalReferences": [ { "type": "website", "url": "https://lodash.com" }, { "type": "vcs", "url": "https://github.com/lodash/lodash" } ] }, { "type": "library", "name": "express", "version": "0.4.9", "purl": "pkg:npm/express@4.18.2", "licenses": [ { "license": { "id": "MIT" } } ], "dependencies": [ { "ref": "pkg:npm/body-parser@1.20.1" }, { "ref": "pkg:npm/cookie-signature@1.0.6" } ] } ], "dependencies": [ { "ref": "pkg:npm/express@4.18.2", "dependsOn": [ "pkg:npm/body-parser@1.20.1", "pkg:npm/cookie-signature@1.0.6" ] } ] }
Key Fields:
components: List of all dependenciespurl: Package URL (universal package identifier)licenses: SPDX license identifiershashes: Cryptographic hashes for integritydependencies: Dependency relationshipsexternalReferences: Links to documentation, source code
SBOM Generation
Automatic Generation:
GitLab automatically generates SBOMs through:
- Dependency Scanning - Analyzes lock files and manifests
- Container Scanning - Scans container image layers
Supported Ecosystems:
- JavaScript: npm, yarn, pnpm (package-lock.json, yarn.lock, pnpm-lock.yaml)
- Python: pip, poetry, pipenv (requirements.txt, Pipfile.lock, poetry.lock)
- Ruby: bundler (Gemfile.lock)
- Java: Maven, Gradle (pom.xml, build.gradle, *.gradle.kts)
- Go: go modules (go.mod, go.sum)
- PHP: Composer (composer.lock)
- C#/.NET: NuGet (packages.lock.json, project.assets.json)
- Rust: Cargo (Cargo.lock)
- Container Images: Docker, OCI images
Configuration:
# Enable Dependency Scanning (generates SBOM automatically) include: - template: Security/Dependency-Scanning.gitlab-ci.yml dependency_scanning: artifacts: reports: cyclonedx: "**/gl-sbom-*.cdx.json"
Container SBOM:
# Enable Container Scanning (generates SBOM for image) include: - template: Security/Container-Scanning.gitlab-ci.yml container_scanning: variables: CS_IMAGE: "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA" CS_SBOM_ENABLED: "true" artifacts: reports: cyclonedx: "**/gl-sbom-*.cdx.json"
Accessing SBOMs
Pipeline Artifacts:
- Navigate to: Pipelines > [Pipeline] > Jobs > dependency_scanning
- Click "Browse" under artifacts
- Download
gl-sbom-*.cdx.json
Dependency List (Ultimate):
- Navigate to: Security & Compliance > Dependency List
- View all dependencies with licenses and vulnerabilities
- Export as CSV or JSON
API Access:
# Get dependency list curl --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \ "https://gitlab.com/api/v4/projects/123/dependencies" # Get SBOM artifact curl --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \ "https://gitlab.com/api/v4/projects/123/jobs/456/artifacts" \ --output sbom.zip
SBOM Management
Version Control:
# Store SBOM in repository generate_sbom: stage: build script: - ./gradlew cyclonedxBom - cp build/reports/bom.json sbom.json artifacts: paths: - sbom.json expire_in: never commit_sbom: stage: publish script: - git config user.name "GitLab CI" - git config user.email "ci@example.com" - git add sbom.json - git commit -m "chore: update SBOM [skip ci]" || true - git push https://oauth2:$CI_JOB_TOKEN@$CI_SERVER_HOST/$CI_PROJECT_PATH.git HEAD:$CI_COMMIT_BRANCH only: - main
SBOM Registry:
# Publish SBOM to artifact registry publish_sbom: stage: publish script: # Upload SBOM to package registry - curl --header "JOB-TOKEN: $CI_JOB_TOKEN" \ --upload-file gl-sbom-npm-npm.cdx.json \ "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/sbom/${CI_COMMIT_TAG}/sbom.json" only: - tags
Dependency Management
Dependency Discovery
Dependency List Page:
GitLab Ultimate provides a centralized Dependency List:
- Navigate to: Security & Compliance > Dependency List
- View all dependencies across all projects (group level)
- Filter by:
- License type
- Vulnerability severity
- Project
- Component name
Information Displayed:
Dependency: lodash
Version: 4.17.21
Package Manager: npm
License: MIT
Vulnerabilities: 0
Projects Using: 23
Latest Version: 4.17.21
Direct Dependency: Yes
Transitive Dependencies: 0
Dependency Analysis
Dependency Tree:
# Generate dependency tree generate_dependency_tree: stage: test script: # npm - npm list --all > dependency-tree.txt # pip - pip install pipdeptree - pipdeptree > dependency-tree.txt # maven - mvn dependency:tree > dependency-tree.txt # gradle - ./gradlew dependencies > dependency-tree.txt artifacts: paths: - dependency-tree.txt
Example Output:
my-app@1.0.0
express@4.18.2
body-parser@1.20.1
bytes@3.1.2
content-type@1.0.4
raw-body@2.5.1
cookie@0.5.0
cookie-signature@1.0.6
lodash@4.17.21
axios@1.2.2
follow-redirects@1.15.2
form-data@4.0.0
Vulnerability Tracking
Vulnerable Dependencies:
GitLab automatically detects vulnerabilities in dependencies:
Detection:
- Dependency Scanning runs in pipeline
- Compares dependencies against vulnerability databases:
- GitLab Advisory Database (enhanced in Ultimate)
- National Vulnerability Database (NVD)
- GitHub Advisory Database
- Language-specific databases (npm, PyPI, RubyGems, etc.)
- Reports findings in Vulnerability Report
- Shows in merge request widget
Remediation:
# Automated dependency updates dependency_updates: stage: maintenance script: # Update npm dependencies - npm update - npm audit fix # Update Python dependencies - pip install --upgrade -r requirements.txt # Create MR with updates - git checkout -b "chore/dependency-updates-${CI_PIPELINE_ID}" - git add package-lock.json requirements.txt - git commit -m "chore: update vulnerable dependencies" - git push origin "chore/dependency-updates-${CI_PIPELINE_ID}" - glab mr create --title "chore: update vulnerable dependencies" --description "Automated dependency updates" when: manual only: - schedules
Dependency Updates
Manual Updates:
# npm npm update package-name npm audit fix npm audit fix --force # Breaking changes # pip pip install --upgrade package-name pip-review --auto # Update all # bundler (Ruby) bundle update package-name # Maven mvn versions:use-latest-versions # Gradle ./gradlew useLatestVersions
Automated Updates:
Renovate Bot:
// renovate.json { "extends": ["config:base"], "labels": ["dependencies"], "assignees": ["@team-lead"], "schedule": ["before 6am on monday"], "packageRules": [ { "matchUpdateTypes": ["minor", "patch"], "automerge": true, "automergeType": "pr", "automergeStrategy": "squash" }, { "matchUpdateTypes": ["major"], "automerge": false, "labels": ["breaking-change"] } ], "vulnerabilityAlerts": { "labels": ["security"], "assignees": ["@security-team"], "automerge": true } }
Dependabot (GitHub-style):
# .gitlab/dependabot.yml version: 2 updates: - package-ecosystem: "npm" directory: "/" schedule: interval: "weekly" reviewers: - "team-lead" labels: - "dependencies" open-pull-requests-limit: 10 - package-ecosystem: "pip" directory: "/" schedule: interval: "weekly" reviewers: - "python-team"
License Compliance
License Detection
Automatic Detection:
GitLab detects licenses from:
- Package metadata (package.json, pom.xml, Gemfile, etc.)
- LICENSE files in dependencies
- SPDX license identifiers
- License headers in source files
License Information in SBOM:
{ "component": { "name": "express", "version": "0.4.9", "licenses": [ { "license": { "id": "MIT", "name": "MIT License", "url": "https://opensource.org/licenses/MIT" } } ] } }
License Policies
Creating License Approval Policies:
- Navigate to: Security & Compliance > Policies
- Click "New policy"
- Select "License approval policy"
- Configure allowed and denied licenses
Policy Configuration:
# .gitlab/license-approval-policy.yml license_approval_policy: name: "Open Source License Policy" description: "Enforce approved open source licenses" # Approved licenses (no action required) approved_licenses: - MIT - Apache-2.0 - BSD-2-Clause - BSD-3-Clause - ISC - CC0-1.0 # Denied licenses (block merge request) denied_licenses: - GPL-3.0 - AGPL-3.0 - CC-BY-NC-4.0 - SSPL-1.0 # Requires approval (security/legal team review) approval_required_licenses: - Apache-1.0 - EPL-1.0 - MPL-2.0 - LGPL-3.0
License Compliance Workflow
Enforcement:
- Dependency/Container Scanning detects licenses
- License approval policy evaluates licenses
- If denied license found:
- Merge request blocked
- Security/legal approval required
- Eligible approver reviews and approves/rejects
Example:
Merge Request: Add React library
Detected License: MIT (approved)
Merge Request: Add GPL-licensed library
Detected License: GPL-3.0 (denied)
Status: Blocked
Required Approval: @legal-team
License Compliance Report
Viewing License Information:
- Navigate to: Security & Compliance > License Compliance
- View all detected licenses
- Filter by approval status
- Export for legal review
Report Format:
License Compliance Report - Project: my-app
Total Dependencies: 247
Unique Licenses: 12
Approved Licenses:
- MIT: 189 dependencies
- Apache-2.0: 34 dependencies
- BSD-3-Clause: 12 dependencies
- ISC: 8 dependencies
Approval Required:
- MPL-2.0: 3 dependencies (pending legal review)
Denied:
- GPL-3.0: 1 dependency (blocked)
- Component: example-gpl-library@1.0.0
- Used in: src/utils/helper.js
- Action Required: Remove or replace
Provenance and Attestation
Overview
Provenance and attestation provide cryptographic proof of:
- Where software was built (build environment)
- How it was built (build process)
- Who built it (identity)
- Integrity of artifacts (digital signatures)
Status in GitLab (2026):
- In Development: Automatic digital signing of build artifacts
- Planned: SLSA (Supply-chain Levels for Software Artifacts) compliance
- Planned: In-toto attestation format support
Build Provenance
Current Capabilities:
GitLab pipelines provide provenance information:
# Capture build metadata build: stage: build script: - | cat > provenance.json <<EOF { "builder": { "id": "$CI_RUNNER_ID", "version": "$CI_RUNNER_VERSION" }, "buildType": "gitlab-pipeline", "invocation": { "configSource": { "uri": "$CI_PROJECT_URL", "digest": { "sha256": "$CI_COMMIT_SHA" }, "entryPoint": ".gitlab-ci.yml" }, "parameters": { "branch": "$CI_COMMIT_BRANCH", "tag": "$CI_COMMIT_TAG" } }, "metadata": { "buildStartedOn": "$CI_PIPELINE_CREATED_AT", "buildFinishedOn": "$(date -u +%Y-%m-%dT%H:%M:%SZ)", "completeness": { "parameters": true, "environment": false, "materials": true } }, "materials": [ { "uri": "git+$CI_REPOSITORY_URL", "digest": { "sha256": "$CI_COMMIT_SHA" } } ] } EOF - npm run build - sha256sum dist/* > checksums.txt artifacts: paths: - dist/ - provenance.json - checksums.txt
Artifact Signing
GPG Signing:
sign_artifacts: stage: sign script: # Import GPG key (from CI/CD variable) - echo "$GPG_PRIVATE_KEY" | gpg --import # Sign artifacts - gpg --armor --detach-sign dist/app.tar.gz # Generate checksums - sha256sum dist/app.tar.gz > dist/app.tar.gz.sha256 # Sign checksums - gpg --armor --detach-sign dist/app.tar.gz.sha256 artifacts: paths: - dist/app.tar.gz - dist/app.tar.gz.asc - dist/app.tar.gz.sha256 - dist/app.tar.gz.sha256.asc
Verification:
# Download public key curl https://example.com/public-key.asc | gpg --import # Verify signature gpg --verify app.tar.gz.asc app.tar.gz # Verify checksum sha256sum -c app.tar.gz.sha256
Container Image Signing
Cosign (Sigstore):
sign_container: stage: sign image: gcr.io/projectsigstore/cosign:latest script: # Sign container image - cosign sign --key $COSIGN_PRIVATE_KEY $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA # Generate attestation - cosign attest --key $COSIGN_PRIVATE_KEY \ --predicate provenance.json \ $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA only: - tags
Verification:
# Verify signature cosign verify --key cosign.pub $IMAGE # Verify attestation cosign verify-attestation --key cosign.pub $IMAGE
Supply Chain Attack Prevention
Threat Model
Common Attack Vectors:
-
Dependency Confusion
- Attacker publishes malicious package with same name
- Package manager downloads attacker's package instead of internal one
-
Typosquatting
- Malicious package with similar name to popular package
- Developers accidentally install wrong package
-
Compromised Package
- Legitimate package account compromised
- Malicious code injected into trusted package
-
Malicious Maintainer
- Package maintainer adds malicious code
- Backdoor distributed to all users
-
Build System Compromise
- Attacker compromises CI/CD system
- Injects malicious code during build
Mitigation Strategies
1. Dependency Pinning:
// package-lock.json (npm) { "dependencies": { "lodash": { "version": "0.4.9", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" } } }
2. Subresource Integrity:
# Verify package integrity install_dependencies: stage: build script: # npm automatically verifies integrity from package-lock.json - npm ci # pip with hash checking - pip install --require-hashes -r requirements.txt
3. Private Package Registry:
# .npmrc @mycompany:registry=https://npm.example.com/ //npm.example.com/:_authToken=${NPM_TOKEN} registry=https://registry.npmjs.org/
4. Allowlist/Blocklist:
# Security policy dependency_policy: allowed_registries: - npm: https://registry.npmjs.org/ - pypi: https://pypi.org/ blocked_packages: - name: "malicious-package" reason: "Known malware" - name: "compromised-lib" reason: "Compromised maintainer account"
5. Automated Scanning:
include: - template: Security/Dependency-Scanning.gitlab-ci.yml - template: Security/Container-Scanning.gitlab-ci.yml # Scan on every commit dependency_scanning: stage: test # Block merge if critical vulnerabilities scan_result_policy: - name: "Block Supply Chain Attacks" rules: - type: scan_finding scanners: ["dependency_scanning", "container_scanning"] severity_levels: ["critical", "high"] vulnerabilities_allowed: 0 actions: - type: require_approval approvers: ["@security-team"]
6. Regular Audits:
# Scheduled security audit security_audit: stage: audit script: # npm audit - npm audit --production - npm audit --audit-level=high # Python safety check - pip install safety - safety check --json # Ruby bundler audit - bundle audit check --update # Report findings - ./generate-audit-report.sh artifacts: reports: junit: audit-report.xml only: - schedules
Best Practices
SBOM Management
- Generate SBOMs Automatically - Enable Dependency and Container Scanning
- Version Control SBOMs - Store SBOMs with releases
- Regular Updates - Regenerate SBOMs with each build
- Include in Releases - Publish SBOMs alongside artifacts
- Audit SBOMs - Review SBOMs for unexpected dependencies
Dependency Management
- Pin Dependencies - Use lock files (package-lock.json, Gemfile.lock, etc.)
- Regular Updates - Update dependencies weekly or monthly
- Security Patches - Apply security updates immediately
- Minimize Dependencies - Remove unused dependencies
- Vet New Dependencies - Review before adding to project
License Compliance
- Define Policy Early - Establish license policy before development
- Automated Enforcement - Use license approval policies
- Regular Reviews - Review licenses quarterly
- Legal Consultation - Involve legal team in policy decisions
- Documentation - Maintain SBOM for compliance evidence
Supply Chain Security
- Defense in Depth - Multiple layers of security
- Continuous Monitoring - Automated scanning on every commit
- Rapid Response - Process for emergency updates
- Incident Response Plan - Documented procedure for supply chain incidents
- Team Training - Educate developers on supply chain risks
Troubleshooting
Common Issues
SBOM not generated:
Checklist:
Dependency Scanning job ran successfully
Lock file present and committed
Supported package manager
Artifacts configured correctly
Check job logs for errors
Missing dependencies in SBOM:
Cause: Lock file not up-to-date
Resolution:
npm install # Regenerate package-lock.json
pip freeze # Update requirements.txt
bundle install # Update Gemfile.lock
License not detected:
Cause: Package missing license metadata
Resolution:
1. Check package repository for license
2. Contact package maintainer
3. Consider alternative package
4. Document in custom license database
False positive vulnerabilities:
Cause: Scanner detecting vulnerability that doesn't apply
Resolution:
1. Verify vulnerability context
2. Check if vulnerable code path is used
3. Dismiss as false positive in Vulnerability Report
4. Add explanation for audit trail
Regulatory Compliance
SBOM Requirements
Executive Order 14028 (USA):
- Software sold to US government must include SBOM
- SBOM must be in standard format (SPDX, CycloneDX)
- Must include all components and dependencies
EU Cyber Resilience Act:
- Manufacturers must provide SBOM for software products
- SBOM must be machine-readable
- Must include vulnerability information
GitLab Compliance:
- Automatically generates CycloneDX SBOMs
- Includes all dependencies and transitive dependencies
- Machine-readable JSON format
- Vulnerability information integrated
References
- Dependency Scanning Documentation
- Container Scanning Documentation
- License Compliance Documentation
- SBOM Documentation
- CycloneDX Specification
- SLSA Framework
Next Steps
- Security Scanning - Configure dependency and container scanning
- Vulnerability Management - Track and remediate vulnerabilities
- Compliance - Meet regulatory requirements