42 comments

[ 0.30 ms ] story [ 46.0 ms ] thread
Why in the world would that specific 3x3 matrix be a trigger for an attack? Are they trying to find someone doing some particular kind of numerical analysis?
I would assume it’s actually so they can allow it to spread before it gets activated. Then do something that affects the entire chain of package dependencies
This matrix is not a condition, it’s a key. JSON.stringify with it’s data goes to the scrypt as a password and that creates an AES-256-GCM key. There is no if, every other input won’t decrypt. That’s why no one will get payload from the package without knowing the exact input.
1. “The X is not Y, it's Z” 2. 3 months old account

Bad bot.

(I still wonder what these not operators have to gain in that process, but they sure want HN karma).

Interestingly, the presumed bot uses unicode apostrophes (’) instead of ', yet misspells "its".
Tamping down on verbosity, removing em-dashes and adding misspellings are the obvious fixes to apply when your first attempts at spamming get flagged for being too on-the-nose: https://news.ycombinator.com/threads?id=coder-pm&next=487167...
There are "humanizer" scripts that these people like to use. This one is not the typical style I see in my online moderator adventures, which is usually "lowercase everything and remove all punctuation except periods", as if we are repelled by em-dash use and not the tortured prose.

I like the removal of a random definite article, to simulate an ESL writer and garner sympathy for using LLMs as a "tool to clean up posts". Heavens, they would never even think of using their Claude subscription to be a slop factory, that would cross a line.

gotta be careful. inevitably people will start emulating the LLM writing style since they're so overexposed to it
Being new here doesn't mean I'm a bot. I'm not native and maybe my style looks for you like a bot, I won't try to argue with you. Just wanted to contribute
Perhaps they just need a way to sneakily activate it? Or perhaps they have a target application which they know uses that. This method suggests a supply chain attack where a valid contributor to a library 'accidentally' includes this package and the hack carries out before anyone notices.

My guess is that it's crypto related but of course it could be anything.

A status code for (industrial/the-man) equipment? You could target specific environments by activating on obscure error codes that can be remotely triggered.

Aka If someone from the outside can make your equipment emit X internally, they can target X in some way.

Does the FBI or any other law-enforcement office follow up on these backdoors? Is this considered a crime, or even conspiracy to commit a crime, or is it only the act of using the backdoor that's a crime?

I can also see that it's still up in NPM without any warning of any kind: - https://www.npmjs.com/package/mathmain

But the Github repo for the package and the author are down: - https://github.com/allendev12 - https://github.com/allendev12/mathmain

Fascinating how intricate the target selection is on this
[delayed]
Probably Cloudflare. For me it shows the package name rather than a redaction. But from memory, Cloudflare email protection redacts it that way in the HTML and then adds a little JS to put it back in which might also do some kind of check to see if it thinks you are a real user before unredacting it.
You're probably allowing the site to run JS. If you don't, you get a bunch of these stupid redactions.
Yes, that’s correct, I’m familiar — but this is all basically offtopic for the post now that the title is corrected.
(comment deleted)
(comment deleted)
My strategy of not using dependencies at all seems to be getting stronger everyday.

Also no LLM generated skipping this hypetrain completely. Just hand written code I can personally vouch for. Code in exchange for cash, this is professional business, Boss.

Btw, I'm available for hire, preferably by Pre Market Fit or pre-MVP startups, email in profile.

Let us know in 2838 when you finish your first program, would love to check it out!
It will take even longer when they discover supply chain attacks on compilers. I mean they where mostly theoretical so far but that might change any day now.
There's this defense mechanism where people that face criticism on excesses and are proposed moderation, will take it to the extreme in order to defend the excess.

"You are spending too much"

"Hah, if I were to take your advise and reduce all costs, I would spend 0, I would die of hunger and the economy would halt!"

It's less a discussion and more a personal trickery that you do on yourself.

(comment deleted)
So, where do you draw the line? Do you accept having an OS? Because that is a huge dependency. So I assume you run directly on BIOS or UEFI? But even those are fairly sizable on modern systems.
>So, where do you draw the line? Do you accept having an OS?

Yes I accept using an OS usually, I guess there's much more than could fit on a single catchy sentence, but there's a clear policy.

Operating System is the biggest exception, for Windows it's pretty simple to carve out everything that is manufactured by Microsoft itself. But for the main Linux OS (Debian/RHEL), I include everything that is distributed by the main package manager (apt/yum) as allowed by the OS policy exception. (On Windows, this is equivalent to adding software packaged and signed by microsoft, like Git).

Alternative package managers like flatpak or snap are against my personal policy, not only are they very bloaty, but they kind of break the OS monopoly and push towards less safe supply chains, if it's not in apt/yum, then I don't use it.

> So I assume you run directly on BIOS or UEFI?

I have gone that route, but only experimentally, it's not very hard to get C compiled binaries to run and interface with keyboard and display through BIOS, but there's a lot of extra work that needs to be done incrementally, in order to use features in the sequence that they have historically been available, like 16 bit, 32 bit, 64 bits, 4GB memory. If you think of Wirth's law, this might actually be an effective long-term pacing strategy.

But I'm not that hardcore personally, not for lack of want, in a professional settings I pull towards the pragmatic side and start conceding to stuff like using an OS, maybe using one or two packages. I would probably revisit booting directly to binary if any startup I work with hits a home run and needs to upgrade to at least 10k+ concurrent users. It's like one step removed from an ASIC, which is a stage almost no company enters, but I would have definitely have passed the baton at that stage, custom hardware is another discipline.

>But even those are fairly sizable on modern systems.

Well not BIOS, but UEFI and device drives certainly are. BIOS would just be some (mostly unwritten) standards on how to initialize, then it dissapears. Of course hardware itself is a dependency, and I'm definitely not going to be summoning computing from heat, sand, and electricity, but my line is definitely at the OS and above.

One final exception that wasn't mentioned is the programming language and its 'built in libraries'. I use the programming language along with its standard distribution. For Python (my main language), that means I don't use pip, but I might use 'import sockets' (it's almost the same as using cffi and glibc anyways). There's an analogue in almost all languages, node with npm, java with maven, php with composer, I just don't add those kinds of dependencies if I have control over it. I chmod ugo-rwx requirements.txt to avoid other engineers from adding leftpadisms.

That's not to say that it never happens, maybe even I imported Flask to meet a deadline, and maybe there's that perfect library from a good source that someone else suggests and it gets accepted, but it doesn't hurt to add some friction, it catches a lot of trash packages from being added to the foundation of a startup, which give almost no benefits at great expense over the lifecycle of the core

Had I found sthg like this, I'd be proud to tell everyone and certainly enjoy doing the writeup. But this smells like it was ai-written...
It didn't seem like the usual AI style, but the flow and language was very strange indeed.

  It uses the LICENSE file as a lock. Before anything else, it reads the package's own LICENSE file and looks for a line that has no business being in a licence:
_sigh_
Some people enjoy doing the thing more than writing about it later. Would you rather this, or no write up at all?
A lot of this seems to be a reminder that the CommonJS module format should just be left to die already. Not that you can't pull similar tricks with `await import()` in ESM, but you can't easily grep an entire dependency for dynamic `require()` half as easily as you can can `grep import\s*\(` for dynamic import and analysis tools for static `import` keyword are easy to use/build rather than no such thing for CommonJS.

Someone thought I was joking when I said I always check JSR before NPM now, because I trust ESM so much more than CommonJS.

This is only partially true: dynamic imports are syntax (like super) but that's not a huge deterrent to hiding them. You could easily do `i = x => import(x)` to obfuscate the imports. Suddenly something looking like `await globalThis[computedValueEqualToI]` is doing imports. You still know stuff is being imported, you just have no idea what without a hell of a lot of effort, which is almost exactly the same effort as with require().
`i` still shows up in my grep, though, for anything like a function call of the word `import(`. Even if it takes a search to figure out what calls `i`, you know something is fishy because `import(` is used at all instead of the `import` keyword. Whereas there's no easy distinguishment of "top-level" static require and dynamic require, it's always a function call. (You can Regex match a negative lookahead for calls that don't include static strings, but that's a much harder regex than the `import(` call regex I provided.)
That's the thing: it doesn't. `globalThis[Function['na'+'me'][5]](...)` is equivalent to `import(...)` and doesn't show up in your grep. There's an infinite number of ways to access the global `i` that don't include the letter `i`. You can't even rely on the normal ways of accessing global variables:

```

new Promise(r => setTimeout('r(this)', 0))

```

This promise resolves to globalThis.

You can know that something is fishy, but it can be obfuscated nearly to the point of being impossible to untangle because you can't even be sure where it's being invoked.

Again, I still don't need to know how `i` is getting invoked if my security bar is `no import() calls`. `i`'s declaration is the red flag. Full stop.

Notably `import` is still a special reserved word in JS, so it does not exist on globalThis. `import()` in function usage is special and so to get added to globalThis has to be redeclared in a wrapper function such as `i`. That redeclaration is now always a red flag. I can work to reverse engineer whatever is calling it, or I can simply declare that entire ESM dependency untrustworthy and move on to something more reliable.

(ETA: Especially because in an ESM context, to be declared on globalThis it cannot use simply top level `var`, it also has to especially be globalThis object pollution, which no matter how you access globalThis to pollute it, looks weird and strange. Bonus: If the source is Typescript it will also likely involve an explicit `as any`, another potentially untrustworthy marker in a downstream dependency.)

What is the fix for npm at this point? It has a lot of issues with the registry