JustAppSec
Back to news

Script injection in GitHub Actions ships malicious elementary-data to PyPI

3 min readPublished 27 Apr 2026Source: Elementary Data

TL;DR - An attacker dropped a crafted PR comment that got interpolated into a shell context by a vulnerable GitHub Actions workflow. That gave them code execution on a CI runner with access to workflow secrets. They used those secrets to trigger release.yml and publish elementary-data==0.23.3 - a malicious build - to PyPI and a Docker registry. If you ran 0.23.3, treat every credential in that environment as compromised.

What happened

elementary-data is Elementary's open-source Python CLI, commonly run inside data and CI pipelines.

On April 24, 2026, an attacker exploited a script-injection vulnerability in one of Elementary's GitHub Actions workflows. The attack shape: a crafted pull request comment body was interpolated directly into a shell context by a vulnerable workflow step. That gave the attacker arbitrary code execution on the CI runner, which had access to workflow secrets. From there, they triggered release.yml via workflow_dispatch and published two malicious artefacts: elementary-data version 0.23.3 to PyPI, and a corresponding Docker image to Elementary's registry.

The window ran from 2026-04-24 22:10 UTC to 2026-04-25 09:45 UTC.

The real risk here is not a bad package version sitting on a registry. It is that a single workflow injection can become a direct publishing compromise - which is the same failure mode behind Cline, tj-actions, and most other recent CI supply-chain incidents.

Who is impacted

  • Users who downloaded and executed elementary-data==0.23.3 during the exposure window.
  • Users who pulled and ran the affected Docker image between 2026-04-24 22:10 UTC and 2026-04-25 09:45 UTC.
  • Elementary confirms no impact to Elementary Cloud, the Elementary dbt package, or any other CLI versions.

Indicators of compromise (from the report):

IndicatorValue
Compromised packageelementary-data==0.23.3
Injection fileelementary.pth
Exfiltration domainigotnofriendsonlineorirl-imgonnakmslmao.skyhanni.cloud
Execution marker$TMPDIR/.trinny-security-update

What to do now

  • Check whether you installed the compromised version:
    • pip show elementary-data | grep Version
  • If you have 0.23.3, remove it and install the safe release:

    "If the version is 0.23.3, uninstall it and replace with the safe version:"

    • pip uninstall elementary-data
    • pip install elementary-data==0.23.4

    "In your requirements and lockfiles, pin explicitly to elementary-data==0.23.4."

  • Delete pip cache files per vendor guidance to avoid stale artefacts.
  • Check for the execution marker on any machine where the CLI may have run:
    • macOS / Linux: /tmp/.trinny-security-update
    • Windows: %TEMP%\.trinny-security-update
  • Treat this as a secrets exposure event if 0.23.3 ran anywhere in your environment:

    "Users who installed 0.23.3, or who pulled and ran the affected Docker image, should assume that any credentials accessible to the environment where it ran may have been exposed."

    • Rotate every credential accessible to the affected environment. Elementary explicitly calls out: dbt profiles, warehouse credentials, cloud provider keys, API tokens, SSH keys, and .env contents.
    • Prioritise CI/CD runners first - they typically hold the broadest secret access at runtime.
  • Escalate to your security team to hunt for unauthorised use of exposed credentials, using the IOCs above.

Why this matters for AppSec

This incident is the same attack chain that has hit multiple projects in the last 12 months: unsanitised GitHub context variables interpolated into shell steps, leading to CI code execution, leading to registry compromise.

The lessons are straightforward:

  1. Never interpolate GitHub context values directly into shell steps. Use intermediate environment variables instead. GitHub's own hardening guide covers this explicitly.
  2. Scope publish tokens tightly and rotate them. A token that can publish to PyPI should not live indefinitely as a workflow secret with broad scope.
  3. Adopt OIDC-based publishing where the registry supports it (PyPI does). Short-lived, audience-scoped tokens eliminate the stolen-token class of attack entirely.
  4. Audit workflow_dispatch triggers. An attacker who gains code execution on a runner with access to workflow secrets can trigger downstream workflows. Treat workflow_dispatch as a privileged action.

Additional information

Related


Content is AI-assisted and reviewed by our team, but issues may be missed and best practices evolve rapidly, send corrections to [email protected]. Always consult official documentation and validate key implementation decisions before making design or security choices.

Need help?Get in touch.