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
- Ecosystem
- PyPIGitHub ActionsCI/CDCloud
- 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):
- The workflow
.github/workflows/update_pylon_issue.ymlput${{ github.event.comment.body }}straight into arun:block. At 22:10 UTC the attacker accountrealtungtungtungsahur, created two days earlier, commented on PR #2147. The comment ran as shell code with the workflow’sGITHUB_TOKEN. - With that token, the attacker created an orphan commit
b1e4b1f3aad0d489ab0e9208031c67402bbb8480authored asgithub-actions[bot], which GitHub showed as “Verified”. It addedelementary.pthand bumped the version to 0.23.3. The attacker tagged itv0.23.3and created a release. - The attacker then dispatched the real
Release packageworkflow withtag=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 as0.23.3andlatest.
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.pthsits insite-packages. Python runsimportlines in.pthfiles 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-credentialsandgh auth tokenoutput; 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.gzand POSTs it toigotnofriendsonlineorirl-imgonnakmslmao.skyhanni[.]cloudwith the headerX-Rise-To-The-Trinny: agree, then writes a marker file$TMPDIR/.trinny-security-update.
Am I affected?
# 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/elementaryThe 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
- Upgrade. Run
pip uninstall elementary-dataand install 0.23.4 or later (issue #2205). As of 2 November 2026, PyPI lists 0.26.1 as the latest release (PyPI). Deleteelementary.pthif it survived the uninstall, and rebuild virtual environments from a pinned lockfile. - Rotate. The maintainers name dbt profiles, warehouse credentials, cloud keys, API tokens, SSH keys and
.envcontents, 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. - Purge the image. Remove the bad digest from runners, caches and registry mirrors, and pin
ghcr.io/elementary-data/elementaryby digest. - Block and hunt for the C2 domain and header from 24 April 2026 onward.
- Fix the same bug in your own workflows. Never interpolate
github.event.comment.body, issue titles or branch names intorun:. Pass them throughenv:and quote the variable. GiveGITHUB_TOKENread-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
- StepSecurity: elementary-data compromised on PyPI and GHCR, forged release via GitHub Actions script injection
- elementary-data issue #2205: maintainer statement and guidance
- OSV MAL-2026-3083: malicious code in elementary-data
- Cloaked: elementary-data PyPI supply chain attack
- elementary-data release history on PyPI