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.
Top comments (0)