mech.app
Dev Tools

Megalodon: Mass GitHub Repo Backdooring via CI Workflows

How 5,718 malicious commits exposed GitHub Actions permission boundaries, secret exfiltration paths, and the trust model that makes CI workflows a suppl...

Source: safedep.io
Megalodon: Mass GitHub Repo Backdooring via CI Workflows

On May 18, 2026, an automated campaign pushed 5,718 malicious commits to 5,561 GitHub repositories in six hours. The attacker used throwaway accounts with forged identities like build-bot, auto-ci, and pipeline-bot to modify .github/workflows/ files. The goal was not to inject code into application logic but to backdoor the CI infrastructure itself.

This is the Megalodon attack. It exposes how GitHub Actions workflows become a supply-chain vector when automation infrastructure gains write access to workflow files. The permission model, trigger types, and secret access rules create a trust boundary that breaks when an attacker controls the workflow definition.

The Attack Surface

GitHub Actions workflows are YAML files that define automation steps. They run on GitHub-hosted or self-hosted runners with access to:

  • Repository secrets (API keys, cloud credentials, deployment tokens)
  • The GITHUB_TOKEN with scoped permissions to the repository
  • Network egress to arbitrary endpoints
  • Arbitrary code execution in the runner environment

The attack surface is the workflow file itself. If an attacker can modify .github/workflows/*.yml, they control what runs in the CI environment.

What Megalodon Changed

The malicious commits injected steps into existing workflows or created new workflow files that:

  1. Exfiltrated repository secrets to attacker-controlled endpoints
  2. Injected backdoor dependencies into build artifacts
  3. Modified deployment scripts to push compromised containers or binaries
  4. Planted persistence by adding workflow triggers on future pull requests

The attacker targeted repositories with:

  • Public visibility (easier to fork and submit pull requests)
  • Existing CI workflows (less suspicious to add steps)
  • Active maintainers (higher chance of merge without scrutiny)

Permission Boundaries in GitHub Actions

GitHub Actions has three main permission boundaries that matter for this attack:

BoundaryScopeRisk
GITHUB_TOKENScoped to the repository, configurable per workflowCan push code, create releases, modify issues if permissions are broad
Secrets contextRepository secrets, environment secrets, organization secretsFull plaintext access if workflow runs with secrets context
Trigger typepull_request, pull_request_target, push, workflow_dispatchDetermines whether forks can access secrets

The pull_request_target Trap

The pull_request_target trigger is the most dangerous for this attack. It runs in the context of the base branch (not the fork) and has access to repository secrets. This is intended for workflows that need to comment on pull requests or deploy preview environments.

If a workflow uses pull_request_target and checks out the pull request code without validation, an attacker can inject malicious steps that run with secret access:

name: Preview Deploy
on:
  pull_request_target:
    types: [opened, synchronize]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          ref: ${{ github.event.pull_request.head.sha }}
      - name: Deploy preview
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        run: |
          # Attacker controls this script via the PR
          ./deploy-preview.sh

The pull_request trigger is safer. It runs in the fork’s context and does not have access to base repository secrets. But many repositories use pull_request_target for legitimate reasons (commenting, labeling, deploying previews), which creates the opening.

Detection Signals

When a workflow file is modified to exfiltrate secrets or inject malicious steps, several signals appear:

  • Diff anomalies: New curl or wget commands to unfamiliar domains, base64 encoding of secret values, or obfuscated shell commands
  • Trigger changes: Adding pull_request_target or workflow_dispatch to workflows that previously used pull_request
  • Secret access expansion: New secrets.* references in steps that did not previously access secrets
  • Network egress: Outbound connections to pastebin-like services, file-sharing sites, or attacker-controlled domains
  • Author identity: Commits from bot-like usernames with no prior contribution history

Megalodon used forged author identities to blend in. The commits appeared to come from build-bot@users.noreply.github.com, which looks like an automated service account. This bypasses human review if maintainers assume bots are trusted.

Workflow Modification as Supply-Chain Attack

The supply-chain risk is not just in dependencies. It is in the automation that builds, tests, and deploys those dependencies. If an attacker controls the workflow, they control:

  • What gets built (injecting malicious dependencies)
  • Where it gets deployed (pushing to attacker-controlled registries)
  • What secrets are used (exfiltrating credentials for later use)

This is harder to detect than a malicious package because workflow files are not scanned by traditional dependency tools. They are infrastructure-as-code, but they run with production credentials.

The Agent Problem

As coding agents (Copilot Workspace, Cursor, Aider) gain the ability to generate and modify CI configs, the attack surface grows. An agent that writes a workflow file may:

  • Add a pull_request_target trigger without understanding the security implications
  • Include a step that logs secrets for debugging
  • Pull in a third-party action from an untrusted source

The agent does not have malicious intent, but it creates the same backdoor. The trust model assumes humans review workflow changes, but agents generate code faster than humans can audit.

Sandboxing Agent-Generated Workflows

To reduce risk when agents write workflow files:

  1. Restrict trigger types: Block pull_request_target and workflow_dispatch in agent-generated workflows unless explicitly approved
  2. Audit secret access: Flag any new secrets.* references for manual review before merge
  3. Limit runner permissions: Use permissions: {} to deny all GITHUB_TOKEN scopes by default, then grant only what is needed
  4. Network egress control: Run workflows in environments with egress filtering to block unknown domains
  5. Workflow signing: Require GPG-signed commits for workflow file changes, with a separate approval process

Example of a locked-down workflow:

name: Agent-Generated Build
on:
  pull_request:  # Not pull_request_target

permissions: {}  # No GITHUB_TOKEN permissions

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Build
        run: |
          npm ci
          npm run build
      # No secret access, no deployment, no network calls

This workflow can build and test but cannot exfiltrate secrets or deploy artifacts.

Failure Modes

The most likely failure modes when defending against workflow backdoors:

  • False negatives: Malicious steps that use legitimate-looking actions (e.g., actions/github-script with inline JavaScript that exfiltrates secrets)
  • Review fatigue: High volume of workflow changes from agents leads to rubber-stamp approvals
  • Inherited risk: Third-party actions that are compromised after initial review (supply-chain attack on the action itself)
  • Self-hosted runners: If runners are persistent and not ephemeral, malware can persist across workflow runs

The Megalodon attack succeeded because it targeted repositories with weak review processes and high trust in bot-like commit authors.

Technical Verdict

Use GitHub Actions workflows with strict boundaries when:

  • You enforce pull_request triggers for untrusted contributions
  • You audit all secrets.* references and restrict access to specific jobs
  • You use ephemeral runners and deny GITHUB_TOKEN permissions by default
  • You treat workflow file changes as infrastructure changes requiring separate approval

Avoid or heavily sandbox when:

  • Agents generate workflow files without human review of trigger types and secret access
  • You rely on pull_request_target for preview deployments without validating the PR code first
  • You use self-hosted runners with persistent state or network access to internal systems
  • You assume bot-like commit authors are trustworthy without verifying the change content

The Megalodon attack shows that CI workflows are not just automation. They are privileged code that runs with production credentials. Treat them like you would treat deployment scripts or infrastructure-as-code: with strict review, limited permissions, and the assumption that any modification is a potential backdoor.