Telnyx Python SDK Compromised on PyPI: TeamPCP Hides AES-256 Infostealer in WAV Audio Frames
Commissioned, Curated and Published by Russ. Researched and written with AI.
What’s New
Published 27 March 2026 – the Telnyx package has been pulled from PyPI; investigation ongoing.
Changelog
| Date | Summary |
|---|---|
| 27 Mar 2026 | Initial publication. |
At 03:51 UTC this morning, two malicious versions of the official Telnyx Python SDK appeared on PyPI. The package has 742,000 downloads per month. This is the latest step in a campaign that has now compromised Trivy, CanisterWorm-infected 46+ npm packages, hit Checkmarx GitHub Actions, and backdoored LiteLLM – all within the past eight days.
The Telnyx compromise adds something new: the payload is hidden inside WAV audio files. Not encoded alongside them, not attached to them – inside the frame data of what is technically a valid audio file.
This is worth understanding properly.
The Attack Chain
If you haven’t read the retrospective on TeamPCP’s campaign, start there. The short version: TeamPCP compromised Trivy (Aqua Security’s open-source vulnerability scanner) on March 19, extracted credentials from every CI/CD pipeline running it without version pinning, and has been using those stolen tokens as a key to unlock each subsequent target.
The chain so far, according to Aikido Security’s analysis:
- March 19: Trivy compromised (CVE-2026-33634, CVSS 9.4). Credentials exfiltrated from CI pipelines.
- March 20: CanisterWorm hits npm. Using stolen tokens, TeamPCP published backdoors across 46+ npm packages. The worm automated token-to-compromise in under 60 seconds.
- March 22: WAV steganography first observed in a Kubernetes wiper variant.
- March 23: Checkmarx GitHub Actions and OpenVSX extensions compromised.
- March 24: LiteLLM versions 1.82.7 and 1.82.8 backdoored. LiteLLM serves roughly 95 million downloads per month and is deployed as an LLM gateway with access to credentials for OpenAI, Anthropic, AWS Bedrock, GCP VertexAI, and more.
- March 27 (today): Telnyx Python SDK. Versions 4.87.1 and 4.87.2.
The pattern is consistent: steal credentials from a trusted tool, use those to push malicious versions of whatever that tool had access to, collect credentials from the next environment, repeat. The attack surface at each step is the trust inherited from the previous compromised system.
What the Telnyx Payload Actually Does
The injection is in telnyx/_client.py. This file runs at import time. You don’t need to call any function or trigger any install hook – import telnyx is enough. There’s nothing to disable at the postinstall level.
The payload branches on OS.
Windows: Downloads hangup.wav from 83[.]142[.]209[.]203:8080. Decodes an XOR-obfuscated executable from the audio frames. Drops it as msbuild.exe in the Windows Startup folder. Runs silently on every login. A hidden .lock file enforces a 12-hour re-drop cooldown.
Linux and Mac: A complete second-stage Python script is hardcoded as a base64 blob at line 459 of _client.py. It fetches ringtone.wav from the same C2, decodes a third-stage collector script from the WAV frames using the same XOR technique, runs it via sys.executable piped to stdin, then encrypts the collected output with AES-256-CBC. The session key is wrapped with an attacker RSA-4096 public key using OAEP. Only the attacker can decrypt what was stolen.
The exfil bundle is named tpcp.tar.gz and sent with the header X-Filename: tpcp.tar.gz. That naming is either brazen or an oversight. Either way, it’s a useful detection signal.
The WAV Trick and Why It Works
Most supply chain payloads get hidden somewhere predictable: setup.py, __init__.py, a postinstall hook. Security tooling has gotten reasonably good at flagging those. TeamPCP is doing something different.
The malicious payload isn’t delivered as a binary or a Python file. It’s delivered as a .wav audio file. Here’s the decode logic, as observed by Aikido Security’s researchers:
with wave.open(wf, 'rb') as w:
b = base64.b64decode(w.readframes(w.getnframes()))
s, m = b[:8], b[8:]
payload = bytes([m[i] ^ s[i % len(s)] for i in range(len(m))])
The WAV file is structurally valid audio. It passes MIME-type checks. A policy allowing .wav fetches won’t block it. Content-based filtering that looks at file type won’t catch it. The malicious content is inside the audio frame data – base64-encoded, then XOR-obfuscated with the first 8 bytes as the key.
This bypasses a class of defences that check what kind of file is being fetched rather than what the file contains. Security tools that watch for executable downloads, Python script downloads, or suspicious MIME types won’t fire. The file looks like audio because it is structured as audio.
TeamPCP first used this technique in a Kubernetes wiper payload on March 22. Five days later it’s in a PyPI package reaching 742,000 downloads per month. They liked it enough to operationalise it quickly.
The technique is not new in the abstract – steganography has existed for decades – but deploying it in an active supply chain campaign against PyPI packages is a meaningful escalation. It suggests TeamPCP is actively iterating their evasion approach, testing techniques in lower-visibility contexts before deploying them at scale.
What Each Stage Is Actually After
The Linux and Mac infostealer runs as a third-stage Python script decoded from the WAV frames. The AES-256-CBC encryption with RSA-4096 OAEP key wrapping means the exfil content is completely opaque to anyone intercepting the traffic. Only the attacker’s private key can recover what was taken.
Given that TeamPCP’s consistent pattern across this campaign has been credential collection – API keys, CI/CD tokens, cloud provider credentials – the safe assumption is that the collector is after whatever secrets are accessible from the environment where telnyx is installed. That could be Telnyx API keys, but if you’re running this in a CI pipeline or a production service alongside other credentials, the blast radius is larger.
IOCs and Immediate Actions
Malicious versions:
telnyx==4.87.1(SHA256:7321caa303fe96ded0492c747d2f353c4f7d17185656fe292ab0a59e2bd0b8d9)telnyx==4.87.2(SHA256:cd08115806662469bbedec4b03f8427b97c8a4b3bc1442dc18b72b4e19395fe3)
Network indicators:
- C2:
83[.]142[.]209[.]203:8080 - Windows payload:
hxxp://83[.]142[.]209[.]203:8080/hangup.wav - Linux payload:
hxxp://83[.]142[.]209[.]203:8080/ringtone.wav - Exfil endpoint:
hxxp://83[.]142[.]209[.]203:8080/ - Exfil header:
X-Filename: tpcp.tar.gz
Windows persistence:
%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\msbuild.exe%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\msbuild.exe.lock
If you’re running telnyx anywhere: pin to telnyx==4.87.0 immediately. If you installed either malicious version, treat the environment as compromised. Rotate API keys, database credentials, SSH keys, and any secrets accessible from that machine. On Windows, check the Startup folder and remove msbuild.exe if present. Monitor outbound HTTP to 83[.]142[.]209[.]203:8080.
The Bigger Picture
What TeamPCP has built over the past eight days is a credential-harvesting chain that uses each compromised tool as a delivery mechanism for the next attack. Trivy’s trusted position in CI/CD pipelines was the entry point. Everything since has been riding downstream trust.
The WAV steganography technique is a sign that they’re actively improving their evasion as they go. A campaign that started with a straight Trivy backdoor is now using audio file obfuscation to deliver its final stage. That’s iteration based on feedback – either from detection rates or from deliberate testing.
The teams most exposed are those running telnyx in environments where it co-exists with other sensitive credentials. If your Python environment for voice or telephony work also has access to database connection strings, cloud provider keys, or CI/CD tokens, assume all of that is now in scope.
The campaign is still developing. Stay pinned. Version pinning across your entire dependency tree – not just direct dependencies – is the only reliable control here.