KyoMel / Yogyakarta, Indonesia

Term 271271 / 344

Codecov Attack

Month
July 2026
Day
6
Source
2026/july-term.md

Definition:

The Codecov Attack was a supply chain breach discovered in April 2021 where an attacker compromised Codecov’s Bash Uploader script — a tool used by over 29,000 organizations to upload code coverage reports to Codecov’s platform. By injecting malicious code into this single shell script, the attacker silently harvested environment variables, API keys, cloud credentials, and secrets from every CI/CD pipeline that ran the modified script over a period of two months (January 31, 2021 – April 1, 2021).

The attack is significant because:

  1. It was not a breach of Codecov’s main application — The attacker didn’t break into Codecov’s database or infrastructure directly. Instead, they gained access to Codecov’s Docker image build process and modified the Bash Uploader before it was distributed to users.

  2. It targeted the supply chain, not the product — The attacker didn’t steal Codecov’s data. They used Codecov’s trusted distribution channel to inject themselves into their customers’ CI/CD pipelines. Customers pulled what they thought was a legitimate update, but it contained a hidden data exfiltration mechanism.

  3. The blast radius was enormous — Codecov’s Bash Uploader runs at the very beginning of a CI/CD pipeline. At that point, the CI environment contains all the secrets needed for the entire build: cloud provider keys, registry credentials, API tokens, database passwords. By compromising this one script, the attacker gained access to potentially thousands of organizations’ most sensitive credentials.

  4. It was discovered accidentally — A customer noticed their CI logs showed an unexpected connection to an unknown IP address. That single anomaly triggered the investigation that uncovered the entire attack.

Example:

A step-by-step visual flow of how the Codecov supply chain attack unfolded — from initial compromise to mass data exfiltration.

═══════════════════════════════════════════════════════════════
  Phases of the Codecov Attack
═══════════════════════════════════════════════════════════════

PHASE 1: INITIAL COMPROMISE (January 2021)
══════════════════════════════════════════════

  Attacker
     │
     │ 1. Exploits a vulnerability in Codecov's
     │    Docker image creation process
     ▼
  Codecov's Docker Build Server
     │
     │ 2. Gains persistent access to the server
     │    that builds and distributes the
     │    "Bash Uploader" script (bash-uploader.sh)
     ▼
  Bash Uploader Script
  (source code, before modification)
     │
     │ 3. Attacker modifies the script — injects
     │    ~100 lines of malicious code
     ▼
  Modified Bash Uploader Script
  (looks identical, functions the same —
   but now has a hidden payload)

PHASE 2: POISONED DISTRIBUTION (Feb - Mar 2021)
══════════════════════════════════════════════════

  Modified Bash Uploader Script
     │
     │ 4. Codecov publishes the modified script
     │    as a routine update
     │    (no security review — it's "just" the
     │     uploader script, not the main app)
     ▼
  Codecov's CDN / GitHub
     │
     │ 5. Customers' CI systems (GitHub Actions,
     │    CircleCI, Jenkins, TravisCI) pull the
     │    "latest" bash-uploader.sh —
     │    it passes checksum verification because
     │    Codecov's own checksum is also updated
     ▼
  Customer's CI/CD Pipeline
  (e.g., GitHub Actions runner)

PHASE 3: THE PAYLOAD FIRES
═══════════════════════════

  CI Pipeline Starts
     │
     │ 6. The modified bash-uploader.sh runs as
     │    the first step in the pipeline
     ▼
  ┌─────────────────────────────────────────────┐
  │  What the modified script does:             │
  │                                             │
  │  a) Runs normally ✓                         │
  │     Uploads coverage data to Codecov        │
  │     (Everything looks normal to the CI log) │
  │                                             │
    │  b) But ALSO secretly:                      │
    │     ┌─────────────────────────────────┐     │
    │     │ Scans ALL environment variables │     │
    │     │ Collects:                       │     │
    │     │ • AWS_ACCESS_KEY_ID             │     │
    │     │ • AWS_SECRET_ACCESS_KEY         │     │
    │     │ • GITHUB_TOKEN                  │     │
    │     │ • DOCKER_PASSWORD               │     │
    │     │ • SLACK_TOKEN                   │     │
    │     │ • Any env var containing        │     │
    │     │   "key", "secret", "token",     │     │
    │     │   "password", "pass"            │     │
    │     │ • npm/Gem/PyPI credentials      │     │
    │     └─────────────────────────────────┘     │
    │                                             │
    │  c) Exfiltrates:                             │
    │     ┌─────────────────────────────────┐     │
    │     │ Sends stolen env vars to an     │     │
    │     │ attacker-controlled server at   │     │
    │     │ a hardened Codecov subdomain:   │     │
    │     │ https://<attacker>.codecov.io   │     │
    │     │                                 │     │
    │     │ The request looks legitimate —  │     │
    │     │ it's going to *.codecov.io,     │     │
    │     │ so security tools don't flag it │     │
    │     └─────────────────────────────────┘     │
    └─────────────────────────────────────────────┘
  
  
  PHASE 4: CASCADING COMPROMISE
  ══════════════════════════════
  
    Attacker's Server
       │
       │ 7. Receives thousands of stolen
       │    credential sets from every
       │    customer CI pipeline that ran
       │    the poisoned script
       ▼
    Stolen Credentials Database
       │
       │ 8. Attacker uses harvested credentials
       │    to breach downstream systems:
       ▼
    ┌─────────────────────────────────────────────┐
    │                                             │
    │  a) AWS accounts → S3 data, EC2 instances   │
    │  b) GitHub repos → private source code,     │
    │     modify code, inject further backdoors   │
      │  c) Docker registries → pull private images │
      │  d) Slack → read internal communications    │
      │  e) npm/PyPI → publish malicious packages   │
      │  f) Cloudflare → modify DNS, CDN config     │
      │                                             │
      └─────────────────────────────────────────────┘
         │
         │  Attackers can now move laterally into
         │  ANY system the stolen credentials
         │  have access to — a compounding
         │  supply chain disaster.
         ▼
      Widespread Compromise
      (Multiplied across 29,000+ organizations)
    
    
    PHASE 5: DETECTION & RESPONSE (April 1, 2021)
    ════════════════════════════════════════════════
    
      A Customer's CI Log
         │
         │ ⚠️ "Why is the bash-uploader.sh connecting
         │    to an IP address I don't recognize?"
         │
         ▼
      Customer contacts Codecov support
         │
         │ Codecov investigates → discovers the
         │ unauthorized modification
         ▼
      Codecov Publishes Security Advisory
      (April 15, 2021)
         │
         │ ● Bash Uploader was compromised
         │ ● Date range: Jan 31 - Apr 1, 2021
         │ ● Any org that ran the uploader in
         │   this window must rotate ALL secrets
         │   stored in CI environment variables
         │ ● ~29,000 customers affected
         ▼
      Industry-wide Emergency Response
         │
         │ ● Thousands of orgs rotate ALL CI secrets
         │ ● GitHub, AWS, Docker, and others
         │   issue security advisories
         │ ● Breach response teams work for weeks
         │ ● Full blast radius never fully determined
         ▼
      Regulatory & Legal Fallout
         │
         │ ● SEC filings from affected public companies
         │ ● GDPR breach notifications across Europe
         │ ● Multiple class-action lawsuits
         │ ● Codecov's CISO steps down
         │ ● Industry-wide re-evaluation of
         │   CI/CD pipeline security
    
    
    ═══════════════════════════════════════════════════════════════
      ATTACK STATISTICS
    ═══════════════════════════════════════════════════════════════
    Duration of compromise:  61 days (Jan 31 → Apr 1)
      Affected organizations:  29,000+ (including 500+ Fortune 500)
      Stolen data types:       CI env vars, API keys, cloud creds,
                               private repo tokens, registry passwords
      Detection method:        Customer noticed anomalous outbound
                               connection in CI logs (pure luck)
      Root cause:             Flaw in Docker image creation process
                               → attacker gained write access to
                               Bash Uploader distribution
      Total estimated impact:  Not fully quantified — but affected
                               companies include major tech firms,
                               banks, healthcare orgs, and government
                               agencies
    
    
    ═══════════════════════════════════════════════════════════════
      KEY LESSONS
    ═══════════════════════════════════════════════════════════════
    
      Lesson 1: Supply chain > Direct breach
      ──────────────────────────────────────
      The attacker didn't need to breach 29,000 organizations
      individually. They poisoned one tool that 29,000 orgs
      trusted and invited inside. One supply chain compromise
      = thousands of downstream breaches.
    
      Lesson 2: CI/CD secrets are the crown jewels
      ────────────────────────────────────────────
      A CI/CD pipeline contains ALL the credentials an
      organization uses to deploy code, access cloud
      infrastructure, publish packages, and communicate
      internally. A single CI env var dump gives an attacker
      the keys to everything.
    
      Lesson 3: Code signing ≠ security
      ─────────────────────────────────
      The modified script had valid checksums because the
      attacker controlled the distribution pipeline that
      generated the checksums. Trusting a download based on
      "the checksum matches" means nothing if the checksum
      itself can also be modified.
    
      Lesson 4: Outbound traffic to expected domains
           can still be malicious
           ──────────────────────────────────────────────
             The exfiltration went to a *.codecov.io subdomain —
             the same domain legitimate traffic uses. Network
             security tools that only check "is this a known domain?"
             would miss this entirely.
           
             Lesson 5: Rotation is the only remedy
             ─────────────────────────────────────
             Once credentials have been exposed, there is no way
             to "un-expose" them. The only response is to treat
             EVERY secret that was present in the CI environment
             during the compromise window as compromised — and
             rotate them all.

Keep reading