r/programming • • 2d ago

How to Gaslight JavaScript Programmers

https://www.bryanpg.com/articles/pragma-twice/proxy.html
36 Upvotes

12 comments sorted by

13

u/erik240 2d ago

Well, the moment you think something doesn’t seem right … you set a breakpoint before the property access.

5

u/ythl 2d ago

Indeed, though you may not always have access to a debugger/breakpoints depending on where the JS is executing!

4

u/CherryLongjump1989 1d ago edited 1d ago

If you've discovered a way to run JS without ready access to breakpoints or a debugger then you've got much bigger problems. Maybe you're still running GWT, trying to set breakpoints in Java.

2

u/pawer13 1d ago

In a former job I had to use a tool created with Java 6 that consumed Javascript scripts using Rhino.

Luckily for me, NodeJS was released and I rewrote the whole tool using JS

1

u/CherryLongjump1989 1d ago

Yes, you had a much bigger problems. Like a non-standard runtime that wasn't entirely compatible with any ECMAScript version.

1

u/ythl 1d ago

At my work we use goja (https://github.com/dop251/goja) to run mathjax in JS VMs in order to render math equations as SVGs. This is so we can avoid a NodeJS runtime dependency and keep our docker images "from scratch" (containing a single statically compiled go binary) which has huge regulatory and cybersecurity benefits.

1

u/CherryLongjump1989 1d ago edited 1d ago

I've already got 20 questions like why didn't you just use a native library that already does exactly that? Real Tex, MicroTex, MathML, even Typst will do a lot more including anything that you might conceivably want to do with svg or html. You're making so many other sacrifices, so whatever MathJax is bringing to the table better really be worth it.

That said I'm deeply skeptical of the benefits and criteria you claim -- I doubt goja is more "secure" than a battle-tested runtime like V8 or JSC, how anyone in a regulatory space has even heard of goja let alone rubber stamped it is beyond me. The thing doesn't have a debugger, you are right. I'm sorry but proxy objects are the least of your problems here. How can you claim that you're writing secure code in a runtime where you can't even debug it? You're basically doing deliberate script injection into a single-process embedded runtime where there's a glaring lack of sandboxing. Go, by itself, hands down easier to secure than a JITed language. Go with an embedded interpreter executing user-supplied javascript on the other hand... I'll put this closer to the worst case scenario of security through obscurity.

Sorry about being so blunt, the project does sound very interesting. I'm into typesetting so I'd have fun working on this and I'm sure you do too.

1

u/ythl 1d ago

> I've already got 20 questions like why didn't you just use a native library that already does exactly that?

The short answer is that we used to use Mathjax + Node.js, and we have hundreds of knowledge articles with math equations a few of which depend on some of the eccentricities of Mathjax, so Mathjax + goja allowed us to remove the Node dependency without needing to check hundreds of KAs for rendering regressions.

> That said I'm deeply skeptical of the benefits and criteria you claim -- I doubt goja is more "secure" than a battle-tested runtime like V8 or JSC, how anyone in a regulatory space has even heard of goja let alone rubber stamped it is beyond me.

I agree with you - goja is almost certainly less secure than V8. However, note that the JS it executes is trusted (not user supplied), so it's fairly low risk. The bigger thing for us was the CVE surface area and SOUP (software of unknown provenance) surface area which is what regulatory bodies like the FDA care about when dealing with medical device software or medical device adjacent software. With a "from scratch" golang binary docker image, the surface area is the go stdlib and go dependencies. That's it. OTOH it's exceedingly difficult to do a "from scratch" Node.js docker image. Which means suddenly your surface area has already exploded into whatever your base distro is (alpine, ubuntu, debian, etc). There's now a torrent of distro-specific CVEs you have to regularly justify as "false positive" or "won't fix" such as libxml2 and all the other c libraries included in your base image. And that's not even mentioning npm also having a tendency of causing causing explosions in SOUP/CVE surface area due to the micro-package dependency web (a problem much less pronounced with go packages). Those are a few of the pressures that led us to move to a 100% golang application. Someday we would like to replace mathjax + goja with a native go solution like https://codeberg.org/go-latex/latex but so far the native go ones aren't mature enough yet (though with LLMs now we could probably fork and get up to snuff pretty quickly).

> The thing doesn't have a debugger, you are right. I'm sorry but proxy objects are the least of your problems here.

Yes, you are right. And actually I haven't ever used Proxy objects at work! I wrote the article because I discovered them when developing a video game and found their behavior surprising and fascinating so I wanted to do an "FYI"/"PSA" type piece. My specific use case for using Proxy was obscuring object APIs in a JavaScript puzzle adventure game I developed, and in my game, you can write and run JS, but you don't have access to a full debugger!

1

u/CherryLongjump1989 13h ago edited 12h ago

It's interesting how CVE checklist security forces people to go down the road of prioritizing labor limitations over legitimate security. I have a prediction -- sooner or later people will use LLMs to go over these obscure language runtimes, text layout libraries, etc, and file a slew of CVEs against them, too.

However, note that the JS it executes is trusted (not user supplied), so it's fairly low risk.

Yeah but you can throw your SOUP/CVE practices out the window because you've effectively got a large corpus of content that has never undergone any kind of security review, and you're executing all this code on your servers. Probably best not to mention it to the regulators, though.

And actually I haven't ever used Proxy objects at work!

It's maybe ironic but the Proxy is a powerful tool specifically for debugging, testing, refactoring, etc. They are particularly useful when you don't have a debugger. You can add it on top of existing code without having to modify the code and so for example, use it for call recording - track function arguments, return values, and timing for method calls. Or you can use it to perform access tracing, for example to guard against typos or unknown keys being read on config objects or enums that would otherwise silently fail by passing along an undefined value into the rest of your code. There are many other such cases where not having direct visibility into the running code is the exact reason why you would reach for a Proxy.

3

u/LukeLC 1d ago

I actually love JS proxies. The most common use-case I come across is when you need an object to default undefined values to something standard/safe. It's also not so complicated as the author makes it sound to reverse-engineer and learn what its capabilities are. The developer console makes it plain that it is a proxy, and you can easily jump to its definition from there.

0

u/backwrds 21h ago

not a very good title.

1

u/MartinLaSaucisse 13h ago

Tl;dr another sign that JS is an absolute garbage language.