I bet there have been a hundred different discussions about this inside of NPM since it was disclosed 10 years ago. With Shai Halud it's gotten too big to ignore.
I do love that javascript's history is basically just coder mentality distilled. "oh yeah we'll fix that shortly" is almost always "oh fuck now we have to"
Are the current LTS node versions (iirc 22, 24, 26) going to update the bundled npm to v12 to benefit from these security fixes? All come with npm v11 now
They are changes in defaults, which could be construed as a security posture change, but the security fix is in everyone's hands. Just set proper defaults, as per article, and done.
I think the best part of this change, is that the default change will mean that lots of new DEVs just running an install, will see instant breakage with annoying packages that presume these settings are on. It should force people to stop expecting scripts to be runnable, for example.
I wonder if there are still reasons to use yarn? Has yarn also implemented safeguards to protect against supply chain attacks? Until now, I only knew about pnpm. It’s great that npm has followed up.
It is not obvious from the post but it seems like the allow list for the scripts supports whitelisting packages instead of a global setting. This should make it easier to maintain org-wise rules to allow scripts only for specific packages.
Is there a linter that could be used for scenarios like this to prevent unsafe default on package manager config?
> Microsoft doesn’t do everything right but the GitHub acquisition has honestly gone better than I ever expected. Rather than forcing GitHub to adopt Microsoft centric policies, Microsoft has adopted more GitHub stuff, especially from a product POV. GitHub still runs as a separate company (different logins and health care and hiring systems) with its own policies and point of view.
GitHub didn’t embrace, extend, extinguish git. You can git push to a different company (e.g. Gitlab) and you’ve migrated. The biggest problems with GitHub are scaling and availability, not lock-in.
Microsoft today is nothing like it was 30 or 20 years ago.
Fifteen years ago we were writing HTML and JavaScript specifically for Internet Explorer. Edge is built on Chromium.
Good luck migrating the ”forge” part with the ”git” part. Your github org settings, pull requests, rulesets, CI/CD pipelines, containers, copilot...
The lock-in always comes from the ”forge” part, never the ”git” part.
Old folks are also aware that applies to every single big tech company that actually sponsors the FOSS tools many don't want to pay anything back, while expecting to be paid themselves.
Old folks also remember the days when it was possible to make a living out of selling software tools.
MSFT acquisition of NPM was a massive shit show, they fired many staff engineers and people that were at github for quite a while. Top comment was a liar.
I was part of the npm team at GitHub. They laid off almost the entire team to focus on AI (CTO literally told us on the layoff announcement call that they're doing this to focus on Copilot)
Would you rather the company went under after it ran out of money and had to fire everyone instead? Not to mention a quarter of the company was laid off the year before the acquisition.
Uhh, I'd expect the trillion dollar transnational corporation to do right by it's workers rather than rat fucking them to appease corporate do-nothing leeches if I'm being frank.
With smaller companies that can't yield global power. It would be better if cloud, office and OS would be separate. Then you wouldn't get shuffed OneDrive into the OS. It's also better for competition if the playing field is equal and one solution isn't the only one that can deeply integrate. Build APIs or don't do it.
NPM (the company) was about to go under in 2020. They raised VC but never found a sustainable business model. GitHub acquired them to keep the ecosystem alive. The acquisition hasn't really benefitted GitHub much at all.
I don’t know if this is the case here, but it’s very hard in general to judge how much software projects ought to cost.
Software projects will grow in complexity to consume whatever budget you give it. If you hire 50 devs and give them a bunch of business objectives, they are going to do what they do and write a ton of software.
It’s not obvious to me that it would be theoretically impossible to build a cheaper package manager.
Yeah, but the azure supply chain attack explains why all of a sudden they can make this change.
It seems that if you want to get something important changed in npm, you simply need exploit some of its short comings against Microsoft instead of discussing why it’s necessary.
native modules. nodejs can have native modules (written in C++, Rust, etc...). Projects usually ship prebuilt natives binaries (for each arch/OS/Nodejs ABI combination) hosted on GitHub Releases and download them automatically at installation time; fallback to build from source if not found. that's where scripts are used
the reason for not bundling all native binaries is becasue the no. of combinations are huge and it can make module size hundreds of MBs
Off the top of my head the purposes I've seen for them:
- building native bindings (node-sass)
- asking for funding (core-js)
... Probably a few more but the native case is probably the biggest and the packages I'm using nowadays ship precompiled blobs in optionalDependencies. Install scripts seem to be out of favor.
My big question as an OSS dev distributing some precompiled binaries via npm for easy installation: does allowScripts also default to disabled when directly installing a package (globally or otherwise)?
> So for that entire class of packages this change makes them safe.
This is misleading. The change addresses one important attack vector. But if one runs the application directly on the host for development, if the package is imported like pointed out in the other comments or the package intends to steal user credentials from production, it is far from "being safe". Safer, but still needs scrutiny.
Don't forget about tests. That'll run code for every package that is imported. Yes, imported, because in JS importing means "run all the top level code in this file". So to continue exploiting you just place your malicious code in index.js instead of a postinstall script. Not as guaranteed to run but still very likely.
Build deps are even disregarded as less critical than runtime deps traditionally. So deps like sphynx for building docs are still a dev side supply chain vector.
The reason this may be overlooked is because build deps are only ran by the devs, but not the users, so users dismiss it as safe. However, if a build dep is infected, the infection may spread to the actual package code, which will then of course be run by the user.
Not theoretical, Microsoft is currently under attack by a worm that spreads through vs code extensions, which then spread to actual packages that users run.
Docs suggest just using a script tag instead of npm, when using npm install, they suggest to run import statement, which can execute arbitrary code.
The bottom line seems to be that if you are using npm, it's cause you are using node, and therefore you will run the imported code in the server, otherwise you would use a script tag.
But maybe there's a way to define a browser only package or .js URL such that it is only downloaded and served but never executed server side?
In any case, not a huge usecase of npm, which again, is designed for node which is backend.
Yes, but that's actually a huge win. I can't know what a package needs to do at install time - the dev knows that. But I know what my tests and program need to do at runtime because it's my job to understand those things.
The dev has to be responsible for ensuring that their build scripts are safe, I need to be responsible for ensuring that my runtime is safe.
It'd be great to have more tools for untrusting libraries (iframes are awesome for this on the frontend) but this is still a massive win.
We already have alternative and superior proposals, it's called Deno.
It's node + npm compatible and its permission system locks everything down by default.
If you know ahead of time, you can turn on which permissions something is supposed to have in the config file.
Or you can just not use a config file at all. Anytime it needs a permission: it asks you what it wants. You can say yes or no, and those are saved in the config file for next time. If you say no, the script throws an error where it tried to access something it didn't have permission for.
---
Example:
- My linter wants access to my file system?
- You can have read access to ./src/ts/
- My bundler wants read and write access to my file system?
- You can have read access to ./src/ts and write access to ./build-output
- Huh, what's that? The bundler was trying to both read and write a file in ./src/ts?
- We don't want input files getting overwritten, that's a recipe for hard-to-diagnose race conditions. Looks like the permission system did more than just keep things secure, it's like a type system for IO.
- Oh, look at that, there was a very subtle bundler misconfig, let me fix that now. How long would that have existed if we didn't use deno...
- Oh what's this? An updated dependency I've been using for 6 months suddenly asking for access to my .env file, and asking to run curl in a separate process? How about "no". Why would a simple DOM utility dependency be asking for those permissions? Ah, looks like it was part of a credential stealing supply chain attack. Glad I wasn't using node.
---
Addendum: Node now has a permission system, but it's broken by design so it's useless.
You'll notice that my comment was a question, you can tell by the presence of question marks at the end of the sentence.
Additionally, if a comment were to hypothetically point out an issue, that is valuable on its own. If someone reacts to a comment that points out an issue this defensively, it's a huge red flag.
As if supply chain attacks could have been prevented by 2fa or passkeys always.
You want delays by x days because supply chain attacks get caught very often within 1-2 days. And if you really really want to make an exception for a zero day then that's no problem and you can still quick patch by exclusion of that rule. They don't contradict in a unsolvable problem. You want both, you get both.
While I think this may be true, what validation do you have on this point?
Have you rolled the numbers, vs all of the high-pri security updates that will be missed on day one, and exploited?
What is really needed is simply more nuance. I agree the delay can help, but honestly the entire ecosystem is broken. There shouldn't be a single thing installed, without someone having an eyes-on. That's how this is fixed.
Distros aren't perfect, but they handle this a load better. And this really runs to the problem, people want "new new new", yet often have very little real reason to want it. 99% of npm packages could be 5 years old, and no one would care.
But outside of that, npm could operate like a distro, but with more of a Debian unstable -> testing method, where it typically takes a few days for this migration to happen.
My point is, the fix isn't publishing by default, then hoping to catch. The fix is that nothing gets published, without a QA/validation step. Of course, that takes money. There is naturally, a super easy fix for that.
The code stays open source. The licensing stays <insert whatever by author>. However?
The ToS for using any or all of the npm architecture is if you're a company, you pay. If you neglect to pay, eg you don't register as a corporate entity, set up and account, and pay per use, then as per ToS the licensing is invalid, and you're fined via a copyright infringement. And yes, this would mean all npm packages would have an altered licensing model, basically with this tacked on.
Is what I'm saying perfect? Nope. Yet it's the general path which should be taken. And frankly, with the way things are going, this level of audit would allow for staff also categorize licenses, ensure accurate template files, and so on.
And some of this is the perfect use of an LLM. Not to do the work, but to flag with human review.
--
This ecosystem is done. Its model is broken. The concept of downloading random stuff without auditing in any way, is broken. The industry will be moving away, is starting to move away, and is having to move away.
So... how can this survive with that concept?
If one doesn't like my proposal above, then they should provide an alterative which allows:
* companies to have validate of licensing
* audits which validate change is not untoward
The maintainer of pnpm mentioned this on the pod rocket podcast recently. Based on recent npm exploits they decided to (and based on a poll they did most users agreed) set to 1 day by default in v11. Can always choose to change it if you desire.
It's unstated, but I'm willing to assume that only the root package.json is consulted to decide if these scripts are allowed. Otherwise, yes, this would not actually change anything.
The changelog design has been like that since last year,[0] which predates today's slop design of small caps and monospace text (probably because they both are based on the same design trend). A year ago, vibe coded websites leaned more on sans serif and gradient text.
If you force every user to just use "--enable-unsecure-feature", guess what will happen?
This is not about improving security. This is about shifting blame.
A much better alternative would've been the introduction of sandboxes or simulation runs that would output which scripts and programs are running due to unpredictable dependencies. This way the user could check before the actual execution, and maintain an allow list much easier. That could be done via an npm update && npm upgrade workflow where the update generates the list that the user has to manually confirm.
Heck, even a chroot would be an improvement, and they're almost pointless these days, considering how good malware got at escaping chroots.
I don't think it's pointless. A large number (the majority?) of users probably don't need install scripts, so disabling them by default is a net security improvement. Those that do can enable the insecure behavior, which will become an explicit decision that is trackable, auditable, etc.
You're not wrong about sandboxing, but sandboxing isn't something that can just be blithely introduced to a large packaging ecosystem that previously assumed full system access. Doing so results in the same kind of regression you point out: if the sandboxing breaks peoples' builds, they'll just disable it and move on with their goals.
Most users don't need it. Having it on by default is a feature for malware writers not users.
But to your point, Node has had permission flags for a while[0] but allows everything by default. Npm could use them to increase security even more. I just hope it doesn't take them another 10 years to change the default.
Most packages don’t need it, but I imagine a large percentage of users do since most projects pull in an insane number of packages.
Still, “default off” is better. It would be nice if there were a lightweight way to fork upstream packages, and cache the native builds. It’d improve build times, make the build step more explicit / sandboxable and allow for easier binary builds for operating systems and processors that M$ treats as second class.
There's an easy way to stop most supply chain attacks:
1. Publishing users must approve each and every release from a smartphone app.
2. Publishing users must provide verified government ID.
The first step prevents the types of attacks where an attacker gets control of a maintainer's computer and publishes a new release.
The second step discourages attacks where a user tries to get a malicious package used by others.
When combined with the security features that already exist, e.g. delays and automatic scanning, it would make it considerably harder to pull off a successful attack.
Issue is this is such a pain (and shuts out a large percentage of the world population) that you'll inevitably get a parallel ecosystem of packages without these onerous controls that everyone would end up using.
I don't know how to square the circle but any variation of "make it safer but really painful and difficult for anyone to publish a package" has this problem
[1]: https://nodejs.org/en/blog/release/v18.19.0#npm-updated-to-v... [2]: https://nodejs.org/en/blog/release/v20.10.0
I think the best part of this change, is that the default change will mean that lots of new DEVs just running an install, will see instant breakage with annoying packages that presume these settings are on. It should force people to stop expecting scripts to be runnable, for example.
Is there a linter that could be used for scenarios like this to prevent unsafe default on package manager config?
Some of it aged... interesting.
Top comment:
> Microsoft doesn’t do everything right but the GitHub acquisition has honestly gone better than I ever expected. Rather than forcing GitHub to adopt Microsoft centric policies, Microsoft has adopted more GitHub stuff, especially from a product POV. GitHub still runs as a separate company (different logins and health care and hiring systems) with its own policies and point of view.
> ...
VS Code is open source. (Cursor is built on it!)
GitHub didn’t embrace, extend, extinguish git. You can git push to a different company (e.g. Gitlab) and you’ve migrated. The biggest problems with GitHub are scaling and availability, not lock-in.
Microsoft today is nothing like it was 30 or 20 years ago.
Fifteen years ago we were writing HTML and JavaScript specifically for Internet Explorer. Edge is built on Chromium.
I don't think so
Literally nobody has said that it did? This is a wild strawman. Who are you trying to fool.
He is famous for hyper-competitiveness and strong desire to win at all costs.
Old folks also remember the days when it was possible to make a living out of selling software tools.
Would you rather the company went under after it ran out of money and had to fire everyone instead? Not to mention a quarter of the company was laid off the year before the acquisition.
you would? has any trillion dollar corporation ever?
Software projects will grow in complexity to consume whatever budget you give it. If you hire 50 devs and give them a bunch of business objectives, they are going to do what they do and write a ton of software.
It’s not obvious to me that it would be theoretically impossible to build a cheaper package manager.
And to be fair 2: The other package repos also suck.
It seems that if you want to get something important changed in npm, you simply need exploit some of its short comings against Microsoft instead of discussing why it’s necessary.
Nice that they're following pnpm's lead on this after [checks watch]... 18 months?
What is their purpose in JS land?
the reason for not bundling all native binaries is becasue the no. of combinations are huge and it can make module size hundreds of MBs
... Probably a few more but the native case is probably the biggest and the packages I'm using nowadays ship precompiled blobs in optionalDependencies. Install scripts seem to be out of favor.
But if you're already following the os + cpu + optionalDependencies model to distribute your precompiled binaries you should be fine.
https://www.kb.cert.org/vuls/id/319816
This is misleading. The change addresses one important attack vector. But if one runs the application directly on the host for development, if the package is imported like pointed out in the other comments or the package intends to steal user credentials from production, it is far from "being safe". Safer, but still needs scrutiny.
https://github.com/kennethreitz/pytheory/issues/47
The reason this may be overlooked is because build deps are only ran by the devs, but not the users, so users dismiss it as safe. However, if a build dep is infected, the infection may spread to the actual package code, which will then of course be run by the user.
Not theoretical, Microsoft is currently under attack by a worm that spreads through vs code extensions, which then spread to actual packages that users run.
There is plenty of malicious stuff you can do from the browser.
Most packages are imported via import/require, even if it's a browser only package. Because of SSR and reasons.
Or maybe not, let's look at a random browser only example, angular and react will use SSR, so they will execute in the server, let's check Jquery:
https://www.npmjs.com/package/jquery
Docs suggest just using a script tag instead of npm, when using npm install, they suggest to run import statement, which can execute arbitrary code.
The bottom line seems to be that if you are using npm, it's cause you are using node, and therefore you will run the imported code in the server, otherwise you would use a script tag.
But maybe there's a way to define a browser only package or .js URL such that it is only downloaded and served but never executed server side?
In any case, not a huge usecase of npm, which again, is designed for node which is backend.
Randome example,
include
The dev has to be responsible for ensuring that their build scripts are safe, I need to be responsible for ensuring that my runtime is safe.
It'd be great to have more tools for untrusting libraries (iframes are awesome for this on the frontend) but this is still a massive win.
Without that, this just comes across like unconstructive commentary.
This moves the needle a little your proposals or the lack thereof don’t move it at all. So I’ll take this over nothing.
It's node + npm compatible and its permission system locks everything down by default.
If you know ahead of time, you can turn on which permissions something is supposed to have in the config file.
Or you can just not use a config file at all. Anytime it needs a permission: it asks you what it wants. You can say yes or no, and those are saved in the config file for next time. If you say no, the script throws an error where it tried to access something it didn't have permission for.
---
Example:
- My linter wants access to my file system?
- My bundler wants read and write access to my file system? - Oh what's this? An updated dependency I've been using for 6 months suddenly asking for access to my .env file, and asking to run curl in a separate process? How about "no". Why would a simple DOM utility dependency be asking for those permissions? Ah, looks like it was part of a credential stealing supply chain attack. Glad I wasn't using node.---
Addendum: Node now has a permission system, but it's broken by design so it's useless.
Additionally, if a comment were to hypothetically point out an issue, that is valuable on its own. If someone reacts to a comment that points out an issue this defensively, it's a huge red flag.
Together with a lockfile that does achieve "package xyz postinstall allowed with hash <1234>"
A better safety net would be to require active 2FA proof for every package update.
You want delays by x days because supply chain attacks get caught very often within 1-2 days. And if you really really want to make an exception for a zero day then that's no problem and you can still quick patch by exclusion of that rule. They don't contradict in a unsolvable problem. You want both, you get both.
(You write something)
So then you have to check every package's updates and decide if you update, yes?
Have you rolled the numbers, vs all of the high-pri security updates that will be missed on day one, and exploited?
What is really needed is simply more nuance. I agree the delay can help, but honestly the entire ecosystem is broken. There shouldn't be a single thing installed, without someone having an eyes-on. That's how this is fixed.
Distros aren't perfect, but they handle this a load better. And this really runs to the problem, people want "new new new", yet often have very little real reason to want it. 99% of npm packages could be 5 years old, and no one would care.
But outside of that, npm could operate like a distro, but with more of a Debian unstable -> testing method, where it typically takes a few days for this migration to happen.
My point is, the fix isn't publishing by default, then hoping to catch. The fix is that nothing gets published, without a QA/validation step. Of course, that takes money. There is naturally, a super easy fix for that.
The code stays open source. The licensing stays <insert whatever by author>. However?
The ToS for using any or all of the npm architecture is if you're a company, you pay. If you neglect to pay, eg you don't register as a corporate entity, set up and account, and pay per use, then as per ToS the licensing is invalid, and you're fined via a copyright infringement. And yes, this would mean all npm packages would have an altered licensing model, basically with this tacked on.
Is what I'm saying perfect? Nope. Yet it's the general path which should be taken. And frankly, with the way things are going, this level of audit would allow for staff also categorize licenses, ensure accurate template files, and so on.
And some of this is the perfect use of an LLM. Not to do the work, but to flag with human review.
--
This ecosystem is done. Its model is broken. The concept of downloading random stuff without auditing in any way, is broken. The industry will be moving away, is starting to move away, and is having to move away.
So... how can this survive with that concept?
If one doesn't like my proposal above, then they should provide an alterative which allows:
* companies to have validate of licensing * audits which validate change is not untoward
Couldn’t this effectively result in the same process we get in pre-12 defaults?
Finally.
"retired" is probably a followup to functionality that was "deprecated".
I agree "breaking" would be clearer
It's a holdover from previous posts where there were more clearly defined deprecations.
but yes, in this case it's more of a behavioural change of defaults, so they just picked the closest vaguely mapped retired/deprecations tag.
1: https://github.blog/changelog/?type=deprecations
[0]: https://github.blog/changelog/2025-05-05-improvements-to-cha...
If you force every user to just use "--enable-unsecure-feature", guess what will happen?
This is not about improving security. This is about shifting blame.
A much better alternative would've been the introduction of sandboxes or simulation runs that would output which scripts and programs are running due to unpredictable dependencies. This way the user could check before the actual execution, and maintain an allow list much easier. That could be done via an npm update && npm upgrade workflow where the update generates the list that the user has to manually confirm.
Heck, even a chroot would be an improvement, and they're almost pointless these days, considering how good malware got at escaping chroots.
You're not wrong about sandboxing, but sandboxing isn't something that can just be blithely introduced to a large packaging ecosystem that previously assumed full system access. Doing so results in the same kind of regression you point out: if the sandboxing breaks peoples' builds, they'll just disable it and move on with their goals.
But to your point, Node has had permission flags for a while[0] but allows everything by default. Npm could use them to increase security even more. I just hope it doesn't take them another 10 years to change the default.
[0] https://nodejs.org/api/permissions.html
Still, “default off” is better. It would be nice if there were a lightweight way to fork upstream packages, and cache the native builds. It’d improve build times, make the build step more explicit / sandboxable and allow for easier binary builds for operating systems and processors that M$ treats as second class.
1. Publishing users must approve each and every release from a smartphone app.
2. Publishing users must provide verified government ID.
The first step prevents the types of attacks where an attacker gets control of a maintainer's computer and publishes a new release.
The second step discourages attacks where a user tries to get a malicious package used by others.
When combined with the security features that already exist, e.g. delays and automatic scanning, it would make it considerably harder to pull off a successful attack.
I don't know how to square the circle but any variation of "make it safer but really painful and difficult for anyone to publish a package" has this problem