I understand that this is meant to be an eye-popping press release (and implicitly a product spotlight), but some of these claims make me gag.
It's not an attack "on" PyPI, or even an attack at all: someone is just spamming the index with packages. There's no evidence that these packages are being downloaded by anyone at all, or that the person in question has made any serious effort to conceal their attentions (it's all stuffed in the setup script without any obfuscation, as the post says). The executable in question isn't even served through PyPI (for reasons that are unclear to me): it's downloaded by the dropper script. Ironically, serving the binary directly would probably raise fewer red flags.
Supply chain security is important; we should reserve phrases like "aggressive attack" for things that aren't script kiddie spam.
Thankfully, they're not actually being stolen because all the packages were already taken down; they're available for legitimate use again: https://pypi.org/project/colorslib/
I think it's a serious threat, especially with LLMs now because people can make believable packages at scale. Not everyone vets their packages thoroughly
Speaking of LLMs. Since LLMs like to hallucinate every now and then, an LLM could also hallucinate names of packages that it tells people to install. And those packages could in turn have been squatted by malware authors.
And in this way, malicious packages may be unintentionally downloaded by users even when those malicious packages did not yet exist when the LLM was trained. Just because the hallucinated package name was randomly later taken by someone malicious.
You've always been able to make "believable" packages at scale. PyPI doesn't enforce uniqueness: you can crank out malicious near-duplicates of any package you please.
> "While being flooded with spam is never good, it gets immediately noticed and mitigated. It's harder for open source projects to spot and stop rare one-offs"
This is the real problem that NPM and other ecosystems face. A determined attacker that is trying to "poison" a popular Open Source package just has to feign as a maintainer long enough to succeed[0].
Defeating these types of attacks will require rethinking how we think about trust of packages.
Projects like Deno are one approach (fork the ecosystem) while projects like Packj (mentioned elsewhere here), Socket.dev, and LunaTrace[1] are taking the other angle (make it harder to install malware).
It's hard to say which approach is better right away. (Probably a hybrid of both, realistically) It's just non-trivial to fix this in one clean swoop. It's messy.
We’ve built Packj [1] to detect packages with install hooks, embedded binary blobs, and other such malicious/risky packages. It performs static/dynamic/metadata analysis to look for "suspicious” attributes.
A number of academic researchers (including us) have studied malware samples from past open-source supply chain attacks and identified code/metadata attributes that make packages vulnerable to such attacks. Packj scans for several such attributes to identify insecure or "weak links" in your software supply chain (e.g., missing or incorrect GitHub repo, very high version number, use of decode+exec, etc.). Full list here: https://github.com/ossillate-inc/packj/blob/main/packj/audit...
It's relative, but I assume it's flagging for certain class of known malicious patterns. There's nothing stopping you from writing malicious python code, but essentially that script will only run while you expect it to in most cases unless it interacts with the OS in some way.
It doesn't make plain Python code you blindly execute any safer, but at least you've explicitly given those packages your trust. I believe this is more geared toward detecting compromises of those packages you have given that trust.
Wonder if that is related to the malware spamming of NPM that I saw something about last night.
Python used to have a "batteries included" philosophy which tried to put most important stuff into the distro, reducing the number of external dependencies any given app needed. They seem to have abandoned that now, leaving us to fend for ourselves against the malware.
If a payload is native it's potentially more of a problem than a script. If the payload had been c or c++, I wouldn't have been surprised if they noted that either.
We should only refer to Rust when it's included in positive events? How is it not relevant here? It was used to build executables to inject, likely for malicious purposes. Given its newness and all the other hype around it, I'd say it's very relevant.
Why not also be sure to mention what OS was used for the build, and what linker, and what file format, and what model of computer was used, and what its default ui language was set to? What is so special about programming language used that sets it apart from those other factors that could be mentioned?
I mean, not really? There’s a lot of legacy stuff written in other languages, but malware authors have realized that people are less skeptical of rust and are actively taking advantage of that fact.
It's still the same story : PyPI still doesn't have a way to automatically detect interactions with the network and the filesystems for the submitted packages. It's a complex thing to do for sure, but that would be a welcome addition, I guess.
PyPI still doesn't have this because no packaging ecosystem does. It's impossible to do in the general case if your packaging schema allows arbitrary code execution, which Python (and Ruby, and NPM, and Cargo, etc.) allow.
The closest thing is pattern/AST matching on the package's source, but trivial obfuscation defeats that. There's also no requirement that a package on PyPI is even uploaded with source (binary wheel-only packages are perfectly acceptable).
This is a little bit too strong, since packaging doesn't require arbitrary code execution. For example, Go doesn't permit arbitrary code execution during `go get`. Now - there have been bugs which permit code execution (like https://github.com/golang/go/issues/22125) but they are treated as security vulnerabilities and bugs.
This seems eminently solvable though. Why can’t every package submission cause some minimal sandboxed docker image to install the package and call the various functions and methods and log all network and disk activity? If anything looks suspicious it would be denied and the submitter would have to appeal it, explaining why the submission is valid. The same applies for NPM and Cargo. I know there is a researcher out there who has retrieved and installed every single pip package to do an analysis, which is a good start. This seems like the kind of thing that wouldn’t even cost all that much, and big corporate users of python would stand to benefit.
yes, SecurityManager was a poor implementation for many reasons, but it's definitely not "impossible" to sandbox downloaded code from the network while having it interact with other existing code, you can do it with typing alone
I'm not sure it's not do-able, actually. What about having an execution sandbox and a way to check the calls made during the execution of the install script for instance?
I worked a few years back on something like this but it went nowhere, but I still believe it would be doable and useful. The only trace I found back is https://wiki.python.org/moin/Testing%20Infrastructure, which contains almost no info...
Smart attackers are already/will add `sleep(SOME_NUMBER_LONGER_THAN_SCAN_SANDBOX_LIFETIME)` before anything that does FS or network access. Not to say that this wouldn't be a welcome addition, but the scanning needs to be understood in the context of the inherent limitations of large scale runtime behavior detection of packages when you have a fixed amount of hardware and time for running those scans.
Namespacing is not a security boundary: it's a usability feature that helps users visually distinguish between packages that share the same name but different owners. I don't think it would meaningfully affect things like package index spam, which this is.
(This is not a reason not to add namespacing; just an observation that it's mostly irrelevant to contexts like this.)
It can be if you implement it to be so. Just let people create an allowlist of approved vendors for their organization or project from those namespaces. This handles not having to approve individual packages from trusted entities like Google, Microsoft, etc. Update the list when new vendors are needed. Reuse elsewhere as necessary.
Maybe the list can be hosted on an internal server for other employees to reuse. Hosting all the packages internally is overkill. Trusting the world by default is overkill.
Now "pip install gooogle/package"
"Hey User, gooogle/package is not from a trusted namespace. Did you mean google/package which is similar and trusted? Or would you like to add gooogle to your local trust file?"
The lack of any kind of curated feeds that only lists verified or popular packges is tragedy. There should be a reasonable way of allowing clients to protect themselves from a typo.
It's not an attack "on" PyPI, or even an attack at all: someone is just spamming the index with packages. There's no evidence that these packages are being downloaded by anyone at all, or that the person in question has made any serious effort to conceal their attentions (it's all stuffed in the setup script without any obfuscation, as the post says). The executable in question isn't even served through PyPI (for reasons that are unclear to me): it's downloaded by the dropper script. Ironically, serving the binary directly would probably raise fewer red flags.
Supply chain security is important; we should reserve phrases like "aggressive attack" for things that aren't script kiddie spam.
Lol, maybe, "chatgpt, give me a thousand feasible pypi package names"?
And in this way, malicious packages may be unintentionally downloaded by users even when those malicious packages did not yet exist when the LLM was trained. Just because the hallucinated package name was randomly later taken by someone malicious.
I wrote a comment on the NPM thread earlier (https://news.ycombinator.com/threads?id=freeqaz) that I'll quote here:
> "While being flooded with spam is never good, it gets immediately noticed and mitigated. It's harder for open source projects to spot and stop rare one-offs"
This is the real problem that NPM and other ecosystems face. A determined attacker that is trying to "poison" a popular Open Source package just has to feign as a maintainer long enough to succeed[0]. Defeating these types of attacks will require rethinking how we think about trust of packages.
Projects like Deno are one approach (fork the ecosystem) while projects like Packj (mentioned elsewhere here), Socket.dev, and LunaTrace[1] are taking the other angle (make it harder to install malware).
It's hard to say which approach is better right away. (Probably a hybrid of both, realistically) It's just non-trivial to fix this in one clean swoop. It's messy.
0: https://www.trendmicro.com/vinfo/us/security/news/cybercrime...
1: https://github.com/lunasec-io/lunasec
There's something beautiful in knowing you're using pure, clean Python. Much easier to install, also.
Deleted Comment
Attacking a popular repository like this does not have to have a high hit rate.
"Script kiddie spam" is now computers get compromised. Unsophisticated mass attack.
This sport of thing, combined with woeful security and fragile systems are causing havoc the world over.
Deleted Comment
1. https://github.com/ossillate-inc/packj
It doesn't make plain Python code you blindly execute any safer, but at least you've explicitly given those packages your trust. I believe this is more geared toward detecting compromises of those packages you have given that trust.
Deleted Comment
Python used to have a "batteries included" philosophy which tried to put most important stuff into the distro, reducing the number of external dependencies any given app needed. They seem to have abandoned that now, leaving us to fend for ourselves against the malware.
NPM spam: https://www.scmagazine.com/analysis/devops/npm-repository-15...
Yes, along with reducing the stdlib and directing us to PyPI for "alternatives".
The closest thing is pattern/AST matching on the package's source, but trivial obfuscation defeats that. There's also no requirement that a package on PyPI is even uploaded with source (binary wheel-only packages are perfectly acceptable).
This is a little bit too strong, since packaging doesn't require arbitrary code execution. For example, Go doesn't permit arbitrary code execution during `go get`. Now - there have been bugs which permit code execution (like https://github.com/golang/go/issues/22125) but they are treated as security vulnerabilities and bugs.
Of course, you're right about Python.
Java's type system: ClassLoaders plus SecurityManager was impossible?
that's literally how Java applets worked, enforced through the type system
https://docstore.mik.ua/orelly/java-ent/security/ch03_01.htm
yes, SecurityManager was a poor implementation for many reasons, but it's definitely not "impossible" to sandbox downloaded code from the network while having it interact with other existing code, you can do it with typing alone
I worked a few years back on something like this but it went nowhere, but I still believe it would be doable and useful. The only trace I found back is https://wiki.python.org/moin/Testing%20Infrastructure, which contains almost no info...
Maven sorted this out 20 years ago
what's a bit sad is the python packaging's authority survey from a few months ago seemed to be mostly interested in vision and mission statements
rather that building a functional set of tools
(This is not a reason not to add namespacing; just an observation that it's mostly irrelevant to contexts like this.)
example: the package named "aws" on pypi was created by some random guy and has been abandoned for years
if pypi/pip supported namespacing that would be info.randomdude.aws instead
and amazon's packages would be under com.amazon
not being able to namespace internal packages is another security issue that is substantially improved with proper namespacing
to be blunt: not supporting it at this point is reckless and irresponsible
(I note you're part of pypa!)
Maybe the list can be hosted on an internal server for other employees to reuse. Hosting all the packages internally is overkill. Trusting the world by default is overkill.
Now "pip install gooogle/package"
"Hey User, gooogle/package is not from a trusted namespace. Did you mean google/package which is similar and trusted? Or would you like to add gooogle to your local trust file?"
The lack of any kind of curated feeds that only lists verified or popular packges is tragedy. There should be a reasonable way of allowing clients to protect themselves from a typo.
Good namespacing (e.g. in Go), in practice, provides critical context about the development/publication of a software package.
But deliver anything more streamlined and secure? Hell, no!
https://blog.hubspot.com/website/data-mining