Show HN: Tips to stay safe from NPM supply chain attacks
96 points| bodash | 5 months ago |github.com
I'd love for you to check it out, and contribute your own insights and best practices to make this a comprehensive resource for the community.
Cheers!
HoyaSaxa|5 months ago
Instead, for those using npm, I'd highly suggest using `npm ci` both locally and of course on CI/CD. This will ensure the (transitive) dependencies pinned in the lockfile are used.
TIL on the `npm install --before="$(date -v -1d)"` trick; thanks for that! Using that to update (transitive) dependencies should be really helpful.
For those using GitHub Actions, I'd also recommend taking advantage of the new dependabot cooldown feature to reduce the likelihood of an incident. Also make sure to pin all GitHub Action dependencies to a sha and enforce that at the GitHub repo/account level.
knlsn|5 months ago
kpcyrd|5 months ago
With the colors incident back in 2022, random stuff started to break not when people updated their dependencies, but immediately, because npx would resolve dependencies when the command is executed.
This means it's not really possible to reason about what code is going to execute, and forensics is going to have a really hard time figuring out what a computer has executed.
If your software uses npx in any capacity, you've auto-failed the SBOM compliance checkbox.
potamic|5 months ago
I hate that this is becoming a thing. I was pretty miffed some time back when I realized go build just went ahead and installed a whole new version of golang on my machine. These are devtools ffs, why so much mollycoddling! And what happened to half a century of good conventions where the default is always to prompt?
condiment|5 months ago
I previously worked in an environment where our ci servers weren't internet-connected. One of the things we did get get node builds to work was we had 'node_modules' for our projects in a separate repository that got joined with our source code in CI to complete a build. When a developer added a dependency, they had to update this repo from their local version. It was annoying to have to synchronize two repositories, but this ended up being a forcing function for the development team to adopt several of the suggestions listed here. When you see a PR with a massive diff for a small dependency change, eyebrows raise and the team starts conversations about how to improve things.
minitech|5 months ago
abejfehr|5 months ago
So `yarn global add nx` will still install the latest version by default, unless you specifically have a `~/.yarnrc` disallowing lifecycle scripts they will still be executed. Using a package manager that doesn’t allow lifecycle scripts by default is the solution here I guess.
I don’t know what the solution is for stuff like [this](https://github.com/nrwl/nx-console/blob/d2fa56509679fc942bbc...) where the editor plugin automatically uses the latest version, or where in general you have little control over what version is used. Any eslint, typescript, nx, prettier, etc plugin will presumably depend on their corresponding package from npm, and if any of those gets compromised then just installing an editor extension could be enough to get you in trouble.
zygentoma|5 months ago
Even occasionally having a glance (e.g. when reading the docs) might be super helpful in discovering strange things going on.
invaliduser|5 months ago
ashishbijlani|5 months ago
Packj uses static+dynamic code/behavioral analysis to scan for indicators of compromise (e.g., spawning of shell, use of SSH keys, network communication, use of decode+eval, etc). It also checks for several metadata attributes to detect impersonating packages (typo squatting).
lrvick|5 months ago
That game of cat and mouse never ends.
The only solution is just actually reviewing the code we ship to our customers. Yes, even the code we copied off the internet with a magic "npm install" command.
dwoldrich|5 months ago
Node and the NPM ecosystem has been so productive for me and package.json scripts got me more into shell scripting than I ever thought I would.
All that said, there are some major insecurity deal breakers that frighten me when using Node in public-facing services.
Sneaking in compiled native binary blobs as part of NPM install, transitive dependencies with unpinned versions, the vast wasteland of unmaintained packages in NPM ... Node just needs to be superceded, I feel like.
It would be really great for a newer tech company with deep pockets like Tesla to pull a Sun Microsystems and release a new secure-by-design OS and language stack - maybe in support of a modernized hardware platform offering.
My preference would be for a deeper standard library like the jdk. I would like some sort of digital provenance that runs from the dev environment, through the os and package manager, through to all device types all the way through to the one and only global app store (or an enterprise-hosted proxy.) The whole kit and kaboodle signed and delivered at all levels.
I would like more energy efficient network hosting and service delivery patterns codified.
I would like public developer guilds with certs not as a prereq for employment, but rather to encourage developers to have something to show for their training other than a nebulous college diploma. Senior guildsmen can present their work products for review as an ongoing proof of their craftsmanship.
fergie|5 months ago
Personally I would like to see more awareness around the dangers of blindly trusting compiled javascript (and non-human-readable code generally).
indigodaddy|5 months ago
https://github.com/safedep/vet
politelemon|5 months ago
Also I find the irony goes hard in their recommendation of installing another attack surface (brew) on Linux and missing the point.
Rockslide|5 months ago
63stack|5 months ago
See this Stackoverflow thread:
https://stackoverflow.com/questions/45022048/why-does-npm-in...
The top answer has 3 updates to it, and links to 2 github issues, with conflicting information.
One says:
>If you run npm i against that package.json and package-lock.json, the latter will never be updated, even if the package.json would be happy with newer versions.
The other says:
>The module tree described by the package lock is reproduced. This means reproducing the structure described in the file, using the specific files referenced in "resolved" if available, falling back to normal package resolution using "version" if one isn't.
>This holds no longer true since npm 5.1.0, because now the generated module tree is a combined result of both package.json and package-lock.json. (Example: package.json specifies some package with version ^1.1.0; package-lock.json had locked it with version 1.1.4; but actually, the package is already available with version 1.1.9. In this case npm i resolves the package to 1.1.9 and overwrites the lockfile accordingly, hence ignoring the information in the lock file.)
So good luck figuring out what is true, but it seems to also depend on your version of NPM. Also, don't get me started on the presence of an entirely separate command "npm ci", which is supposed to be the one that is reproducible.
Absolute clowns.
bodash|5 months ago
That's why we use `npm ci` or `--frozen-lockfile` to install the exactly versions as lockfiles. But, by default, the `^` operator and just `install` command will check registry for any new releases and download them.
The primary arguments against pinning versions are missing security updates and increased maintenance overhead. But given the patterns we've seen, the attackers really _hope_ we automatically install new releases
aiahs|5 months ago
I'd be interested in hearing the setup other people have for their dev envs, also are you using separate browsers for Dev/Internet?
ry8806|5 months ago
I use this on all my front end projects and it protects my "host" machine from malicious packages, it's not a silver bullet though; other practices, e.g. good secret management, will help harden your dev environment from these attacks
jimbohn|5 months ago
Yoric|5 months ago
cyphar|5 months ago
A friend of mine has been working on [1] which is a less computer-sciency solution to the problem for Go modules that doesn't require adding effects to the type system (to be a bit snarky -- good luck getting more type changes into Go, it might take another 3 decades).
[1]: https://github.com/AkihiroSuda/gomodjail
fold_left|5 months ago
I thought it might have some merit at the time, but it never really took off as an idea.
hulitu|5 months ago
1. Don't use the damn thing.
2. If it needs an internet connection to compile, uninstall it.
turtleyacht|5 months ago
zenmac|5 months ago
privatelypublic|5 months ago
aetherspawn|5 months ago
Edit: too long to paste here, but if you ask ChatGPT it will show you how using a yarnrc file.
lrvick|5 months ago
Pick whichever of these will consume the fewest resources over time:
1. review an existing library and all dependencies, and all security updates to them forever (or ensure someone capable does or did)
2. implement the minimal functions you require on top of the language standard library yourself
Yes, this is serious advice, and I have followed it while shipping web applications to millions of people at multiple companies, as a consultant for many more companies, and as a founder and security engineer.
sho|5 months ago
Security and convenience are always in tension, but there is usually a productive, "sweet spot" middle ground. Your "solution" is way off to one side of that sweet spot. The status quo is probably a little too far off in the other direction. But a happy medium can be found where most teams are fine, most of the time, while retaining the ability to take advantage from the open source ecosystem.
eastbound|5 months ago
knlsn|5 months ago
captn3m0|5 months ago
em-bee|5 months ago
Off topic: blog posts, sign-up pages, newsletters, lists, and other reading material. Those can't be tried out, so can't be Show HNs.
it's not reading material.
it's a set of instructions that you can actually try. so i think it fits.
mediumsmart|5 months ago
physix|5 months ago
https://gist.github.com/pschleger/c1c36fbde003bea5eee7ce4291...
And a prompt to review a site I built for GitHub Pages, which I'll try this week.
https://gist.github.com/pschleger/8d5fcea6b96d8504ac58bb2f8d...