Supply Chain Attacks Are Real and Your Pipeline Is a Target

by Arif Ikhsanudin, Backend Developer

What Happened to Codecov and Why Your Pipeline Is Similar

In April 2021, attackers compromised Codecov's bash uploader script — a tool used by thousands of teams in their CI pipelines to upload coverage reports. The malicious version of the script exfiltrated CI environment variables (which contain credentials, tokens, and secrets) to an attacker-controlled server. Teams that used the script in their pipelines had their credentials harvested silently. Among the affected: Twilio, HashiCorp, Rapid7, and hundreds of other organizations.

The attack worked because the pipeline was trusted to execute code from third parties without scrutiny. The Codecov script ran with access to the same environment variables as every other pipeline step — including production credentials, cloud provider tokens, and private repository access tokens.

Your pipeline almost certainly does the same thing. Every GitHub Action you reference, every Docker base image you pull, every Maven dependency your build downloads is third-party code executing in your pipeline environment. The trust you're extending is often implicit and unexamined.

The Attack Surfaces

GitHub Actions (and equivalent plugins) are the most direct attack surface. When you reference uses: some-org/some-action@v2, you're executing code from that repository. If the action's repository is compromised, or if the tag v2 is moved to a different (malicious) commit, your pipeline runs the attacker's code.

# Dangerous: tags can be moved to different commits
- uses: actions/checkout@v4

# Safer: pinned to a specific commit SHA
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683  # v4.2.2

Commit SHAs are immutable. A tag can be moved; a SHA cannot. Pinning to a SHA means that even if the action's repository is compromised and tags are moved, your pipeline continues using the audited version.

Docker base images carry the same risk. An attacker who gains write access to a Docker Hub account can push a malicious image to a popular tag — node:20-alpine or eclipse-temurin:21-jre. Your pipeline pulls the image by tag, not by digest, and executes the malicious version.

# Vulnerable to tag mutation:
FROM eclipse-temurin:21-jre

# Pinned to a specific image digest:
FROM eclipse-temurin:21-jre@sha256:a1b2c3d4e5f6...  # Cannot be mutated

Dependencies from public registries are the broadest attack surface and the hardest to defend. Typosquatting attacks (a package named com.myorg.utlils instead of com.myorg.utils) have been used in real attacks against Maven, npm, and PyPI ecosystems. Compromised legitimate packages (the event-stream npm incident, the ua-parser-js compromise) execute malicious code when installed.

Mitigations That Are Practical at Team Scale

Pin your actions to commit SHAs. This is the most impactful change for GitHub Actions users. Tools like pin-github-action or Dependabot's action update management can automate keeping pinned SHAs current:

# .github/dependabot.yml
updates:
  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "weekly"
    # Dependabot will open PRs to update pinned SHA references

Use a private artifact repository. Nexus, Artifactory, or AWS CodeArtifact act as a proxy between your build and the public registry. Dependencies are pulled through the proxy, which can be configured to block unknown packages, enforce allowlists, and scan incoming artifacts before caching them. This doesn't prevent compromise of allowed packages, but it prevents typosquatting and makes dependency changes visible.

Run SBOM (Software Bill of Materials) generation and scanning. Syft generates an SBOM from your container image or dependency tree; Grype scans it for known vulnerabilities:

- name: Generate SBOM
  uses: anchore/sbom-action@v0
  with:
    image: myapp:${{ github.sha }}

- name: Scan for vulnerabilities
  uses: anchore/scan-action@v3
  with:
    image: myapp:${{ github.sha }}
    fail-build: true
    severity-cutoff: high

Running SBOM generation on every build gives you a point-in-time inventory of what's in your images. Running it against a fixed baseline lets you detect unexpected additions.

Minimize pipeline permissions. Supply chain attacks succeed because the compromised code runs with broad permissions. If your pipeline's OIDC role has permission only to push to ECR and update a single ECS service, even a fully compromised action can only do those two things. Defense in depth: reduce trust in third-party code and reduce what compromised code can do.

Review action source code before first use. For actions from outside the major vendors (GitHub, HashiCorp, AWS, Docker), read the code before adding it. Most malicious actions are not subtle — they exfiltrate environment variables or call out to external URLs. A 15-minute code review before adding a new action is proportionate to the risk.

The supply chain is a real attack surface used in real attacks against real organizations. Treating it as such is not paranoia — it's appropriate threat modeling for a system that executes third-party code with production credentials on every commit.

Scale Your Backend - Need an Experienced Backend Developer?

We provide backend engineers who join your team as contractors to help build, improve, and scale your backend systems.

We focus on clean backend design, clear documentation, and systems that remain reliable as products grow. Our goal is to strengthen your team and deliver backend systems that are easy to operate and maintain.

We work from our own development environments and support teams across US, EU, and APAC timezones. Our workflow emphasizes documentation and asynchronous collaboration to keep development efficient and focused.

  • Production Backend Experience. Experience building and maintaining backend systems, APIs, and databases used in production.
  • Scalable Architecture. Design backend systems that stay reliable as your product and traffic grow.
  • Contractor Friendly. Flexible engagement for short projects, long-term support, or extra help during releases.
  • Focus on Backend Reliability. Improve API performance, database stability, and overall backend reliability.
  • Documentation-Driven Development. Development guided by clear documentation so teams stay aligned and work efficiently.
  • Domain-Driven Design. Design backend systems around real business processes and product needs.

Tell us about your project

Our offices

  • Copenhagen
    1 Carlsberg Gate
    1260, København, Denmark
  • Magelang
    12 Jalan Bligo
    56485, Magelang, Indonesia

More articles

Specifications Too Low for Developers: The Typewriter Mentality

“Why does a developer need a $5000 laptop?” Because writing code isn’t typing—it’s running a small universe on your machine.

Read more

Why Dubai Startups Lose Backend Engineers to Better Offers Every 18 Months

You relocated him from Lahore, sponsored his visa, found him an apartment in JLT. Eighteen months later he's joining a fintech in DIFC for 30% more.

Read more

How to End a Contract Professionally So They Come Back Next Time

The ending of a contract is as important as the beginning. How you close an engagement determines whether you are remembered as someone worth working with again.

Read more

Reviewing Code You Don't Fully Understand Is More Common Than You Think

Most developers have approved a PR they didn't fully understand and said nothing. This is a competence problem less often than it's a process problem — and it's fixable without anyone having to admit ignorance.

Read more