Remix.run Logo
raggi 25 days ago

install scripts are a distraction, just like package signatures are a distraction. adding/removing either feature has no significant impact on the wormability of this package ecosystem. installed npm code is run, with nearly zero exceptions.

nine_k 25 days ago | parent | next [-]

The installed code may be run in different settings, under a different user, with different privileges. Say, it may not run in CI/CD at all, or run only with the test user's privileges.

Postinstall scripts run at install time, with installer's privileges.

piperswe 25 days ago | parent | prev | next [-]

A lot of it ends up bundled to run in a browser though, and doesn't end up running in Node.js

throwaway27448 25 days ago | parent | prev | next [-]

Surely every layer of defense in depth is a distraction except the one that prevents the problem.

dns_snek 25 days ago | parent [-]

It's not defense in depth if the mechanism is trivially bypassed.

throwaway27448 25 days ago | parent [-]

Trivial relative to which perspective? The distinction matters enough to care. Just because your father might give away their phone pin over the phone doesn't mean we should allow this granting remote access to his phone.

dns_snek 25 days ago | parent [-]

Trivial in the sense that in 99.9% of situations, "npm install" is immediately followed by "npm run", "npm test", or some form of execution. Any execution that imports a dependency is enough for a transitive dependency to execute its malicious payload immediately.

Post-install scripts have a slight edge over executing malicious code on import, i.e. they work 99.95% of the time instead of 99.9% of the time, but removing these scripts wouldn't materially change the situation we're in. You're locking the back door but leaving the front door and all of the windows wide open.

I'm going to suggest that we might be worse off in the short-medium term if post-install scripts are removed because everyone who thought that disabling post-install scripts was a "good enough" standalone security strategy will get caught with their pants down as attackers modify their payloads.

throwaway27448 24 days ago | parent | next [-]

> Post-install scripts have a slight edge over executing malicious code on import, i.e. they work 99.95% of the time instead of 99.9% of the time

The "instead of" depends very much on the exploit and where it's wedged in the code. I doubt it's anywhere near 99%. Plus, getting the exploit to execute on the developer's machine is difficult to manage even in the best cases.

> because everyone who thought that disabling post-install scripts was a "good enough" standalone security strategy will get caught with their pants down as attackers modify their payloads.

Saying "well there are stupid people in the world" seems like a pretty bad justification to leave a hole open.

dns_snek 23 days ago | parent [-]

> The "instead of" depends very much on the exploit and where it's wedged in the code. I doubt it's anywhere near 99%. Plus, getting the exploit to execute on the developer's machine is difficult to manage even in the best cases.

We don't need to guess, it's going to be wedged in index.js, probably on line 1.

Are you aware that all transitive dependencies are executed immediately? You depend on PackageA which imports PackageB, which imports PackageC, which imports a trojanized PackageD. As soon as PackageD is imported, it executes its payload and infects your machine.

All of this happens in a blink of an eye, as soon as you run anything that kicks off an import chain containing a trojanized dependency.

Try it for yourself. This will simulate a malicious transitive dependency: koa > cookies > keygrip > tsscmp. You don't need to do anything except import koa.

    mkdir demo && cd demo
    npm install --save koa@3.2.0
    echo 'import "koa";' > demo.mjs
    echo 'console.log("\n\n---  pwned by a transitive dependency ---")' >> node_modules/tsscmp/lib/index.js
    node demo.mjs

> Saying "well there are stupid people in the world" seems like a pretty bad justification to leave a hole open

Then you're calling much of the HN audience stupid. I've had this argument on here several times - and this is the top percentile of people who try to do something at all.

The justification for leaving this hole open is that it's a waste of time, resources, and mindshare patching a hole when there's a comparable and unpatchable hole right next to it. Advocate for things that actually work, like sandboxes.

cindyllm 25 days ago | parent | prev [-]

[dead]

827a 25 days ago | parent | prev [-]

> There's a huge difference, because postinstall scripts are almost guaranteed to run in your CI pipeline. Compromised code probably won't (maybe it will if your test cases test a compromised package). Different attack profile. Worse in some ways (your CI likely has NPM push tokens, which is how this single-package worm become a multi-package self-replicating worm) (your CI pipeline also likely has some level of privileged access to your cloud environment; deployed services are more likely to be highly scoped). But, better in some ways.

dns_snek 25 days ago | parent [-]

> Compromised code probably won't (maybe it will if your test cases test a compromised package).

Code runs automatically on import, you don't have to call dependency.infectMePlease()

Your code imports depA which imports depB which imports depC which imports depD which has been compromised, and boom, malicious code runs before you've even finished resolving the imports.

> your CI likely has NPM push tokens, which is how this single-package worm become a multi-package self-replicating worm

I've never once seen or worked with a CI pipeline that ran "npm install" that would be any safer if post-install scripts didn't exist. They all run "npm run test" or similar.