Backdoored Telnyx PyPI releases 4.87.1 and 4.87.2 hid a credential stealer in WAV audio

TeamPCP pushed malicious telnyx 4.87.1 and 4.87.2 to PyPI on 27 March 2026. A plain import ran a stealer pulled from WAV files. How to check and clean up.

TechLogHub Engineering Team
March 27, 2026
4 min read
0 views

Share Article

Backdoored Telnyx PyPI package pushes malware hidden in WAV audio

On 27 March 2026 someone with stolen publishing credentials uploaded two malicious versions of telnyx, the official Python SDK for the Telnyx communications API, to PyPI. Running import telnyx was enough to start a credential stealer that was downloaded at runtime hidden inside WAV audio files. If either version reached a laptop, CI runner or container image, treat that environment as compromised.

What happened

According to the project's GitHub security advisory (GHSA-955r-262c-33jc), version 4.87.1 was published at 03:51 UTC and 4.87.2 at 04:07 UTC. The first upload had a casing typo (Setup() instead of setup()) that stopped the malware from running, so the attacker pushed a fixed release about 16 minutes later. PyPI quarantined both versions at 10:13 UTC, leaving an exposure window of about six hours. Neither release matched any commit in the upstream GitHub repository. The advisory says the uploads were made with stolen PyPI credentials, and Trend Micro noted that the project hadn't set up PyPI trusted publishing.

Researchers including Aikido, Socket, Endor Labs, JFrog and Trend Micro attribute the attack to TeamPCP, the group behind a string of supply-chain compromises that started with the Trivy scanner on 19 March and then hit LiteLLM on PyPI around 24 March. The attribution rests on shared artifacts: the same RSA-4096 public key, the same tpcp.tar.gz exfiltration archive name and X-Filename header, and the same OpenSSL encryption chain. SecurityWeek reported that the SDK gets more than 670,000 downloads a month.

Who is affected

  • Any environment that installed telnyx 4.87.1 or 4.87.2 between 03:51 and 10:13 UTC on 27 March 2026, including through an unpinned dependency (telnyx, telnyx>=4) in a requirements file or a Docker build.
  • Version 4.87.0 and earlier, installs that weren't upgraded during the window, and builds from GitHub source are not affected.
  • Kubernetes clusters reachable from an infected host, because the payload looks for cluster access.

What it means for developers and engineering teams

The malicious code was spliced into telnyx/_client.py in three separate pieces (a Base64 helper among the imports, a large encoded blob, and a Windows branch after the real classes) so that no single diff hunk looked obviously malicious. Everything ran at module scope, so importing the package was enough. No function call was needed.

Instead of shipping the stealer inside the package, the loader downloaded ringtone.wav (Linux/macOS) or hangup.wav (Windows) from 83.142.209.203:8080. It read the audio frames with Python's wave module, Base64-decoded them, and used the first 8 bytes as an XOR key to recover the real payload. To a network monitor that looks like an audio download, and static scanners of the package never see the stealer.

  • Linux/macOS: a detached process harvested SSH keys, AWS/GCP/Azure credentials, Kubernetes tokens, Docker configs, .env files, database credentials and crypto wallets. If it found Kubernetes access, it tried to deploy privileged pods on every node. Data was encrypted with AES-256 and RSA-4096 and posted as tpcp.tar.gz.
  • Windows: it dropped a binary as msbuild.exe in the user's Startup folder for persistence and used a hidden msbuild.exe.lock file to avoid re-running within 12 hours.

The weak points are familiar. A maintainer's long-lived upload token was the way in, and consumers who don't pin versions pull new releases automatically. CI runners are especially exposed because they install fresh dependencies on every run and often hold deploy credentials.

What to do now

  1. Find exposure: run pip show telnyx in each environment and search lockfiles and build logs, for example grep -rnE "telnyx[=@ ]+4\.87\.[12]" .. Check CI logs and container image layers built on 27 March.
  2. Remove and pin: pip uninstall telnyx, then pin telnyx==4.87.0 (or a later clean release) with hashes and install with pip install --require-hashes -r requirements.txt.
  3. Rotate everything the host could read: SSH keys, cloud and Kubernetes credentials, registry tokens, database passwords, .env secrets and Telnyx API keys.
  4. Hunt for persistence: on Linux/macOS look for an audiomon systemd user service, ~/.config/audiomon/ and /tmp/.initd_state. On Windows check the Startup folder for msbuild.exe.
  5. Check clusters: list privileged pods you didn't create, for example kubectl get pods -A -o json | jq -r '.items[] | select(any(.spec.containers[]; .securityContext.privileged==true)) | .metadata.namespace+"/"+.metadata.name'.
  6. Block and alert on egress to 83.142.209.203 and on HTTP requests carrying X-Filename: tpcp.tar.gz.
  7. If you maintain packages, switch to PyPI trusted publishing (OIDC from CI) and remove long-lived API tokens.

Related on TechLogHub

  • SDK: what you're trusting when you install one
  • CI/CD: where unpinned dependencies get pulled automatically
  • Kubernetes: why cluster credentials are a top target

Sources

Stay Updated

Get the next deep dive in your inbox

Subscribe for product analysis, engineering explainers, and practical guides published on TechLogHub.

See what launched this week

One email a week: new and trending developer tools, fresh comparisons, and what shipped. Unsubscribe in one click.

Telnyx PyPI Backdoor: WAV-Hidden Credential Stealer | Backdoored Telnyx Pypi Package Pushes Malware Hidden In Wav Audio | TechLogHub