Supply-Chain Attacks Turn Security and DevSecOps Tools into Credential-Theft Paths

Summary
An analysis of supply-chain compromises affecting XZ Utils, GitHub Actions dependencies, Trivy, and LiteLLM describes how attackers abused trusted tools and release paths to steal credentials, and outlines defensive measures.
Key points
- The XZ Utils backdoor used malicious binary test fixtures and a build-time injection mechanism; it was discovered after an engineer noticed unusual SSH authentication latency.
- A compromised reviewdog dependency propagated through GitHub Actions to tj-actions/changed-files, exposing CI runner memory to credential scraping across more than 23,000 repositories.
- Attackers retained an Aqua Security bot token after credential rotation, then poisoned Trivy action tags and a release; payloads targeted runner memory or files containing credentials.
- The Trivy payload used Internet Computer infrastructure for C2 and a GitHub release as a fallback exfiltration path, complicating conventional takedown responses.
- Malicious LiteLLM PyPI versions used a Python .pth file to run automatically when Python started, collecting credentials and Kubernetes secrets; a process-forking bug caused crashes that helped expose it.
- The article recommends pinning GitHub Actions to full commit SHAs, auditing and rotating bot tokens, monitoring action entrypoint changes, reviewing pull_request_target workflows, and checking package provenance.
- It says the Trivy and LiteLLM incidents shared persistence naming and encryption patterns, but leaves open whether they involved the same actor or a shared toolkit.
Article Details
- Attack Vectors
- XZ Utils 5.6.0 and 5.6.1 contained a backdoor introduced through binary test files that injected a precompiled object into the liblzma build.
- The XZ operation used contributor personas to build trust and pressure the maintainer before malicious code was introduced.
- A compromised reviewdog action propagated through transitive GitHub Actions dependencies to tj-actions/changed-files, where a Python payload scraped CI runner process memory for secrets.
- Aqua Security's Trivy workflows were exploited through pull_request_target; after an incomplete credential rotation, retained aqua-bot credentials were used to repoint action tags and publish a malicious Trivy release.
- The Trivy payload harvested credentials from runner memory or filesystem locations, then used ICP-hosted C2 and a GitHub release asset as an exfiltration path.
- Malicious LiteLLM versions were uploaded directly to PyPI using compromised maintainer credentials, bypassing the GitHub release pipeline. A .pth file executed payload code when Python started.
- The LiteLLM payload collected credentials and Kubernetes secrets, created a privileged pod mounting the host filesystem, and installed persistence as a systemd user service.
- Defensive Notes
- Pin GitHub Actions to full commit SHAs rather than mutable version tags.
- After a CI/CD compromise, audit and rotate bot and service-account tokens, including tokens with release or tag write permissions.
- Monitor downloaded GitHub Action entrypoint sizes against per-action, per-SHA baselines and investigate significant deviations.
- Map transitive Action dependencies and review their write permissions and ability to execute shell commands.
- Block and log CI runner egress to blockchain domains such as *.icp0.io, as recommended by the article.
- Audit workflows using pull_request_target and apply least-privilege secret scopes; replace the trigger with pull_request when its use is not justified.
- Verify commit identity using commit SHAs and provenance or transparency records rather than relying on GitHub UI timestamps.
- Check package versions against corresponding GitHub releases or signed provenance, and treat mismatches as unverified.
- Treat files matching ~/.config/sysmon*.py on developer machines or CI runners as requiring immediate triage, as recommended by the article.
Indicators of compromise
| Type | Indicator | Context |
|---|---|---|
| DOMAIN | scan[.]aquasecurtiy[.]org | Typosquatted domain identified as the Trivy incident's primary exfiltration destination. |
| URL | hxxps[:]//models[.]litellm[.]cloud/ | Typosquatted URL used to receive the encrypted LiteLLM credential bundle. |
| URL | hxxps[:]//tdtqy-oyaaa-aaaae-af2dq-cai[.]raw[.]icp0[.]io | Primary C2 URL polled by the malicious Trivy binary. |
MITRE ATT&CK
T1027 · Obfuscated Files or InformationThe XZ payload was stored in binary test fixtures and de-obfuscated at build time using tr.T1036 · MasqueradingThe XZ operation used credible fake contributor identities to author commits and pressure the maintainer.T1036.005 · Match Legitimate Resource Name or LocationThe Trivy and LiteLLM payloads used sysmon.py naming to resemble legitimate system-monitoring artifacts.T1041 · Exfiltration Over C2 ChannelThe Trivy and LiteLLM payloads sent encrypted data to their C2 destinations.T1048 · Exfiltration Over Alternative ProtocolThe tj-actions incident exfiltrated secrets by printing them to public CI workflow logs.T1059.006 · PythonA malicious Python script ran on CI runners and scraped process memory in the tj-actions incident.T1098 · Account ManipulationAn unrevoked aqua-bot service-account token retained release-signing access after credential rotation.T1102 · Web ServiceThe malicious Trivy binary polled an ICP blockchain-hosted endpoint for C2.T1195.001 · Compromise Software Dependencies and Development ToolsMalicious code entered software dependencies or development tools, including the XZ Utils build and poisoned reviewdog action.T1195.002 · Compromise Software Supply ChainThe Trivy incident exploited a pull_request_target workflow and force-pushed action tags to malicious code.T1199 · Trusted RelationshipA poisoned reviewdog action propagated through transitive dependencies to tj-actions and downstream repositories.T1528 · Steal Application Access TokenThe tj-actions payload extracted GitHub Actions runner tokens and repository secrets from process memory.T1543.001 · Launch AgentThe LiteLLM payload installed sysmon.service as a persistent systemd user service.T1552 · Unsecured CredentialsTrivy and LiteLLM payloads searched filesystems for SSH keys, cloud credentials, Kubernetes secrets, and other sensitive data.T1552.001 · Credentials In FilesThe tj-actions payload read /proc/{PID}/mem and searched runner memory for GitHub secret structures.T1554 · Compromise Host Software BinaryA backdoored XZ Utils binary was distributed through upstream release channels.T1556 · Modify Authentication ProcessThe XZ implant hooked RSA_public_decrypt resolution and weakened SSH public-key authentication.T1567.001 · Exfiltration to Code RepositoryThe Trivy payload uploaded an encrypted credential bundle as a release asset in an attacker-created GitHub repository.T1585.001 · Social Media AccountsThe XZ operation used fake contributor personas to establish accounts and pressure the maintainer.T1611 · Escape to HostThe LiteLLM payload created a privileged Kubernetes pod in kube-system that mounted the host filesystem.
CVE
CVE-2024-3094Case Study I — XZ Utils (CVE-2024-3094): The Two-Year Patience OperationCVE-2025-30066Case Study II — reviewdog → tj-actions (CVE-2025-30066 / CVE-2025-30154): The Automated Trust ExploitCVE-2025-30154Case Study II — reviewdog → tj-actions (CVE-2025-30066 / CVE-2025-30154): The Automated Trust Exploit
People
Threat Actors
Hans JansenNamed as a third account that applied similar pressure to the XZ Utils maintainer; the article does not establish the account's real identity.Jia TanContributor identity used in the XZ Utils compromise; the article says the operator used GitHub handle JiaT75 and presented as Jia Tan.Jigar KumarNamed as a coordinated persona that pressured the XZ Utils maintainer to merge Jia Tan's patches faster; the article does not establish the persona's real identity.
Vendors
Aqua SecurityCase Study III — Aqua Security / Trivy (March 2026): The Blockchain-Backed, Multi-Stage InfostealerCrowdStrikechain security, had its own supply chain compromised in a way that its own tooling did not detect. CrowdStrike detected the Trivy compromise through behavioral anomalies in customer pipelines, not through Aqua'sGitHubThe threat actor operated under GitHub handle JiaT75, presenting as "Jia Tan." Account created in October 2021. What followed was 30+ months of being a genuinely useful contributor. bug fixes, performance improvements,
Products
GitHub ActionsStep 4 — tj-actions/changed-files is one of the most widely used GitHub Actions in existence — it detects which files changed in a PR. It internally depends on eslint-changed-files, so it too pulled in the poison.liblzmafrom any scanner in common use. The resulting bash script injected a precompiled object file into the liblzma build stage.LiteLLMCase Study IV — litellm v1.82.8 (PyPI, March 24, 2026): The .pth Auto-Execution EscalationPyPICase Study IV — litellm v1.82.8 (PyPI, March 24, 2026): The .pth Auto-Execution Escalationreviewdog/action-setupStep 1 — reviewdog/action-setup is a utility action — it installs the reviewdog linting tool onto the CI runner. It's a building block that other reviewdog actions depend on.reviewdog/action-typosStep 2 — reviewdog/action-typos (and other reviewdog actions) call action-setup first to install the tool before doing their own work. So when action-setup was poisoned, every action that used it inherited the malicioussetup-trivyretained credentials, the attacker force-pushed 76 of 77 version tags in trivy-action and all 7 in setup-trivy to a malicious commit, while simultaneously publishing trivy v0.69.4 through the compromised releasetj-actions/changed-filesOn March 14, 2025, tj-actions/changed-files, embedded in over 23,000 repositories, was found executing a malicious Python script on CI runners. Initial reporting framed this as a single-action compromise.tj-actions/eslint-changed-filesStep 3 — tj-actions/eslint-changed-files uses reviewdog actions internally to lint changed files, so it pulled in the poisoned action-setup transitively.TrivyCase Study III — Aqua Security / Trivy (March 2026): The Blockchain-Backed, Multi-Stage Infostealertrivy-actionUsing aqua-bot's retained credentials, the attacker force-pushed 76 of 77 version tags in trivy-action and all 7 in setup-trivy to a malicious commit, while simultaneously publishing trivy v0.69.4 through theXZ UtilsCase Study I — XZ Utils (CVE-2024-3094): The Two-Year Patience Operation
Tools
pip-auditthat has no corresponding GitHub release tag or signed provenance attestation on PyPI. Tools like pip-audit combined with PyPI's provenance API can flag version-to-release mismatches. Any package version on PyPIreviewdogCase Study II — reviewdog → tj-actions (CVE-2025-30066 / CVE-2025-30154): The Automated Trust Exploit