The malicious package that never showed up in anyone's requirements.txt

Two PyPI packages published this week show why checking your direct dependencies is not enough. The credential-stealing code was one dependency away, in a package nobody typed into a requirements file on purpose.

supply chainPyPIcase studytransitive dependencies

On 3 September 2026, GitHub's Advisory Database published two malware reports for PyPI packages, credited to OpenSSF's malicious-packages tracking effort. Read separately, they look like routine entries in a database that logs thousands of these a year. Read together, they describe a specific trick worth understanding, because it defeats the most common way developers check a package before installing it: looking at the name in their own requirements file.

The two packages

telemetry-helper is the one that actually steals data. According to the advisory, importing it starts a background thread that waits 30 seconds, then sends the hostname, username, working directory and the complete environment variable set to a webhook endpoint. Environment variables are exactly where AWS keys, GitHub tokens and database credentials tend to live, so "complete environment variables" is not a small claim.

env-validator-tool does not steal anything itself. Its advisory says its malicious functionality "is intentionally included in a dependency of the package" — it exists to pull telemetry-helper in as a dependency. GitHub groups both advisories under the same campaign label, 2026-09-telemetry-helper.

Neither name is dramatic. Both fit the pattern of a hundred legitimate internal utilities: a config validator, a telemetry shim. That is very likely the point. A package called steal-your-aws-keys gets noticed. A package called env-validator-tool gets installed.

Why "check your dependencies" isn't precise enough

If you install env-validator-tool, your requirements file says env-validator-tool. It does not say telemetry-helper. That name only appears in the resolved dependency tree — the full set of packages pip actually pulls down, including whatever your direct dependencies decided to depend on themselves.

Most manual review stops at the file a person edited. Nobody sits down and reads the resolved tree line by line, because for any project with more than a handful of dependencies it runs to hundreds of entries, most of them unfamiliar on sight. That gap — between what you chose and what you actually run — is exactly where this campaign sits.

This is a different failure mode from the slopsquatting case we've written about before, where an AI assistant invents a name that does not exist and an attacker registers it. Here both names are real, both were published to PyPI, and the one doing damage was never typed by a human at all. It arrived as someone else's choice.

The check that would have caught it

You do not need to install a package to see what it depends on. PyPI's JSON API exposes the declared dependencies of any release under requires_dist, before you run pip install on anything:

curl -s https://pypi.org/pypi/PACKAGE_NAME/json | python3 -c \
  "import json,sys; print(json.load(sys.stdin)['info']['requires_dist'])"

Run it against a real package and you get a real answer. For requests right now:

['charset_normalizer<4,>=2', 'idna<4,>=2.5', 'urllib3<3,>=1.26', 'certifi>=2023.5.7', ...]

Four names you did not type, all pulled in on your behalf. That is normal — requests has been depending on those libraries for years, and they have their own long histories. The difference with env-validator-tool is that running the same command against it, before installing, would have surfaced telemetry-helper in the list: one more name to check, and a check that would have failed, because telemetry-helper was published with no history behind it either.

At the time of writing, both names return 404 from PyPI — pulled after the advisory. That is the system working as intended, but it also marks the edge of what a point-in-time check can do. A scan run today finds nothing, because the packages are gone. A scan run in the window between publication and takedown is the only one that would have mattered, which is the same argument for running this at every pull request rather than occasionally: the check is only useful while the threat is still live, and you do not get to choose when that window is.

What this doesn't tell you

We don't know how many projects installed either package, or whether the campaign succeeded anywhere — GitHub's advisory doesn't say, and we have not found a source that does. We also don't know whether env-validator-tool was hand-picked to sound trustworthy or just happened to. Both are reasonable guesses, neither is a fact we can point to.

What the advisory does establish, plainly, is the mechanism: a package with no history depending on a second package with no history, and the dependency relationship being the only place that second name appears. Checking the packages you named and skipping the ones your dependencies named for you leaves exactly that gap open.

Check this on your own pull requests

MagSolutionsAI is a GitHub App that verifies every dependency in every pull request against the live PyPI and npm registries, and blocks the ones that do not exist. Free for public repositories, forever — no card, no CI config.