elementary-data 0.23.3 Was Compromised for 48 Hours Before Anyone Noticed

elementary-data 0.23.3 Was Compromised for 48 Hours Before Anyone Noticed#
On April 24 at 22:54 UTC, a malicious version of elementary-data was published to PyPI. The package has 1.1 million monthly downloads. It is the core of the Elementary open-source data observability platform, used by data and analytics engineers running dbt pipelines across Snowflake, BigQuery, Postgres, and Databricks.
The compromise was not discovered publicly until April 26, when a community member opened a GitHub issue. The malicious version was live and installable for roughly 48 hours.
No CVE has been filed. A CVE-only security tool returns a clean result for elementary-data==0.23.3 today.
How the attack worked#
This is not the standard "compromised maintainer account" story. The attacker never needed the maintainers' credentials.
Instead, they exploited a GitHub Actions script injection vulnerability. The attack sequence:
- The attacker posted a malicious comment on an open pull request in the elementary-data repository
- A GitHub Actions workflow flaw caused the workflow to execute attacker-controlled shell code from the comment text
- The workflow's
GITHUB_TOKENwas exposed - The attacker used the token to forge a signed commit and tag:
v0.23.3 - The tag triggered elementary-data's legitimate release pipeline
- The pipeline built and published the backdoored package to PyPI and a malicious image to GitHub Container Registry simultaneously
- The release appeared as an official, signed elementary-data release
Systems that did not pin their elementary-data version pulled
0.23.3automatically during that window. There was nothing visually or cryptographically distinguishable about the malicious release from any legitimate one.
What the payload does#
The malicious release contained elementary.pth, a Python path configuration file that executes automatically at interpreter startup before any user code runs, before any CI guard can intervene.
The payload collected SSH keys and Git credentials, AWS, GCP, and Azure credentials, Kubernetes and Docker secrets, CI environment variables, .env files and developer tokens, crypto wallet files, and system data including /etc/passwd and shell history.
If you had elementary-data without a pinned version in any environment that ran between April 24 and April 27, treat everything that environment had access to as compromised and rotate immediately.
The .pth pattern#
This is the second confirmed use of the .pth execution technique in 33 days.
On March 24, versions 1.82.7 and 1.82.8 of LiteLLM were compromised by TeamPCP using litellm.pth. On April 24, elementary-data 0.23.3 used elementary.pth. Different packages, different threat actors, same primitive.
Python evaluates .pth files in the site-packages directory on every interpreter startup. It happens before any user code, before any import guard, before any runtime security check. Once a malicious .pth file is installed, the only way to stop it executing is to remove the package.
The technique works because it is simple, reliable, and leaves no obvious trace in the package's main code. A developer inspecting elementary/ would not see the malicious logic. It lives in a separate file that Python loads invisibly.
What Attestd returns#
elementary-data is now monitored by Attestd's supply chain integrity layer. This was added today in response to this incident.
curl "https://api.attestd.io/v1/check?product=elementary-data&version=0.23.3" \
-H "Authorization: Bearer YOUR_API_KEY"
{
"product": "elementary-data",
"version": "0.23.3",
"supported": true,
"risk_state": "none",
"supply_chain": {
"compromised": true,
"sources": ["osv", "registry"],
"malware_type": "backdoor",
"description": "GitHub Actions script injection via PR comment forged signed v0.23.3 release. .pth file executes at startup stealing SSH keys, cloud credentials, CI secrets, crypto wallets.",
"advisory_url": "https://www.stepsecurity.io/blog/elementary-data-compromised-on-pypi-and-ghcr-forged-release-pushed-via-github-actions-script-injection",
"compromised_at": "2026-04-24T22:54:25Z",
"removed_at": "2026-04-27T00:00:00Z"
}
}
Three things worth noting about this response.
risk_state: "none" alongside supply_chain.compromised: true. No CVE exists for this compromise. A tool that only checks CVE data returns a clean result. The supply chain signal is the only structured detector that catches this category of attack.
sources: ["osv", "registry"] means two independent sources flagged this version. OSV published advisory MAL-2026-3083. Attestd's own registry entry fired separately. Independent confirmation, not a single source.
compromised_at: "2026-04-24T22:54:25Z" is the timestamp from the OSV advisory, reflecting when the malicious commit was first observed. The package was compromised April 24, not April 26. The public disclosure came two days later.
The clean replacement:
curl "https://api.attestd.io/v1/check?product=elementary-data&version=0.23.4" \
-H "Authorization: Bearer YOUR_API_KEY"
{
"product": "elementary-data",
"version": "0.23.4",
"supported": true,
"risk_state": "none",
"supply_chain": {
"compromised": false,
"sources": []
}
}
The detection gap#
Attestd's OSV sweep flagged MAL-2026-3083 at 12:42 AM on April 27. The sweep runs continuously across all of PyPI's MAL- advisory namespace, not just monitored packages. It surfaces unmonitored packages with confirmed malicious advisories so they can be added to the watchlist.
The BleepingComputer article reporting on this incident published later that morning.
The 48-hour window between compromise and public awareness is not unusual. It is the normal pattern. An attacker who exploits a CI/CD pipeline rather than compromising an account produces a release that is indistinguishable from a legitimate one. Without an automated supply chain signal layer, the only detection mechanism is a community member noticing something unusual and opening a GitHub issue. That takes time.
The dbt ecosystem is now monitored#
Today's expansion adds elementary-data alongside the full dbt ecosystem to Attestd's supply chain watchlist. The monitored PyPI package list now includes dbt-core, dbt-bigquery, dbt-snowflake, dbt-postgres, dbt-databricks, and great-expectations.
Data engineers building AI pipelines on dbt are a specific, high-value target. The packages they depend on process production credentials and infrastructure configuration. A compromise in this layer has the same blast radius as a compromised AI agent framework.
The full monitored package list is at attestd.io/docs/supply-chain.
What to do if you were affected#
If elementary-data without a pinned version was installed in any environment between April 24 and April 27:
Rotate SSH keys, Git credentials, all cloud credentials (AWS, GCP, Azure), Kubernetes and Docker secrets, CI environment variables, and any tokens stored in .env files. Rebuild affected environments from a known safe point. Check for unexpected process activity or outbound connections during the exposure window.
Upgrade to elementary-data==0.23.4 and pin the version.
Get an API key at api.attestd.io/portal/login. Free tier, 1,000 calls a month, no credit card required.