Lotusbail Npm Package Found to Be Harvesting Whatsapp Messages and Contacts
Key topics
The discovery of malware in the Lotusbail npm package, which had racked up 56k downloads, has sparked a lively debate about the trustworthiness of popular packages. Commenters weighed in on the impracticality of thoroughly reviewing every dependency's source code, with some advocating for a more nuanced approach to vetting packages, such as scrutinizing every dependency and considering the package's popularity threshold. While some joked that GitHub stars are a poor metric for security, others pointed out that 56k downloads may not be enough to guarantee a package's safety, with one commenter noting that scanning code only after it breaks is a flawed strategy. As the discussion unfolded, a consensus emerged that relying solely on popularity is misguided, and that a more comprehensive approach to security is needed.
Snapshot generated from the HN discussion
Discussion Activity
Very active discussionFirst comment
14m
Peak period
110
0-3h
Avg / period
14.5
Based on 160 loaded comments
Key moments
- 01Story posted
Dec 22, 2025 at 5:35 PM EST
11 days ago
Step 01 - 02First comment
Dec 22, 2025 at 5:50 PM EST
14m after posting
Step 02 - 03Peak activity
110 comments in 0-3h
Hottest window of the conversation
Step 03 - 04Latest activity
Dec 24, 2025 at 11:00 AM EST
9 days ago
Step 04
Generating AI Summary...
Analyzing up to 500 comments to identify key contributors and discussion patterns
Want the full context?
Jump to the original sources
Read the primary article or dive into the live Hacker News thread when you're ready.
In this case more realistic advice would probably be to either rely on a more popular package to benefit from swarm intelligence, or creating your own implementation.
Yes, I'm sure many dependencies aren't very necessary. However, in many projects I worked on (corporate) which were on the older Webpack/Babel/Jest stack, you can expect node_modules at over 1 GB. There this ship has sailed long ago.
But on the upside, most of those packages should be fairly popular. With pnpm's dependency cooldown and whitelisting of postinstall scripts, you are probably good.
Age can't be gamed, but number of downloads sure can.
That seems ..low..?
I have 0 cred in anything security, so maybe i'm just missing a bigger picture thing, but like...if you told me i had to make some sort of malicious NPM package and get people to use it, i'd probably just find something that works, copy the code, put in some stylistic changes, and then bury my malicious code in there?
This seems so obvious that I question if the OP is correct in stating people aren't looking for that, or maybe I misunderstand what they mean because i'm ignorant?
That's how the xz exploit was caught.
It’s hard to read any blog anymore without trying to work out which part is actually from a human.
But then, you'd only be sure that the first sentence was legitimate and not the rest of the article. That is why I constantly reassure my readers that they're some goddamn motherfuckers throughout my writing. And you, too, are one, my friend.
Realistically, this is impossible.
I ran a little experiment recently, and it does take longer than just pulling in npm dependencies, but not that much longer for my particular project: logging, routing, rpc layer with end-to-end static types, database migrations, and so on. It took me a week to build a realistic, albeit simple app with only a few dependencies (Preact and Zod) running on Bun.
And, if you do need a lib because it's too much work, like maybe you have to parse some obscure language, just vendor the package. Read it, test it, make sure it works, and then pin the version. Realistically, you should only have a few dozens packages like this.
That's what's needed and I am seriously surprised NPM is trusted like it is. And I am seriously surprised developers aren't afraid of being sued for shipping malware to people.
Which when compared to NPM, which has no meaningful controls of any sort, is an enormous difference.
Yeah thats the entire point.
At least they seemed to have policies:
https://security.metacpan.org/
You can mitigate it by fully containerizing your dev env, locking your deps, enabling security scans, and manually updating your deps on a lagging schedule.
Never use npm global deps, pretty much the worst thing you can do in this situation.
Kind of a terrifying statement, right there.
The industry runs on a lot more unexamined trust than people think.
Well, I should qualify that. I do use quite a few dependencies, but they are ones that I wrote.
I've watched developers judge dependencies by GH stars, and "shiny" quotient.
On a completely unrelated tangent, I remember reading about a "GH Stars as a Service" outfit. I don't see any way that could be abused, though.../s
i dont know what the solution here is other than stop using npm
... So you're saying there is a blueprint for mitigating this already, and it just isn't followed?
I've heard rumor of a few 100k people laid off in tech over the past few years that might be interested.
- Random numbers
- Timezones, date formatting
- JSON parsing & serialization
- Functional programming tools (map, filter, reduce, Object.fromEntries, etc)
- TypedArrays
And if you use bun or nodejs, you also have out of the box access to an HTTP server, filesystem APIs, gzip, TLS and more. And if you're working in a browser, almost everything in jquery has since been pulled into the browser too. Eg, document.querySelector.
Of course, web frameworks like react aren't part of the standard library in JS. Nor should they be.
What more do you want JS to include by default? What do java, python and go have in their standard libraries that JS is missing?
But of course it fucking doesn't because it's a scripting language for the web. It has what it needs.
It does though! The JS stdlib even includes an entire wasm runtime. Its huge!
Seriously. I can barely think of any features in the C++ stdlib that are missing from JS. There's a couple - like JS is missing std::priority_queue. But JS has soooo much stuff that C++ is missing. Its insane.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
Also not many people seem to know this, but in the aftermath of leftpad being pulled from npm, npmjs changed their policy to disallow module authors from ever pulling old packages, outside a few very exceptional circumstances. The leftpad fiasco can’t happen again.
And no programming language's stdlib includes e. g. WhatsApp API libraries
Personally I think we need to start adding capability based systems into our programming languages. Random code shouldn't have "ambient authority" to just do anything on my computer with the same privileges as me. Like, if a function has this signature:
Then it should only be able to read its input, and return any integer it wants. But it shouldn't get ambient authority to access anything else on my computer. No network access. No filesystem. Nothing.Philosophically, I kind of think of it like function arguments and globals. If I call a function foo(someobj), then function foo is explicitly given access to someobj. And it also has access to any globals in my program. But we generally consider globals to be smelly. Passing data explicitly is better.
But the whole filesystem is essentially available as a global that any function, anywhere, can access. With full user permissions. I say no. I want languages where the filesystem itself (or a subset of it) can be passed as an argument. And if a function doesn't get passed a filesystem, it can't access a filesystem. If a function isn't passed a network socket, it can't just create one out of nothing.
I don't think it would be that onerous. The main function would get passed "the whole operating system" in a sense - like the filesystem and so on. And then it can pass files and sockets and whatnot to functions that need access to that stuff.
If we build something like that, we should be able to build something like npm but where you don't need to trust the developers of 3rd party software so much. The current system of trusting everyone with everything is insane.
Ironically, any c++ app I've written on windows does exactly this. "Are you sure you want to allow this program to access networking?" At least the first time I run it.
I also rarely write/run code for windows.
If I can't yum (et.al.) install it I absolutely review the past major point releases for an hour and do my research on the library.
1. Capabilities given to a program by the user. Eg, "This program wants to access your contacts. Allow / deny". But everything within a program might still have undifferentiated access. This requires support from the operating system to restrict what a program can do. This exists today in iOS and Android.
2. Capabilities within a program. So, if I call a function in a 3rd party library with the signature add(int, int), it can't access the filesystem or open network connections or access any data thats not in its argument list. Enforcing this would require support from the programming language, not the operating system. I don't know of any programming languages today which do this. C and Rust both fail here, as any function in the program can access the memory space of the entire program and make arbitrary syscalls.
Application level permissions are a good start. But its the second kind of fine-grained capabilities that would protect us from malicious packages in npm, pip and cargo.
When you look at a mobile program such as the GadgetBridge which is synchronizing data between a mobile device and a watch, and number of permissions it requires like contacts, bluetooth pairing, notifications, yadda yadda the list goes on.
Systems like E-Lang wouldn't bundle all these up into a single application. Your watch would have some capabilities, and those would interact directly with capabilities on the phone. I feel like if you want to look at our current popular mobile OS's as capability systems the capabilities are pretty coarse grained.
One thing I would add about compilers, npm, pip, cargo. Is that compilers are transformational programs, they really only need read and write access to a finite set of input, and output. In that sense, even capabilities are overkill because honestly they only need the bare minimum of IO, a batch processing system could do better than our mainstream OS security model.
I guess if you ship it you are still passing along contagion
NPM and NPM-style package managers that are designed to late-fetch dependencies just before build-time are already fundamentally broken. They're an end-run around the underlying version control system, all in favor of an ill-considered, half-baked scheme to implement an alternative approach to version control of the package manager project maintainers' devising.
And they provide cover for attacks like this, because they encourage a culture where one's dependencies are all "over there" and so the surface area gets swept under the rug and they never get reviewed (because 56K NPM users can't be wrong).
Should the OS prevent you from doing API calls to WhatsApps servers? What about the actual library this is based on, should that be blocked as well?
But okay, let's go further and use git submodules so that package.json is out of the picture. Even in that case we have the same problem.
Or, let's go even further and vendor the dependency so it is now copied into our source code. Even in that case too, we still have the same problem.
The dependency has been malicious all along, so if we use it in any way the game is already over.
I assume by "underlying version control system" you mean apt, rpm, homebrew and friends? They don't solve this problem either. Nobody in the opensource world is auditing code for you. Compromised xz still made it into apt. Who knows how many other packages are compromised in a similar way?
Also, complain if you want about npm. But apt and friends don't solve the problem that npm, cargo, pip and so on solve. I'm writing some software. I want to depend on some package X at version Y (eg numpy, serde, react, whatever). I want to use that package, at that version, on all supported platforms. Debian. Ubuntu. Redhat. MacOS. And so on.
Try and do that using the system package manager and you're in a world of hurt. "Oh, your system only has official packages for SDL2, not SDL3. Maybe move your entire computer to an unustable branch of ubuntu to fix it?" / "Yeah, we don't have that python package in homebrew. Maybe you could add it and maintain it yourself?" / "New ticket: I'm trying to run your software in gentoo, but it only has an earlier version of dependency Y."
Hell. Utter hell.
It's like I said you should use a hammer not a screwdriver and you're criticizing the hammer for not coming with free carpenters.
That's still true of nix. Whether you should trust a package is on you. But nix solves everything else listed here.
> I want to use that package, at that version, on all supported platforms...
Nix derivations will fail to build if their contents rely on the FHS (https://refspecs.linuxfoundation.org/FHS_3.0/fhs/index.html), so if a package tries to blindly trust that `/bin/bash` is in fact a compatible version of what you think it is, it won't make it into the package set. So we can each package our a bash script, and instead of running on "bash" each will run on the precise version of bash that we packaged with it. This goes for everything though, compilers, linkers, interpreters, packages that you might otherwise have installed with pip or npm or cargo... nix demands a hash for it up front. It could still have been malicious the whole time, but it can't suddenly become malicious at a later date.
> ... Debian. Ubuntu. Redhat. MacOS. And so on. Try and do that using the system package manager and you're in a world of hurt.
If you're on NixOS, nix is your system package manager. If you're not, you can still install nix and use it on all of those platforms (not Windows, certain heroic folk are working on that, WSL works though)
> Oh, your system only has official packages for SDL2, not SDL3. Maybe move your entire computer to an unustable branch of ubuntu to fix it?"
I just installed SDL3, nix put it in `/nix/store/yla09kr0357x5khlm8ijkmfm8vvzzkxb-sdl3-3.2.26`. Then I installed SDL2, nix put it in `/nix/store/a5ybsxyliwbay8lxx4994xinr2jw079z-sdl2-compat-2.32.58` If I want one or the other at different times, nix will add or remove those from my path. I just have to tell nix which one I want...
> "Yeah, we don't have that python package in homebrew. Maybe you could add it and maintain it yourself?"All of the major languages have some kind of foo2nix adapter package. When I want to use a python package that's not in nixpkgs, I use uv2nix and nix handles enforcing package sanity on them (i.e. maps uv.lock, a python thing, into flake.lock, a nix thing). I've been dabbling with typescript lately, so I'm using pnpm2nix to map typescript libraries not in nixpkgs in a similar way.
It's not perfect and bad things still make it through, but just look at your example - XZ. This never made it into Debian stable repositories and it was caught remarkably quickly. Meanwhile, we have NPM vulnerability after vulnerability.
Even OpenBSD, famous for auditing their code, doesn't audit packages. Only the base system.
I’m not really sure what you think a maintainer adds here. They don’t audit the code. A well written npm or cargo or pip module works automatically on all operating systems. Why would we need or want human intervention? To what? Manually add each package to N other operating systems? Sounds like a huge waste of time. Especially given the selection of packages (and versions of those packages) in every operating system will end up totally different. It’s a massive headache if you want your software to work on multiple Linux distros. And everyone wants that.
Npm also isn’t perfect. But npm also has 20x as many packages as apt does on Ubuntu (3.1M vs 150k). I wouldn’t be surprised if there is more malicious code on npm. Until we get better security tools, its buyer beware.
If apt's DNA was to download package binaries straight from Github, then I would blame it on the package manager for making it so inherently easy to download malware, wouldn't I?
The issue I have is that I don't really have a good idea for a solution to this problem - on one hand, I don't expect everyone to roll the entire modern stacks by hand every time. Killing collaborative software development seems like literally throwing the baby out with the bath water. On the other hand, I feel like nothing I touch is "secure" in any real sense - the tick boxes are there, and they are all checked, but I don't think a single one of them really protects me against anything - most of the time, the monster is already inside the house.
Speed of development and development experience are not metrics to be minimized/discarded lightly. If you were to start a company/product/project tomorrow, a lot of the things you want to be doing in the beginning are not related to these tools. You probably, most of the time, want to be exploring your solution space. Creating a development and CI/CD environment that can fully take advantage of these tools capabilities (like hermeticity and reproducibility) is not straightforward - in most cases setting up, scaling and maintaining these often requires a whole team with knowledge that most developers won't have. You don't want to gatekeep the writing of new software behind such requirements. But I do agree that the default should be closer to this, than what we have today. How we get there - now that is the million dollar question.
Yes, but IMO a tooling change is needed first. There just isn't good infrastructure fir doing this.
If, for code, there is a parallel "state" document with the intent behind each line of code, each function
And in conjunction that state document is connected to a "higher layer of abstraction" document (recursively up as needed) to tie in higher layers of intent
Such a thing would make it easier to surface weird behavior imo, alongside general "spec driven design" perks. More human readable = more eyes, and potential for automated LLM analysis too.
I'm not sure it'd be _Perfect_, but I think it'd be loads better than what we've got now
Is NPM really collaborative? People just throw stuff out there and you can pick it up. It's the least commons denominator of collaboration.
The thing that NPM is missing is trust and trust doesn't scale to 1000x dependencies.
I don't know, it just seems like every tech area has these problems and I honestly don't understand why there aren't more 'standardized' solutions here
ive started using Flutter even for web applications as well, works pretty well, still use Astro/React tho for frontend websites so I can't completely get away from it.
The language is too hard to do a meaningful static analysis. This particular attack is much harder (though not impossible) to execute in Java, Go, or Rust-based packages.
1 - https://ashishb.net/tech/javascript/
True. In a backend, however, a compromised payload can put all of user's and your non-user data at risk.
That sounds like a GDPR fine waiting to be issued right there.
It is not harder to write. It is more challenging to execute this attack stealthily.
Due to the myriad behaviors of runtimes (browser vs. backend), frameworks (and their numerous versions), and over-dependency on external dependencies (e.g., leftpad), the risk in JS-based backends increases significantly.
https://en.wikipedia.org/wiki/Apache_Commons
Something that I find to be a frustrating side effect of malware issues like this is that it seems to result in well-intentioned security teams locking down the data in apps.
The justification is quite plausible -- in this case WhatsApp messages were being stolen! But the thing is... that if this isn't what they steal they'll steal something else.
Meanwhile locking down those apps so the only apps with a certain signature can read from your WhatsApp means that if you want to back up your messages or read them for any legitimate purpose you're now SOL, or reliant on a usually slow, non-automatable UI-only flow.
I'm glad that modern computers are more secure than they have been, but I think that defense in depth by locking down everything and creating more silos is a problem of its own.
I don't think we should be handing more power to OS makers and away from users. There has to be a middle ground between wall gardens and open systems. It would be much better for node & npm to come up with a solution than locking down access.
Currently OSs are a free-for-all, where the user must blindly trust third-party apps.
This was fine in 1980 but isn't anymore.
A great microcosm illustration of this is automation permission on macOS right now: there's a separate allow dialog for every single app. If you try to use a general purpose automation app it needs to request permission for every single app on your computer individually the first time you use it. Having experienced that in practice it... absolutely sucks.
At this point it makes me feel like we need something like an async audit API. Maybe the OS just tracks and logs all of your apps' activity and then:
1) You can view it of course.
2) The OS monitors for deviations from expected patterns for that app globally (kinda like Microsoft's SmartScreen?)
3) Your own apps can get permission to read this audit log if you want to analyze it your own way and/or be more secure. If you're more paranoid maybe you could use a variant that kills an app in a hurry if it's misbehaving.
Sadly you can't even implement this as a third party thing on macOS at this point because the security model prohibits you from monitoring other apps. You can't even do it with the user's permission because tracing apps requires you to turn SIP off.
The problem here, is that like so many social-media apps, the first thing the app will do is scrape as much as it possibly can from the device, lest it lose access later, at which point auditing it and restricting its permissions is already too late.
Give an inch, and they’ll take a mile. Better to make them justify every millimetre instead.
We're not in 1980 anymore. Most people need zero, and even power users need at most one or two apps that need that full access to the disk.
In macOS, for example, the sandbox and the file dialog already allow opening any file, bundle or folder on the disk. I haven't really come across any app that does better browsing than this dialog, but if there's any, it should be a special case. Funny enough, WhatsApp on iOS is an app that reimplements the photo browser, as a dark pattern to force users to either give full permission to photos or suffer.
The only time where the OS file dialog becomes limited is when a file is actually "multiple files". Which is 1) solvable by bundles or folders and 2) a symptom of developers not giving a shit about usability.
51 more comments available on Hacker News