[HN Gopher] NPM flooded with malicious packages downloaded more ...
___________________________________________________________________
NPM flooded with malicious packages downloaded more than 86k times
Author : jnord
Score : 105 points
Date : 2025-10-30 00:37 UTC (22 hours ago)
(HTM) web link (arstechnica.com)
(TXT) w3m dump (arstechnica.com)
| edoceo wrote:
| Happy I keep a mirror of my deps, that I have to "manually"
| update. But also, the download numbers are not really accurate
| for actual install count - for example each test run could
| increment.
| robpco wrote:
| Alternate article with more detailed description of exploit:
| https://www.bleepingcomputer.com/news/security/phantomraven-...
| crtasm wrote:
| >When you run npm install, npm doesn't just download packages. It
| executes code. Specifically, it runs lifecycle scripts defined in
| package.json - preinstall, install, and postinstall hooks.
|
| What's the legitimate use case for a package install being
| allowed to run arbitrary commands on your computer?
|
| Quote is from the researchers report
| https://www.koi.ai/blog/phantomraven-npm-malware-hidden-in-i...
|
| edit: I was thinking of this other case that spawned terminals,
| but the question stands: https://socket.dev/blog/10-npm-
| typosquatted-packages-deploy-...
| j1elo wrote:
| Easy example that I know of: the Mediasoup project is a library
| written in C++ for streaming video over the internet. It is
| published as a Node package and offers a JS API. Upon
| installing, it would just download the appropriate C++ sources
| and compile them on the spot. The project maintainers wanted to
| write code, not manage precompiled builds, so that was the most
| logical way of installing it. Note that a while ago they ended
| up adding downloadable builds for the most common platforms,
| but for anything else the expectation still was (and is, I
| guess) to build sources at install time.
| exe34 wrote:
| how hard would it be to say "upon first install, run
| do_sketchy_shit.sh to install requirements"?
| lelandbatey wrote:
| People want package managers to do that for them. As much
| as I think it's often a mistake (if your stuff requires
| more than expanding archives different folders to install,
| then somewhere in the stack something has gone quite
| wrong), I will concede that because we live in an imperfect
| world, other folks will want the possibility to "just run
| the thing automatically to _get it done_. " I hope we can
| get to a world where such hooks are no longer required one
| day.
| exe34 wrote:
| yes that's why npm is for them. I'd rather download the
| libraries that I need one by one.
| squidsoup wrote:
| pnpm v10 disables all lifecycle scripts by default and requires
| the user to whitelist packages.
|
| https://github.com/orgs/pnpm/discussions/8945
| chrisweekly wrote:
| One of the many reasons there is no good reason to use npm;
| pnpm is better in every way.
| sroussey wrote:
| It's just security theater in the end. You can just as easily
| put all that stuff in the package files since a package is
| installed to run code. You have that code then do all the
| sketchy stuff.
|
| What's needed is an entitlements system so a package you
| install doesn't do runtime stuff like install crypto mining
| software. Even then...
| theodorejb wrote:
| I would expect to be able to download a package and then
| inspect the code before I decide to import/run any of the
| package files. But npm by default will run arbitrary code
| in the package before developers have a chance to inspect
| it, which can be very surprising and dangerous.
| theodorejb wrote:
| Bun also doesn't execute lifestyle scripts by default, except
| for a customizable whitelist of trusted dependencies:
|
| https://bun.com/docs/guides/install/trusted
| vorticalbox wrote:
| One use case is downloading of binaries. For example mongo-
| memory-server [0] will download the mongoDB binary after you
| have installed it.
|
| [0] https://www.npmjs.com/package/mongodb-memory-server
| 8note wrote:
| why would i want that though, compared to downloading that
| binary in the install download?
|
| the npm version is decoupled from the binary version, when i
| want them locked together
| jonhohle wrote:
| I think it falls into a few buckets:
|
| A) maintainers don't know any better and connect things
| with string and gum until it most works and ship it
|
| B) people who are smart, but naive and think it will be
| different this time
|
| C) package manager creators who think they're creating
| something that hasn't been done before, don't look at prior
| art or failures, and fall into all of the same holes
| literally every other package manager has fallen into and
| will continue to fall into because no one in this industry
| learns anything.
| DangitBobby wrote:
| I seem to recall Husky at one point using lifecycle hooks to
| install the git hooks configured in your repository when
| running NPM install.
| interstice wrote:
| Notable times this has bitten me include compiling image
| compression tools for gulp and older versions of sass, oh and a
| memorable one with openssl. Downloading a npm package should
| ideally not also require messing around with c compilation
| tools.
| zahlman wrote:
| > doesn't just download packages. It executes code.
| Specifically, it
|
| It pains me to remember that the reason LLMs write like this is
| because many humans did in the training data.
| ghusto wrote:
| When people ask me what's so wrong with lowering the bar of entry
| for engineering, I point to things like this.
| cxr wrote:
| Imagine if we had a system where you could just deposit the
| source code for a program you work on into a "depository". You
| could set it up so your team could "admit" the changes that have
| your approval, but it doesn't allow third parties to modify
| what's in your depository (even if it's a library that you're
| using that they wrote). When you build/deploy your program, you
| only compile/run third-party versions that have been admitted to
| the depository, and you never just eagerly fetch other versions
| that purport to be updates right before build time. If there is
| an update, you can download a copy and admit it to your repo at
| the normal time that you verify that your program actually needs
| the update. Even if it sounds far-fetched, I imagine we could get
| by with a system like this.
| edoceo wrote:
| That is exactly what I do.
| anthk wrote:
| You are describing BSD ports from the 90's. FreeBSD ports date
| back to 1993.
| ok123456 wrote:
| Also, Gentoo dating back to 2003.
| SoftTalker wrote:
| And today.
| chrisweekly wrote:
| You're describing a custom registry. These exist IRL (eg jFrog
| Artifactory). Useful for managing allow-listed packages which
| have met whatever criteria you might have (eg CVE-free based on
| your security tool of choice). Use of a custom registry, and a
| sane package manager (pnpm, not npm), and its lockfile, will
| significantly enhance your supply-chain security.
| cxr wrote:
| No. I am literally describing bog standard use of an ordinary
| VCS/SCM where the code for e.g. Skia, sqlite, libpng, etc. is
| placed in a "third-party/" subdirectory. Except I'm
| deliberately using the words "admit" and "depository" here
| instead of "commit" and "repository".
|
| Overlay version control systems like NPM, Cargo, etc. and
| their harebrained schemes involving "lockfiles" to paper over
| their deficiencies have evidently totally destroyed folks'
| ability to conceive of just using an SCM like Git or
| Mercurial to manage source the way that they're made for
| without introducing a second, half-assed,
| "registry"-dependent VCS into the mix.
| kej wrote:
| Now you have the opposite problem, where a vulnerability could
| be found in one of your dependencies but you don't get the fix
| until the next "normal time that you verify that your program
| actually needs the update".
| edoceo wrote:
| If a security issue is found that creates the "normal time".
|
| That is, when a security issue is found, regardless of supply
| chain tooling one would update.
|
| That there is a little cache/mirror thing in the middle is of
| little consequence in that case.
|
| And for all other cases the blessed versions in your mirror
| are better even if not latest.
| lenkite wrote:
| Well in the Java world, Maven had custom repositories which did
| this for the last 20+ years.
| 650REDHAIR wrote:
| As a hobbyist how do I stay protected and in the loop for
| breaches like this? I often follow guides that are popular and
| written by well-respected authors and I might be too flippant
| with installing dependencies trying to solve a pain point that
| has derailed my original project.
|
| Somewhat related, I also have a small homelab running local
| services and every now and then I try a new technology.
| occasionally I'll build a little thing that is neat and could be
| useful to someone else, but then I worry that I'm just a target
| for some bot to infiltrate because I'm not sophisticated enough
| to stop it.
|
| Where do I start?
| ajross wrote:
| > As a hobbyist how do I stay protected and in the loop for
| breaches like this?
|
| For the case of general software, "Don't use node" would be my
| advice, and by extension any packaging backend without external
| audit and validation. PyPI has its oopses too, Cargo is
| theoretically just as bad but in practice has been safe.
|
| The gold standard is Use The Software Debian Ships (Fedora is
| great too, arch is a bit down the ladder but not nearly as bad
| as the user-submitted madness outside Linux).
|
| But it seems like your question is about front end web
| development, and that's not my world and I have no advice
| beyond sympathy.
|
| > occasionally I'll build a little thing that is neat and could
| be useful to someone else, but then I worry that I'm just a
| target for some bot
|
| Pretty much that's the problem exactly. Distributing software
| is hard. It's a lot of work at a bunch of different levels of
| the process, and someone needs to commit to doing it. If you
| aren't willing to commit your time and resources, don't
| distribute it in a consumable way (obviously you can distribute
| what you built with it, and if it's appropriately licensed
| maybe someone else will come along and productize it).
|
| NPM thought they could hack that overhead and do better, but it
| turns out to have been a moved-too-fast-and-broke-things
| situation in hindsight.
| squidsoup wrote:
| Having spent a year trying to develop against dependencies
| only provided by a debian release, it is really painful in
| practice. At some point you're going to need something that
| is not packaged, or newer than the packaged version in your
| release.
| ajross wrote:
| It really depends on what you're doing. But yes, if you
| want to develop in "The NPM Style" where you suck down tiny
| things to do little pieces of what you need (and those
| things suck down tiny things, ad infinitum) then you're
| naturally exposed to the security risks inherent with
| depending on an unaudited soup of tiny things.
|
| You don't get secure things for free, you have to pay for
| that by doing things like "import and audit software
| yourself" or even "write simple utilities from scratch" on
| occasion.
| LtWorf wrote:
| That's when you join debian :)
| megous wrote:
| As a hobyist (or profesionally) you can also write code
| without dependencies outside of node itself.
| paulryanrogers wrote:
| Didn't Debian ship a uniquely weak version of OpenSSL for
| years? HeartBleed perhaps?
|
| IME Debian is falling behind on security fixes.
| ajross wrote:
| They did, and no one is perfect. But Debian is the best.
|
| FWIW, the subject at hand here isn't accidentally
| introduced security bugs (which affect all software and
| aren't well treated by auditing and testing). It's
| deliberately malicious malware appearing as a dependency to
| legitimate software.
|
| So the use case here isn't Heartbleed, it's something like
| the xz-utils trojan. I'll give you one guess as to who
| caught that.
| zahlman wrote:
| > PyPI has its oopses too, Cargo is theoretically just as bad
| but in practice has been safe.
|
| One obvious further mitigation for Python is to configure
| your package installer to require pre-built wheels, and
| inspect the resulting environment prior to use. Of course,
| wheels can contain all sorts of compiled binary blobs and
| even the Python code can be obfuscated (or even missing, with
| just a compiled .pyc file in its place); but at least this
| way you are protected from arbitrary code running _at install
| time_.
| Etheryte wrote:
| Use dependencies that are fairly popular and pick a release
| that's at least a year old. Done. If there was something wrong
| with it, someone would've found it by now. For a hobbyist,
| that's more than sufficient.
| numbsafari wrote:
| Don't do development on your local machine. Full stop. Just
| don't.
|
| Do development, all of it, inside VMs or containers, either
| local or remote.
|
| Use ephemeral credentials within said VMs, or use no
| credentials. For example, do all your git pulls on your laptop
| directly, or in a separate VM with a mounted volume that is
| then shared with the VM/containers where you are running dev
| tooling.
|
| This has the added benefit of not only sandboxing your code,
| but also making your dev environments repeatable.
|
| If you are using GitHub, use codespaces. If you are using
| gitlab, workspaces. If you are using neither, check out tools
| like UTM or Vagrant.
| suck-my-spez wrote:
| Are people actually using UTM to do local development?
|
| Im genuinely curious because I casually looked into it so
| that i could work on some hobby stuff over lunch on my work
| machine.
|
| However I just assumed the performance wouldn't be too great.
|
| Would love to hear how people are setup...
| DyslexicAtheist wrote:
| you had me at:
|
| _> Don 't do development_
| jonhohle wrote:
| There are some operating systems, like FreeBSD, where you use
| the system's package manager and not a million language
| specific package managers.
|
| I still maintain pushing this back to library authors is the
| right thing to do instead of making this painful for literally
| millions of end-users. The friction of getting a package
| accepted into a critical mass of distributions is the point.
| evertheylen wrote:
| If you're on Linux, I've tried to build an easy yet secure way
| to isolate your system from your coding projects with
| containers. See https://github.com/evertheylen/probox
| uyzstvqs wrote:
| I'm not sure about NPM specifically, but in general: Pick a
| specific version and have your build system verify the known
| good checksum for that version. Give new packages at least 4
| weeks before using them, and look at the git commits of the
| project, especially for lesser-known packages.
| throwaway81523 wrote:
| "It's always NPM."
| gbransgrove wrote:
| Because these are fetching dependencies in the lifecycle hooks,
| even if they are legitimate at the moment there is no guarantee
| that it will stay that way. The owner of those dependencies could
| get compromised, or themselves be malicious, or be the package
| owner waiting to flip the switch to make existing versions become
| malicious. It's hard to see how the lifecycle hooks on install
| can stay in their current form.
| severino wrote:
| I wonder what could one do if he wants to use NPM for programming
| with a very popular framework (like Angular or Vue) and stay
| safe. Is just picking a not very recent version of the top level
| framework (Angular, etc.) enough? Is it possible to somehow
| isolate NPM so the code it runs, like those postinstall hooks,
| doesn't mess with your system, while at the same time allowing
| you to use it normally?
| theodorejb wrote:
| One option to make it a little safer is to add ignore-
| scripts=true to a .npmrc file in your project root. Lifestyle
| scripts then won't run automatically. It's not as nice as Pnpm
| or Bun, though, since this also prevents your own postinstall
| scripts from running (not just those of dependencies), and
| there's no way to whitelist trusted packages.
___________________________________________________________________
(page generated 2025-10-30 23:00 UTC)