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

推荐订阅源

Martin Fowler
Martin Fowler
Jina AI
Jina AI
J
Java Code Geeks
Microsoft Security Blog
Microsoft Security Blog
Recent Announcements
Recent Announcements
I
InfoQ
L
LangChain Blog
The Cloudflare Blog
IT之家
IT之家
博客园 - 叶小钗
Apple Machine Learning Research
Apple Machine Learning Research
B
Blog
A
About on SuperTechFans
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Last Week in AI
Last Week in AI
Blog — PlanetScale
Blog — PlanetScale
罗磊的独立博客
云风的 BLOG
云风的 BLOG
Microsoft Azure Blog
Microsoft Azure Blog
Engineering at Meta
Engineering at Meta
F
Fortinet All Blogs
博客园 - 聂微东
美团技术团队
博客园_首页

Step Security Blog

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 xygeni-action Compromised: C2 Reverse Shell Backdoor Injected via Tag Poisoning - 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
elementary-data Compromised on PyPI and GHCR: Forged Rele...
2026-04-25 · via Step Security Blog

A malicious version of elementary-data (0.23.3) was published to PyPI and is, at the time of writing, still listed as the latest release. elementary-data is a widely deployed Python package for dbt data observability.

The same release run also pushed a multi-arch container image to GitHub Container Registry at ghcr.io/elementary-data/elementary, tagged both 0.23.3 and latest. Every unpinned docker pull ghcr.io/elementary-data/elementary and every FROM ghcr.io/elementary-data/elementary line without a pinned tag has been pulling the trojaned image since April 24.

The attacker exploited a script injection vulnerability in one of the project's own GitHub Actions workflows, then used the workflow's GITHUB_TOKEN to forge a signed release commit and dispatch the legitimate publishing pipeline against it — without ever touching the master branch or opening a pull request.

UPDATE: The Elementary team removed elementary-data 0.23.3 from PyPI and the matching malicious image from GHCR. They have since published a clean replacement, 0.23.4, and the :latest tag now resolves to the clean image. The maintainer's full incident notice is in issue #2205.

The compromise was reported by crisperik in issue #2205 on April 25, 2026, and shortly afterwards confirmed by H-Max, who also escalated it directly on the Elementary community Slack.

Issue #2205 — the original community report.

elementary-data==0.23.3 was uploaded to PyPI on April 24, 2026 at 22:20:47 UTC. Both the wheel and the source distribution contain a single malicious addition compared to 0.23.2: a top-level elementary.pth file. Python automatically discovers .pth files in site-packages and execs any line beginning with import at interpreter startup — meaning the payload fires on every Python invocation in any environment where the package is installed, not only on import elementary.

PyPI listing for elementary-data 0.23.3. The malicious release sits at the top of the version history, marked as the latest release. It was uploaded on April 24, 2026 at 22:20:47 UTC and remains live and unyanked at the time of writing

The corresponding GitHub release is the giveaway. The release name, dsajdkjsajkdsajk, and body, dsakdjsakjdjsa, are gibberish - an attacker keyboard-mash that no maintainer would have signed off on. The release was created by github-actions[bot], not by a human, and is still labelled "Latest" on the project page:

The v0.23.3 GitHub release. Compare the title and body — dsajdkjsajkdsajk and dsakdjsakjdjsa — against the prior release, Python v0.23.2, which follows the project's normal naming convention.

The v0.23.3 Git tag points at commit b1e4b1f3. That commit changes exactly two things: it bumps pyproject.toml to 0.23.3, and it adds elementary.pth — a single line, ~245 KB of base64:

The malicious elementary.pth file shipped inside the wheel

The Docker Image Is Compromised Too Including :latest

The same Release package workflow that uploads to PyPI also has a build-and-push-docker-image job. Both jobs ran successfully against the orphan-tagged commit and finished in the same workflow run. The result is a multi-arch (linux/amd64 + linux/arm64) image at ghcr.io/elementary-data/elementary, tagged with both 0.23.3 and latest, that carries the same payload as the wheel:

  • Compromised: ghcr.io/elementary-data/elementary:0.23.3 → digest sha256:31ecc5939de6...634255
  • Compromised (same digest): ghcr.io/elementary-data/elementary:latest → digest sha256:31ecc5939de6...634255
  • Clean: ghcr.io/elementary-data/elementary:0.23.2 → digest sha256:b3bbfafde1a0...35d3d9

The image landing at :latest is the consequential part. Many teams pin Python package versions in requirements.txt or lockfiles but use latest (or no tag at all, which defaults to latest) for container images. Anyone running a Kubernetes deployment, an Argo CD application, a Docker Compose stack, or a Dockerfile FROM line that does not pin the image by digest has been pulling the trojaned build since April 24.

The Payload: A Three-Stage Credential Stealer

The .pth file decodes a base64 wrapper, which then walks two more layers of XOR-with-MD5-keystream encryption before reaching the actual collector. Two cipher seeds are baked into the payload as cleartext strings:

  • swabag — seed for stage 1 → stage 2
  • for any questions: contact 050afbe046d7545f5af1a0d3fcfbaf6e993fd93d487b431f09bc9e963c7220a135 on session — seed for stage 2 → stage 3 (the string also functions as the actor's contact channel)

Stage 3 is a comprehensive credential and secret harvester. It reads from disk and from live cloud APIs:

  • Identity: all SSH private keys, authorized_keys, known_hosts, ~/.git-credentials, gh auth token
  • Cloud (file + live API): AWS credentials and IMDSv2 role lookup, then SigV4-signed direct calls to AWS Secrets Manager (ListSecrets/GetSecretValue) and SSM Parameter Store; GCP application_default_credentials.json; Azure ~/.azure
  • Container & orchestration: ~/.docker/config.json, ~/.kube/config, all /etc/kubernetes/*.conf, ServiceAccount tokens, kubectl get secrets --all-namespaces
  • Secrets at rest: every .env* reachable to depth 6, ~/.npmrc, ~/.pypirc, ~/.cargo/credentials.toml, ~/.vault-token, ~/.netrc, ~/.pgpass, ~/.my.cnf
  • Crypto wallets: Bitcoin, Litecoin, Dogecoin, Zcash, Dash, Monero, Ripple wallet configs and wallet*.dat; Ethereum keystores; Cardano keys; Solana validator and identity keypairs (validator-keypair.json, id.json, etc.); Anchor target/deploy keys
  • System: /etc/passwd, /etc/shadow, shell histories, /var/log/auth.log

The collected output is tar-gzipped into trin.tar.gz and POSTed in a single request via curl --data-binary to:

https://igotnofriendsonlineorirl-imgonnakmslmao.skyhanni.cloud/
Header: X-Rise-To-The-Trinny: agree

How the Forged Release Reached PyPI and GHCR

Step 1: A comment that became code

The first move was a single comment on an open pull request. PR #2147 is a long-lived master → docs sync PR opened automatically by the project's release pipeline back in March, sitting open in the queue. The attacker dropped a single line into the comment box:

The comment that started the attack. The author realtungtungtungsahur is a 2-day-old GitHub account with no prior activity.

The vulnerable workflow is .github/workflows/update_pylon_issue.yml. Its first step interpolates the comment body directly into a run: block:

The unsafe line in update_pylon_issue.yml. The expression ${{ github.event.comment.body }} is expanded by the runner into the shell script before bash parses it.

This is a textbook GitHub Actions script injection vulnerability. The same class of bug appears across github.event.issue.title, github.event.pull_request.title, github.head_ref, and similar fields. When the comment fired the workflow at 22:10:14, the runner started a handle_comment job with the repository's GITHUB_TOKEN in scope, then immediately executed the attacker's curl | bash stager:

The injected payload running inside the workflow. The job log shows the curl | bash command from the comment body executing as part of the Extract Issue or Pull Request Details step.

Step 2: Forging a release commit, then keeping the runner alive

The forged commit's message, release/v0.23.2 (#2188), is a verbatim copy of an unrelated, legitimate PR title from nine days earlier:

The forged commit b1e4b1f3. Author github-actions[bot], committer web-flow, green "Verified" PGP badge, message release/v0.23.2 (#2188). The diff adds elementary.pth at the repository root and bumps pyproject.toml to 0.23.3.

The original handle_comment job did not finish quickly. It kept running for over two and a half hours before finally exiting with status failure — long enough for the rest of the attack to play out under the cover of an "in-progress" workflow run:

The hung comment-trigger run. Triggered by realtungtungtungsahur at 22:10:14 UTC, conclusion failure, total runtime 2 hours 46 minutes.

Step 3: Dispatching the legitimate publishing pipeline

With the malicious commit in place and the v0.23.3 tag pointing at it, the attacker called the GitHub API to dispatch the Release package workflow with input tag=v0.23.3. The workflow's checkout step uses ref: ${{ inputs.tag || github.ref }}, so it built straight from the orphan-tagged commit:

The Release package run that did the publishing. Event: workflow_dispatch. Triggering actor: github-actions[bot]

The PyPI publish step running against the orphan commit. Inside publish-to-pypi, the pypa/gh-action-pypi-publish action uploads the freshly built wheel and sdist to PyPI using the project's stored PYPI_USER / PYPI_PASS secrets.

How StepSecurity Detects and Prevents This

Threat Intelligence: 24x7 SOC and Threat Center

StepSecurity operates a 24x7 Security Operations Center that continuously monitors npm, PyPI, GitHub Actions, and the wider open-source ecosystem for supply chain attacks. When the SOC confirms a compromise, the StepSecurity Threat Center publishes a real-time advisory to our customers with "Am I Affected?" links pre-wired to that tenant's own codebase, CI baselines, and developer-machine inventory and the relevant indicators are pushed to downstream protections (Harden-Runner global block list, Compromised Package Check, Developer MDM, etc.) so they take effect across every workflow without any customer configuration change.

The Threat Center advisory for this incident. Customers see the alert with "Am I Affected?" links resolved to their own organization, the C2 domain pinned for baseline lookup, and the compromised package and image versions ready to feed into the codebase, CI, and developer-machine searches.

Block C2 traffic with Harden-Runner

Harden-Runner monitors every outbound connection from your GitHub Actions runners. The C2 domain has been added to the Harden-Runner global block list, so every workflow using Harden-Runner now refuses the curl POST to igotnofriendsonlineorirl-imgonnakmslmao.skyhanni.cloud before any credential leaves the runner.

Harden-Runner blocking the C2 callback. Network event view from a controlled run that installed elementary-data==0.23.3 and tried to reach the C2. Harden-Runner identifies the outbound call, classifies it as an attack, and refuses the connection. You can inspect the live run for yourself: Harden-Runner Insights — Network Events.

Block known-compromised packages at PR time

The PyPI Compromised Package Check blocks pull requests that introduce a known-malicious version. elementary-data==0.23.3 has been added to the list. The PyPI Package Cooldown Check would also have flagged a PR that adopted 0.23.3 for being too newly published to trust, holding it for review until the cooldown window elapsed.

The PR-time check in action. A pull request that introduces elementary-data==0.23.3 fails the StepSecurity Compromised Package Check, with the run output explaining why the version is blocked and pointing reviewers at the corresponding advisory.

Discover affected developer machines

StepSecurity Developer MDM inventories Python packages installed across enrolled developer machines so you can identify exposure within minutes of a disclosure.

Indicators of Compromise

  • Compromised PyPI package: elementary-data==0.23.3
  • Last clean PyPI version: 0.23.2
  • Compromised container image: ghcr.io/elementary-data/elementary:0.23.3 and :latest (both at digest sha256:31ecc5939de6d24cf60c50d4ca26cf7a8c322db82a8ce4bd122ebd89cf634255; multi-arch linux/amd64 + linux/arm64)
  • Last clean container image: ghcr.io/elementary-data/elementary:0.23.2 (digest sha256:b3bbfafde1a0db3a4d47e70eb0eb2ca19daef4a19410154a71abee567b35d3d9)
  • Injection file: elementary.pth at the package root (single base64-wrapped line, ~245 KB)
  • Git tag: v0.23.3 → commit b1e4b1f3aad0d489ab0e9208031c67402bbb8480 (orphan; not reachable from any branch)
  • C2 / exfiltration domain: igotnofriendsonlineorirl-imgonnakmslmao.skyhanni.cloud
  • Exfiltration header: X-Rise-To-The-Trinny: agree
  • Exfiltration archive: trin.tar.gz (created in temp dir; auto-cleaned post-upload)
  • Persistent execution marker: $TMPDIR/.trinny-security-update
  • Stager URL (expired): https://litter.catbox.moe/iqesmbhukgd2c7hq.sh
  • Attacker GitHub account: realtungtungtungsahur (created April 22, 2026)
  • Actor contact (Session ID): 050afbe046d7545f5af1a0d3fcfbaf6e993fd93d487b431f09bc9e963c7220a135

Acknowledgements

Credit for this disclosure belongs to two members of the elementary-data community whose quick action shortened the exposure window:

  • crisperik — identified that the v0.23.3 release contained malicious base64-encoded code, recognised the similarity to the recent litellm compromises, and opened issue #2205 at 06:18 UTC on April 25.
  • H-Max — independently confirmed the report on the issue minutes later and posted to the Elementary community Slack so a maintainer would see it directly, accelerating the response.

We also recognise the Elementary team for their fast investigation and remediation: the malicious artifacts were removed from PyPI and GHCR within hours of the report, a clean replacement (0.23.4) was published the same day, and a transparent public incident notice was posted on issue #2205.