How to protect your organization from the telnyx PyPI compromise
Today, malicious versions of telnyx, the official Python SDK for Telnyx's carrier-grade communications platform, were published to PyPI. Telnyx is downloaded roughly 790,000 times each month.
Versions 4.87.1 and 4.87.2 contain malicious code injected into telnyx/_client.py. These versions were published to PyPI without corresponding source code on GitHub, indicating the PyPI publishing credentials were compromised. The last known clean version is 4.87.0, which was published just yesterday (March 26).
Like the Trivy, Checkmarx, and LiteLLM breaches earlier this month, Chainguard customers are not impacted by this telnyx attack. The compromised library versions had no publicly verifiable source code, so Chainguard never built them. In turn, they never existed in the Chainguard Repository.
What the malware does
The attack is technically sophisticated and deliberately deceptive.
Both malicious functions are called at module scope, meaning the payload executes the moment you run import telnyx. This happens before any application logic runs.There is no install hook to disable and no postinstall script to block.
The payload delivery mechanism deserves close attention. The malware downloads hangup.wav from a remote C2 server. On Windows, a native binary is extracted from the WAV file, leading to persistence across reboots. On Linux and macOS, the code extracts a credential harvester from the WAV file, just as we saw in the Trivy and LiteLLM attacks. Disguising the payload in an audio file format that matches the specifics of the attacked package demonstrates a new level of attacker craft.
Immediate steps if you are affected
If you installed telnyx==4.87.1 or telnyx==4.87.2:
Uninstall immediately and pin to
telnyx==4.87.0Treat the environment as fully compromised. You should rotate all credentials, API keys, SSH keys, and any secrets accessible from that machine
Check for persistence: on Windows, look for
msbuild.exein%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\
These are the same attackers who breached Trivy
This attack is attributed to TeamPCP with high confidence. Here’s what we know:
The attackers used an identical RSA-4096 public key matching the
litellmPyPI compromise from earlier this weekThe
tpcp.tar.gzarchive name andX-Filename: tpcp.tar.gzmatch the TeamPCP signatureThe attack uses the same AES-256-CBC + RSA OAEP encryption scheme via OpenSSL CLI
In short, this attack is part of a well-coordinated campaign. The pattern holds across every compromise: steal credentials from trusted open source security tools via malicious GitHub Actions, use those credentials to push malicious dependency versions of whatever that tool had access to, collect whatever is running in the next environment, and repeat.
The timeline
March 19: Trivy container and GitHub Actions compromised. TeamPCP backdoored Aqua Security's open source vulnerability scanner, Trivy. For several days, the attackers exfiltrated credentials from every CI/CD pipeline running Trivy-specific versions of a Trivy container and from nearly all versions of Trivy’s GitHub Actions, trivy-action and setup-trivy, that were not pinned to SHA commits.
March 20: CanisterWorm spreads and impacts 140+ npm packages. Team PCP planted a persistent backdoor and used stolen npm tokens to autonomously discover every package the victim account could publish to, increment the patch version, and republish. Major namespaces such as @EmilGroup and @OpenGov had malicious versions that lacked accompanying source code distributed via npm.
March 23: Checkmarx GitHub Actions compromised. TeamPCP uploaded malicious versions of ast-github-action and kics-github-action, and anyone who used those actions had their credentials stolen.
March 24: LiteLLM compromised (97M+ monthly downloads). TeamPCP published backdoored versions 1.82.7 and 1.82.8 of LiteLLM to PyPI. The attackers gained access to the maintainer’s PyPI account by exploiting stolen access tokens after LiteLLM used an unpinned version of Trivy.
March 27 (today): Telnyx compromised.
Open source’s blast radius problem
Open source's interconnectedness is both its greatest feature and its greatest weakness. The above timeline shows that, despite the attack starting with Trivy, you did not need to use Trivy to be impacted now. All you needed was something that used Trivy, or use something that used something that uses Trivy.
Open source software is a web of dependencies that continues to build on each other. The average JavaScript library has 30 dependencies. For Python, the figure is 4. And that’s just the average; some essential dependencies can have more than 100 transitive dependencies.
When a package gets compromised, it can impact thousands of developers. In turn, attackers gain access to a new set of credentials to use for the next attack, widening the blast radius. Those credentials open new attack surfaces, and the next target is determined by whatever doors those credentials unlock. There’s no trackable logic to follow, and it’s impossible to defend against reactively.
Telnyx is a communications SDK. It has no surface-level relationship to a vulnerability scanner. Yet, days later, it’s attacked.
Why Chainguard customers were protected
Chainguard Libraries are built from publicly verifiable source code. This single architectural decision is what kept (and continues to keep) customers protected across every stage of this campaign.
Research shows that 98%+ of malware has no publicly verifiable source code. It gets shared on public registries as pre-packaged malicious binaries with no matching source. In every library incident in this campaign, the GitHub repository remained clean. The telnyx GitHub source showed no signs of compromise. Same with LiteLLM. The malware is injected in a pre-packaged binary that lives only on PyPI, not in the source.
Because Chainguard builds Containers and Libraries exclusively from source, the compromised versions of LiteLLM and Telnyx were never built. For Trivy, every Action that Chainguard builds is hardened against a security best-practice ruleset. The CI/CD workflows Chainguard publishes to the Chainguard Repository are immune from tag hijacking, secret exfiltration via logs, and pull_request_tag abuse by default.
As a result, Chainguard customers do not have to rotate credentials, audit their log files, or perform any incident response or triage. They’re just safe.
As a response to this continuing wave of TeamPCP attacks, we are making our Trivy image free for 12 months, and Chainguard Libraries and Actions free for three months.
Join us on a live webinar to go deeper
If you want to understand how this campaign unfolded and how you can improve your secure posture, join Chainguard CEO Dan Lorenc and VP of Product Reid Tatoris for a live webinar on Thursday, April 2.
Share this article
Articles connexes
- security
You were one pip install away from the litellm breach. Chainguard customers weren’t.
Ross Gordon, Staff Product Marketing Manager, and Bria Giordano, Director, Product Management
- security
Secure-by-default: Chainguard customers unaffected by the Trivy supply chain attack
Reid Tatoris, VP of Product
- security
Going deep: Upstream distros and hidden CVEs
Chainguard Research
- security
Chainguard + Second Front: A faster, more secure path into government markets
Ben Prouty, Principal Partner Sales Manager, Chainguard, and Veronica Lusetti, Senior Manager of Partnerships, Second Front
- security
This Shit is Hard: The life and death of a CVE in the Chainguard Factory
Patrick Smyth, Principal Developer Relations Enginee
- security
npm’s update to harden their supply chain, and points to consider
Adam La Morre, Senior Solutions Engineer