CriticalSupply chainPatch available

elementary-data 0.23.3 backdoor: GitHub Actions comment injection published an infostealer to PyPI and GHCR

elementary-data 0.23.3 on PyPI and its GHCR image ran a credential stealer via elementary.pth. Find 0.23.3, move to 0.23.4 or later, and rotate secrets.

Published
Updated
Fixed in
elementary-data 0.23.4 (clean replacement); 0.23.2 was the last clean release before the attack
Exploitation
Yes. 0.23.3 was live on PyPI from 22:20 UTC on 24 April to 09:45 UTC on 25 April 2026

What happened

On 24 April 2026, an attacker published a backdoored elementary-data 0.23.3, the Python CLI of the Elementary dbt observability tool. No maintainer account was stolen. The attacker abused the project’s own release pipeline (StepSecurity):

  1. The workflow .github/workflows/update_pylon_issue.yml put ${{ github.event.comment.body }} straight into a run: block. At 22:10 UTC the attacker account realtungtungtungsahur, created two days earlier, commented on PR #2147. The comment ran as shell code with the workflow’s GITHUB_TOKEN.
  2. With that token, the attacker created an orphan commit b1e4b1f3aad0d489ab0e9208031c67402bbb8480 authored as github-actions[bot], which GitHub showed as “Verified”. It added elementary.pth and bumped the version to 0.23.3. The attacker tagged it v0.23.3 and created a release.
  3. The attacker then dispatched the real Release package workflow with tag=v0.23.3. It built from the orphan commit and published to PyPI at 22:20 UTC, and pushed a multi-arch image to GHCR as 0.23.3 and latest.

A user reported it in issue #2205 on 25 April. The maintainers quarantined and then removed 0.23.3 from PyPI and Docker, and published a clean 0.23.4 the same day. The OSV record gives the PyPI exposure window as 22:20 UTC on 24 April to 09:45 UTC on 25 April (OSV MAL-2026-3083). The maintainers say Elementary Cloud, the Elementary dbt package and other CLI versions were not affected (issue #2205).

How the payload works

Details from StepSecurity:

  • elementary.pth sits in site-packages. Python runs import lines in .pth files at every interpreter start, so the payload ran on any Python invocation in that environment, not only when you used Elementary.
  • It decodes about 245 KB of base64, then two XOR layers.
  • It collects SSH keys, ~/.git-credentials and gh auth token output; AWS credentials, IMDSv2 role data, and live AWS Secrets Manager and SSM Parameter Store values; GCP and Azure credential files; Docker config, kubeconfig and service-account tokens; .env* files, .npmrc, .pypirc, .cargo/credentials.toml, .vault-token, .netrc, .pgpass, .my.cnf; crypto wallets; and /etc/passwd, /etc/shadow, shell history and /var/log/auth.log.
  • It packs everything into trin.tar.gz and POSTs it to igotnofriendsonlineorirl-imgonnakmslmao.skyhanni[.]cloud with the header X-Rise-To-The-Trinny: agree, then writes a marker file $TMPDIR/.trinny-security-update.

Am I affected?

bash
# Installed version (0.23.3 is the bad one)
pip show elementary-data 2>/dev/null | grep -E '^Version'

# The payload file in any Python environment on this machine
find / -name 'elementary.pth' -path '*site-packages*' 2>/dev/null

# Marker left by the payload
ls -la "${TMPDIR:-/tmp}/.trinny-security-update" 2>/dev/null

# Pins in requirements and lockfiles
grep -rnE 'elementary-data(\[[^]]*\])?==0\.23\.3' --include='requirements*.txt' --include='*.in' .
grep -nE -A1 'name = "elementary-data"' poetry.lock uv.lock 2>/dev/null | grep '"0.23.3"'

# Container images on this host, by digest
docker image ls --digests ghcr.io/elementary-data/elementary

The malicious GHCR digest is sha256:31ecc5939de6d24cf60c50d4ca26cf7a8c322db82a8ce4bd122ebd89cf634255. The clean 0.23.2 image is sha256:b3bbfafde1a0db3a4d47e70eb0eb2ca19daef4a19410154a71abee567b35d3d9 (StepSecurity). Any Dockerfile or job that pulled :latest in the window got the bad build.

Unpinned pip install elementary-data in CI during the window also resolved to 0.23.3. Check pip logs and build output for that version string. In DNS, proxy and egress logs, look for skyhanni.cloud, the stager URL litter.catbox.moe/iqesmbhukgd2c7hq.sh (OSV MAL-2026-3083), and POSTs carrying the X-Rise-To-The-Trinny header.

What to do now

  1. Upgrade. Run pip uninstall elementary-data and install 0.23.4 or later (issue #2205). As of 2 November 2026, PyPI lists 0.26.1 as the latest release (PyPI). Delete elementary.pth if it survived the uninstall, and rebuild virtual environments from a pinned lockfile.
  2. Rotate. The maintainers name dbt profiles, warehouse credentials, cloud keys, API tokens, SSH keys and .env contents, and say CI runners are most exposed (issue #2205). Given what the payload read, also rotate AWS Secrets Manager and SSM values it could reach, Kubernetes service-account tokens, and npm, PyPI, Cargo and Vault tokens.
  3. Purge the image. Remove the bad digest from runners, caches and registry mirrors, and pin ghcr.io/elementary-data/elementary by digest.
  4. Block and hunt for the C2 domain and header from 24 April 2026 onward.
  5. Fix the same bug in your own workflows. Never interpolate github.event.comment.body, issue titles or branch names into run:. Pass them through env: and quote the variable. Give GITHUB_TOKEN read-only permissions by default, and restrict who can dispatch release workflows (StepSecurity).

Why this matters

The “Verified” badge and the bot author made the forged commit look like routine automation, and the real pipeline produced the artifacts. Provenance that only says “built by our workflow” would have vouched for this release. What actually failed was one unquoted expression in a minor workflow that held a token able to write tags and dispatch releases.

Sources