Continuous Integration / Continuous Deception: Trying my luck as a malicious maintainer

Benedikt Haußner (Red Teamer)

fwd:cloudsec Europe 2025 · Day 1 · Main Room

Overview

Benedikt Haußner, an internal red teamer based in Germany specializing in cloud and CI/CD security, presented a year's worth of research into how a malicious open-source maintainer can poison software releases through GitHub pipeline manipulation — without modifying application source code. Through three progressively sophisticated attacks — mutable release tampering, typosquatting third-party actions, and hidden self-hosted runners using homoglyph characters — Haußner demonstrated that the software supply chain's trust assumptions around GitHub releases are fundamentally brittle. All attacks abuse existing features rather than exploiting vulnerabilities (no CVEs involved), and all leave detectable traces — but only if defenders know where to look.

Watch on YouTube

Visual summary for Continuous Integration / Continuous Deception: Trying my luck as a malicious maintainer by Benedikt Haußner
Visual summary for Continuous Integration / Continuous Deception: Trying my luck as a malicious maintainer by Benedikt Haußner

Key moments

  1. 2:00 Setting the rules — poisoning releases without changing application source code, no CVEs involved
  2. 6:00 Attack 1: Mutable release tampering — automated workflow replaces assets with 1-second timestamp gap
  3. 8:00 Events API vs Releases API divergence — the only reliable detection for mutable release tampering
  4. 10:00 Attack 2: Typosquatting 'eklons/checkout' — malicious code injected at line 1895 of a cloned action
  5. 12:00 Orphaned commit trick — malicious commit reachable via actions/checkout fork network after repo deletion
  6. 14:00 Attack 3: Homoglyph N-dash replaces hyphen in ubuntu-latest, routing to attacker's self-hosted runner
  7. 16:00 Key detection: runnergroupid of zero means GitHub-hosted — any other value indicates self-hosted
  8. 18:00 Defensive recommendations — immutability features, Harden Runner, and incident response preparation

Continuous Integration / Continuous Deception: Trying my luck as a malicious maintainer

Speakers: Benedikt Haußner, Red Teamer

Conference: fwd:cloudsec Europe 2025

YouTube: https://www.youtube.com/watch?v=ehmAy320R4A

Overview

Benedikt Haußner, an internal red teamer based in Germany specializing in cloud and CI/CD security, presented a year's worth of research into how a malicious open-source maintainer can poison software releases through GitHub pipeline manipulation — without modifying application source code. Through three progressively sophisticated attacks — mutable release tampering, typosquatting third-party actions, and hidden self-hosted runners using homoglyph characters — Haußner demonstrated that the software supply chain's trust assumptions around GitHub releases are fundamentally brittle. All attacks abuse existing features rather than exploiting vulnerabilities (no CVEs involved), and all leave detectable traces — but only if defenders know where to look.

Background

▶ Watch: Setting the rules — poisoning releases without changing application source co... (2:00)

Software supply chain attacks are accelerating. In the weeks and months preceding this talk, the security community saw the chalk and debug npm package breach, the NX npm incident, and the infamous tj-actions/changed-files GitHub Actions compromise. These incidents demonstrate that the build and distribution stages of the software supply chain are active targets, yet most organizations focus their security assessment on application source code through SAST tooling, leaving pipelines essentially unmonitored.

Haußner's research premise: assume you are already a malicious maintainer (phished, disgruntled, or otherwise compromised). Your goal is to poison a release without changing the application source code — because source code changes are visible in open-source repositories and may be caught by SAST tools. Instead, target the pipeline definitions, third-party actions, and build infrastructure that consumers rarely inspect.

Key Findings

▶ Watch: Events API vs Releases API divergence — the only reliable detection for mutab... (8:00)

GitHub releases are mutable by default. Release assets can be manually replaced through the GitHub GUI after initial publication. The only metadata indicators are the updated_at timestamp (which differs from published_at) and the uploader field showing the maintainer's username instead of the GitHub Actions bot. These indicators are subtle and easily overlooked.

Automated mutable release tampering is nearly invisible. By pushing a secondary workflow on a separate branch that monitors for new releases and automatically replaces assets, a malicious maintainer can reduce the timestamp gap between published_at and updated_at to 1 second or less. The uploader remains the GitHub Actions bot, making the tampering forensically indistinguishable from a legitimate release in most monitoring scenarios.

The Events API and Releases API diverge after tampering. The GitHub Events API publishes file hashes on first publish and does not update on subsequent modifications. The Releases API always returns the latest state. Comparing digests between these two APIs can detect tampering — but the Events API has latency of 30 seconds to 6 hours and may not exist for all repositories.

Typosquatting GitHub Actions is trivially easy. Haußner registered the username "eklons" and created a checkout action that mirrors actions/checkout with two malicious lines injected at line 1895-1896 of the source code. The workflow reference eklons/checkout@v5 is visually similar to actions/checkout@v5 and functionally identical — except for the injected payload. After use, the attacker deletes their repository and re-forks the legitimate action, making forensic analysis find only clean code.

Orphaned commits persist across fork networks. A particularly dangerous variant: a malicious commit made in a fork of actions/checkout can be referenced by commit hash from the original actions/checkout repository — even after the fork is deleted. The commit exists in the fork network graph and is reachable via github.com/actions/checkout/<commit-hash>. GitHub displays a warning ("this commit does not belong to any branch") but this is easily dismissed, and the condition cannot be detected via the GitHub API.

Homoglyph characters enable hidden self-hosted runner injection. By replacing the hyphen in ubuntu-latest with an N-dash (visually identical, different byte code), a malicious maintainer can direct a workflow to run on a self-hosted runner tagged with ubuntu–latest (N-dash) instead of GitHub-hosted ubuntu-latest (hyphen). On a self-hosted runner, the attacker has root access and can modify any release artifact. GitHub correctly routes to the self-hosted runner because the label is technically different.

Runner group ID zero indicates GitHub-hosted runners. The one reliable detection mechanism for the self-hosted runner attack: if the runner_group_id in the workflow run metadata is 0, the runner was GitHub-hosted. Any non-zero value indicates a self-hosted runner. All other runner metadata (name, labels, etc.) can be spoofed using homoglyph techniques.

Technical Deep Dive

▶ Watch: Orphaned commit trick — malicious commit reachable via actions/checkout fork ... (12:00)

Attack 1: Mutable Release Tampering

The benchmark release workflow is straightforward: on tag push, checkout the code, create a release using gh release create with the tagged file. The attacker creates a separate branch with a monitoring workflow that watches for release events and immediately replaces the release asset using gh release delete-asset and gh release upload. The timing is tight enough that published_at and updated_at show at most a 1-second gap, and the uploader remains github-actions[bot].

Protection: Enable release immutability (currently in GitHub public beta), which prevents post-publication asset modification.

Attack 2: Typosquatting Third-Party Actions

The attacker clones the source of actions/checkout (specifically three vital files), creates a repository under a visually similar username (e.g., eklons/checkout), injects malicious code deep in the codebase (lines 1895-1896), and tags it as v5. The victim's workflow references eklons/checkout@v5 instead of actions/checkout@v5. After execution, the attacker deletes the repository and re-forks the clean version — forensic investigation of the username's repository shows only legitimate code.

The orphaned commit variant is more dangerous: the attacker forks actions/checkout, makes a malicious commit, then references it by commit hash. After deleting the fork, the commit remains reachable through the original repository's fork network. A workflow pinned to this commit hash appears to reference actions/checkout directly, and the only indicator is a GitHub GUI warning about the commit not belonging to any branch — which is not available via API.

Protection: Use immutable actions publishing (coming in GitHub's next quarter), which prevents post-publication modification of action code.

Attack 3: Hidden Self-Hosted Runner via Homoglyph

The runs-on field in the workflow YAML specifies ubuntu–latest with an N-dash instead of a hyphen. The attacker registers a self-hosted runner tagged with this N-dash label. GitHub routes the job to the self-hosted runner where the attacker has root access, enabling arbitrary modification of release artifacts. Run logs reveal the self-hosted runner, but logs can be deleted (returning 404 via API). The runner_group_id field is the only reliable indicator — 0 means GitHub-hosted, anything else means self-hosted.

Protection: Verify that maintainers use GitHub-hosted runners for open-source projects (free for public repositories). Question any use of self-hosted runners.

Demo / Proof of Concept

▶ Watch: Attack 3: Homoglyph N-dash replaces hyphen in ubuntu-latest, routing to attac... (14:00)

All attacks were demonstrated through the published results, with release artifacts available for diffing in Haußner's GitHub repository. The repository contains approximately 80 pages of documentation covering all attack variants, detailed indicators of compromise, hunting leads, and prior research references. No live exploitation was performed on stage due to internet connectivity limitations.

Defensive Implications

▶ Watch: Defensive recommendations — immutability features, Harden Runner, and inciden... (18:00)

For consumers of open-source software:

  • Enable or request release immutability on repositories you depend on. This is the single most impactful mitigation.
  • Compare file hashes between the GitHub Events API and Releases API to detect post-publication tampering.
  • Inspect runner_group_id in workflow run metadata — non-zero values indicate self-hosted runners.
  • Audit third-party GitHub Actions for typosquatting, particularly custom forks of popular actions like actions/checkout.
  • Be skeptical of commit-hash-pinned action references that display "this commit does not belong to any branch" warnings.
  • Automate supply chain monitoring — manual inspection does not scale across hundreds of dependencies.

For maintainers:

  • Enable release immutability and immutable tags.
  • Use GitHub-hosted runners for open-source projects (free for public repositories).
  • Adopt immutable actions publishing when available.
  • Use tools like Step Security's Harden Runner to monitor in-pipeline activity.

For organizations:

  • Prioritize auditing your most critical pipelines first, then work outward to first-party dependencies.
  • SAST on application source code alone is insufficient — pipeline definitions and third-party actions are the unmonitored attack surface.
  • Develop incident response playbooks for supply chain compromise, including secret rotation procedures and priority ordering.
  • Tools like Poutine (GitHub Actions pipeline auditing) can help identify risky pipeline configurations at scale.

Key Takeaways

  • GitHub releases are mutable by default — a malicious maintainer can replace release assets with near-zero forensic indicators using automated workflows.
  • Typosquatting GitHub Actions with visually similar usernames is trivially achievable, and orphaned commits in fork networks persist even after the malicious repository is deleted.
  • Homoglyph characters (N-dash vs. hyphen) can silently redirect workflows to attacker-controlled self-hosted runners where root access enables arbitrary release modification.
  • The runner_group_id field (zero = GitHub-hosted) is the only reliable indicator for detecting self-hosted runner substitution.
  • Release immutability, immutable tags, and immutable actions publishing (upcoming) are the primary mitigations — help maintainers adopt them.
  • All attacks leave detectable traces, but detection requires automation — manual inspection does not scale.

About the Speaker(s)

Benedikt Haußner is an internal red teamer based in Germany, specializing in cloud and CI/CD security. His research over the past year focused on supply chain attack techniques from the malicious maintainer perspective, documented in an extensive public repository covering attack variants, indicators of compromise, and hunting leads. He previously worked as a penetration tester.

Reviews

Dr. Zero (Offensive Security Researcher) — STRONG ACCEPT

A well-structured, practical demonstration of supply chain attack techniques that most organizations are not monitoring for. The three attack variants — mutable release tampering, action typosquatting with orphaned commits, and homoglyph-based runner substitution — are all achievable with existing GitHub features and leave only subtle traces. The orphaned commit persistence across fork networks is the standout finding.

Heather Calloway (CISO) — STRONG ACCEPT

A critically important talk for any organization consuming open-source software — which is every organization. Haußner demonstrates that release integrity assumptions in CI/CD pipelines are fundamentally broken, and the mitigations (release immutability, runner verification, action attestation) are either immature or not yet adopted. This research should drive immediate governance action around software supply chain verification.

→ Top-rated talks at fwd:cloudsec Europe 2025

All talks from fwd:cloudsec Europe 2025