‹ BackHN Continuity

Thread

Why does mathmain need an encrypted loader?

138 points · 43 comments · abhisek

  1. WorldMaker · · focus · HN ↗
    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.

    1. bastawhiz · · focus · HN ↗
      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().
      1. WorldMaker · · focus · HN ↗
        `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.)

        (ETA: Even/especially in minified code. Something like `var r = require` is rather common in Code Golfing/minifying CommonJS so grepping all uses of require both static and dynamic is also complicated by nicknames. But ESM doesn't minify static import ever and yeah dynamic import might be minified, but that still means it sticks out as a sore thumb if it exists at all even in minified shapes. Especially in minified shapes because that often means it is used multiple times for a minifier to decide that minifying it is worth the tax of declaring the minified nickname.)

        1. bastawhiz · · focus · HN ↗
          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.

          1. WorldMaker · · focus · HN ↗
            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.)

Open on Hacker News to reply ↗

Unofficial Hacker News client; not affiliated with Y Combinator.