Open Source Dependencies as Attack Vectors — Building Software Supply Chain Security with DevSecOps & SBOM
I still can't forget the night Log4Shell hit in December 2021. The entire team was scrambling through dependency trees shouting "Where do we have Log4j in our services?" — and that search alone took two full days. Later, when I properly dug into the concept of SBOM, I realized that if we'd had one in place, those two days could have been reduced to just a few minutes. It was a painful lesson in how that difference translates directly into real downtime and real business losses.
Some of you reading this might be thinking, "Isn't security the security team's job?" But in modern software development, that boundary has completely dissolved. The moment you run npm install, hundreds of open source libraries enter your system. If even one of them has a vulnerability, from an attacker's perspective, you've opened the door yourself.
In this article, we'll explore the core philosophy of DevSecOps, why SBOM is now the most important security tool available, and how to integrate it into a real CI/CD pipeline.
Core Concepts
DevSecOps: Bringing Security into the Development Flow
DevSecOps is, as the name suggests, a portmanteau of Development + Security + Operations. Its core philosophy is "Shift Left Security" — pulling security validation as far forward in the development cycle as possible.
The old approach looked like this: developers finish writing code → QA team runs tests → security team reviews before release. The problem is that by the time a security issue is found in this model, an enormous amount of effort has already been invested. Code may need to be rewritten, and release schedules slip. So the compromises creep in: "This is probably good enough."
DevSecOps changes that flow.
[Code Commit] → Secret Detection (Gitleaks) → SAST (Semgrep) → SCA (Trivy)
→ [Build] → SBOM Generation (Syft/CycloneDX) → SLSA Provenance Generation¹ → Container Signing (Cosign)
→ [Deploy] → SLSA Provenance Verification¹ → DAST → Runtime Monitoring¹ SLSA (Supply-chain Levels for Software Artifacts): A level-based framework for ensuring build integrity. It generates provenance (a proof of origin) at the build stage and verifies it at deployment. We'll cover this in detail in the next post.
From the moment a commit is pushed, security layers activate automatically. From a developer's perspective, the experience becomes: you open a PR and immediately get feedback like "This library has a CVE." Problems get caught at the point when they're cheapest to fix.
For security to be woven throughout the pipeline this way, you need a foundational tool. That foundation is SBOM.
Supply Chain Security: The Problem is What Isn't Your Code
Software Supply Chain refers to everything that goes into your software: source code, open source dependencies, build systems, artifacts, and the entire deployment pipeline. Attackers target the weakest link in that chain.
The SolarWinds incident in late 2020 burned the concept of supply chain security into the global consciousness. Attackers infiltrated SolarWinds' build pipeline and embedded the SUNBURST backdoor into a legitimate software update. More than 18,000 customers installed the "official update" and were unknowingly compromised. It was a stark reminder that the build pipeline itself can be an attack target.
Log4Shell was a different form of the same threat. It was an RCE (Remote Code Execution) vulnerability in Apache Log4j 2, a Java logging library that had spread to hundreds of millions of systems worldwide. Many teams didn't even know their services were using Log4j — and the reason was precisely that they had no SBOM.
The first tool for addressing these supply chain threats is SBOM.
SBOM: The Ingredient List for Software
SBOM (Software Bill of Materials) is an inventory of every component that makes up your software. It's exactly like the ingredient label on the back of a food package — it specifies "which libraries are in this software, at which versions, under which licenses" in a machine-readable format.
There are three major SBOM standard formats. Honestly, I found it confusing at first to know which one to pick, but in practice, you run two tools and go with whichever produces better results.
| Standard | Lead Organization | Characteristics |
|---|---|---|
| SPDX | Linux Foundation | ISO/IEC 5962 international standard, general-purpose |
| CycloneDX | OWASP Foundation | Optimized for security analysis, officially adopted by GitLab |
| SWID | NIST | Enterprise software asset management |
If you're starting fresh, pick either CycloneDX or SPDX. If you're using GitLab, CycloneDX integrates naturally; if you're in the GitHub Actions ecosystem, SPDX is more convenient.
Regulatory Mandates: Why You Need to Prepare Now
Regulation has started moving in earnest. In the US, Executive Order 14028 (2021) mandated that software sold to the federal government must include an SBOM. In the EU, the Cyber Resilience Act (CRA), which entered into force in December 2024, will be fully applicable by end of 2026. For any manufacturer selling digital products, providing an SBOM, handling vulnerabilities, and adhering to security-by-design principles will be a legal obligation.
The numbers are telling too. In 2026, the DevSecOps market is valued at $8.6–$10.9 billion, and the SBOM management market is growing at a compound annual rate of 22.1%. This is no longer a "big enterprise" story — it's becoming our team's story.
Practical Application
Note: If containers or CI/CD are still unfamiliar to you (e.g., if you work in frontend or data engineering), it's perfectly fine to start with just Example 1 and Example 4. Examples 2 and 3 are more directly relevant in environments that build container images.
Example 1: Auto-Generating SBOMs in GitHub Actions
The fastest way to get started is to attach anchore/sbom-action to GitHub Actions. It automatically generates an SBOM and saves it as an artifact on every PR.
Prerequisites: All you need is a repository with GitHub Actions enabled. No additional installation required.
# .github/workflows/sbom.yml
name: Generate SBOM
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
sbom:
runs-on: ubuntu-latest
permissions:
contents: read # read is sufficient if you're only uploading artifacts
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Generate SBOM (SPDX)
uses: anchore/sbom-action@v0
with:
format: spdx-json
output-file: sbom.spdx.json
- name: Generate SBOM (CycloneDX)
uses: anchore/sbom-action@v0
with:
format: cyclonedx-json
output-file: sbom.cyclonedx.json
- name: Upload SBOM artifact
uses: actions/upload-artifact@v4
with:
name: sbom-files
path: |
sbom.spdx.json
sbom.cyclonedx.jsonWith this in place, an SBOM file is generated and saved as an artifact on every build. When something like Log4Shell hits, you can determine whether your services are affected within minutes. That is the real difference between two days and a few minutes.
Example 2: Container Image Vulnerability Scanning with Trivy + SBOM Integration
Trivy is a tool for unified scanning of container images, filesystems, and Git repositories. It's a CNCF graduated project, and it was one of the first tools I introduced to my team.
Prerequisites: For local testing, install with brew install trivy (macOS) or the official install script. The CI/CD example assumes a container image has already been built.
# Scan container image for vulnerabilities
trivy image --severity HIGH,CRITICAL myapp:latest
# Generate SBOM (CycloneDX format)
trivy image --format cyclonedx --output sbom.json myapp:latest
# Match vulnerabilities against an existing SBOM file
trivy sbom sbom.jsonIntegrated into a CI/CD pipeline, it looks like this:
# GitHub Actions example
# In production, strongly recommended to pin to a SHA hash instead of @master
- name: Scan container image
uses: aquasecurity/trivy-action@master # replace with SHA hash
with:
image-ref: myapp:${{ github.sha }}
format: table
exit-code: 1 # fail the build if CRITICAL is found
severity: CRITICAL,HIGH
- name: Generate SBOM from image
run: |
trivy image \
--format cyclonedx \
--output sbom-${{ github.sha }}.json \
myapp:${{ github.sha }}The exit-code: 1 setting is important. It fails the build outright when a CRITICAL vulnerability is found, preventing that image from ever being deployed. Early on, there can be many false positives and the development team may push back — it's recommended to manage exceptions with a .trivyignore file and gradually raise the bar over time.
Example 3: Signing Container Images with Cosign
How do you guarantee that a built image hasn't been tampered with during the deployment process? Sigstore's Cosign is the answer. It supports keyless signing, so you can sign images without managing separate keys.
You might wonder how it's secure without a key. GitHub Actions' OIDC token acts as an ephemeral certificate, so you don't need to store a long-lived secret key anywhere. The token itself expires quickly, so even if it were stolen, it cannot be reused.
Prerequisites: Install Cosign with brew install cosign (macOS) or the official install guide, and you'll need to be logged into GHCR (GitHub Container Registry).
# Install Cosign
brew install cosign
# Keyless signing in GitHub Actions (OIDC-based)
cosign sign --yes ghcr.io/myorg/myapp:latest
# Verify signature (Cosign v2 syntax — specify exact identity)
cosign verify \
--certificate-identity "https://github.com/myorg/myapp/.github/workflows/release.yml@refs/heads/main" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
ghcr.io/myorg/myapp:latest
# Use regexp option to allow multiple branches/tags
cosign verify \
--certificate-identity-regexp "^https://github.com/myorg/myapp/" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
ghcr.io/myorg/myapp:latestGoogle applies Binary Authorization policies to GKE clusters so that unsigned containers simply cannot be deployed. If you operate a Kubernetes cluster, this is a direction worth considering.
Example 4: Hardening Third-Party GitHub Actions Security
In March 2025, malicious code was injected into the tj-actions/changed-files action. Thousands of repositories were affected, and sensitive secrets — cloud credentials, API tokens, and more that CI/CD pipelines were processing — were leaked through build logs. Many teams had referenced the action with uses: tj-actions/changed-files@v35, but the problem was that a tag can be changed to point to a different commit at any time.
# Dangerous — tags can be tampered with
- uses: actions/checkout@v4
# Safe — SHA hashes are immutable
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2Pinning to a SHA hash guarantees exactly which code that commit represents. It may seem tedious, but setting up Dependabot or Renovate will automatically open update PRs, significantly reducing the management burden.
Pros and Cons Analysis
Advantages
| Item | Details |
|---|---|
| Vulnerability visibility | Instantly identify which components have CVEs |
| Incident response speed | Pinpoint affected systems within minutes when events like Log4Shell occur |
| Regulatory compliance | Meet legal requirements such as EU CRA and US EO 14028 |
| Trust framework | Establish transparency between software suppliers and consumers |
| Automation foundation | Continuous security verification via CI/CD integration without human intervention |
Disadvantages and Caveats
| Item | Details | Mitigation |
|---|---|---|
| Integration complexity | Requires pipeline redesign, tool integration, and team training | Phased adoption, start with small projects |
| SBOM quality issues | Auto-generated SBOMs have accuracy limits, such as missing transitive dependencies | Use multiple tools in parallel, validate periodically |
| False positives | SAST/SCA tool false positives can slow development velocity | Manage with .trivyignore, gradually tighten thresholds |
| Operational overhead | Ongoing burden of generating, storing, and updating SBOMs | Automate artifact storage, set retention policies |
| Fragmented standards | Choosing between SPDX vs. CycloneDX and managing interoperability | Maintain consistency after choosing a tool, use conversion utilities |
SCA (Software Composition Analysis) is a technique for analyzing open source dependencies to detect known vulnerabilities (CVEs). It is distinct from SAST (Static Application Security Testing), which finds security flaws in code you've written yourself.
CVE (Common Vulnerabilities and Exposures) is a common identification system for publicly disclosed security vulnerabilities.
CVE-2021-44228is the official identifier for Log4Shell.
The Most Common Mistakes in Practice
-
Generating the SBOM once and never updating it. An SBOM is a living document. It only has meaning if it's regenerated every time dependencies change. If it's not automated in a CI/CD pipeline, it inevitably becomes a file nobody maintains.
-
Applying strict policies to all pipelines from the start. If you fail the build every time a HIGH vulnerability is found, deployments will grind to a halt early on and the whole team will be thrown into chaos. It's recommended to start by blocking only CRITICAL findings and gradually raise the bar from there.
-
Referencing third-party GitHub Actions only by tag. As mentioned, tags can be tampered with. Especially in workflows that handle private source code, it's best practice to always pin to a SHA hash.
Closing Thoughts
SBOM is not merely a security tool — it is a language for building trust between teams, between suppliers and users. And now is the time to learn that language.
You don't need to do everything at once. The three steps below are designed to progress in order — local exploration → CI/CD integration → pipeline security hardening — so you can build naturally, one step at a time.
-
You can experience SBOM generation locally. After running
brew install syft, executesyft packages .and you'll get a full list of your current project's dependencies. Seeing for the first time "so these are all the libraries in our service" can be quite a shock. -
You can add a Trivy scan to your CI/CD pipeline. If you're using GitHub Actions, adding
aquasecurity/trivy-actionto a workflow takes about 10 minutes. It's fine to start without anexit-code— just run it in report-only mode first. -
It's recommended to pin third-party GitHub Actions to SHA hashes. Open your current
.github/workflows/*.ymlfiles and replace tag references like@v3or@v4with SHA hashes. With Dependabot enabled, update PRs will be generated automatically.
Next post: A hands-on guide to incrementally achieving build integrity with SLSA framework levels 1 through 4
References
- CISA - Software Bill of Materials (SBOM)
- CISA - 2025 Minimum Elements for a Software Bill of Materials
- DevSecOps Trends 2026: AI, Supply Chain & Zero Trust - Practical DevSecOps
- The 2026 Guide to Software Supply Chain Security - Cloudsmith
- SBOMs in 2025: Trends & Predictions - Anchore
- Software Supply Chain Security: SBOM, SLSA, Sigstore (2025) - Elysiate
- The Ultimate Guide to SBOMs - GitLab
- What is an SBOM? - GitHub
- Lessons from Log4Shell: 4 key takeaways for DevSecOps teams - ReversingLabs
- SolarWinds Attack: Play by Play and Lessons Learned - Aqua Security
- SLSA Framework Guide - Practical DevSecOps
- Sigstore - OpenSSF
- Top 5 SBOM Tools 2025 - OX Security