20 comments

  • simonw 17 hours ago
    All these JavaScript engines and it's still remarkably hard to find a robust solution for executing JavaScript from untrusted sources inside my own server-side applications.

    Every time I look I find repos that look promising at first but are either unmaintained or have a team or just one or two maintainers running them as a side project.

    I want my sandbox to be backed by a large, well funded security team working for a product with real money on the line if there are any holes!

    (Playing with Cloudflare workerd this morning, which seems like it should cover my organizational requirements at least.)

    Update: Classic, even Cloudflare workerd has "WARNING: workerd is not a hardened sandbox" in the README! https://github.com/cloudflare/workerd?tab=readme-ov-file#war...

    • smarx007 6 minutes ago
      > I want my sandbox to be backed by a large, well funded security team

      How much are you ready to pay for a license?

    • kentonv 15 hours ago
      To add some color to "workerd is not a hardened sandbox":

      workerd does not include any sandboxing layers other than V8 itself. If someone has a V8 zero-day exploit, they can break out of the sandbox.

      But putting aside zero-day exploits for a moment, workerd is designed to be a sandbox. That is, applications by default have access to nothing except what you give them. There is only one default-on type of access: public internet access (covering public IPs only). You can disable this by overriding `globalOutbound` in the config (with which you can either intercept internet requests, or just block them).

      This is pretty different from e.g. Node, which starts from the assumption that apps should have permission to run arbitrary native code, limited only by the permissions of the user account under which Node is running.

      Some other runtimes advertise various forms of permissions, but workerd is the only one I know of where this is the core intended use case, and where all permissions (other than optionally public internet access, as mentioned) must be granted via capability-based security.

      Unfortunately, JavaScript engines are complicated, which means they tend to have bugs, and these bugs are often exploitable to escape the sandbox. This is not just true of V8, it's true of all of them; any that claims otherwise is naive. Cloudflare in production has a multi-layer security model to mitigate this, but our model involves a lot of, shall we say, active management which can't easily be packaged up into an open source product.

      With all that said, not all threat models require you to worry about such zero-day exploits, and you need to think about risk/benefit tradeoffs. We obviously have to worry about zero-days at Cloudflare since anyone can just upload code to us and run it. But if you're not literally accepting code directly from anonymous internet users then the risk may be a lot lower, and the overall security benefit of fine-grained sandboxing may be worth the increased exposure to zero-days.

      • simonw 15 hours ago
        Right - I trust workerd in the context of Cloudflare because I know it has a team of people who's job it is to keep it secure who are on-call 24/7.

        The problem I have is that I'm just one person and I don't want to be on call 24/7 ready to react to sandbox escapes, so I'm hoping I can find a solution that someone else built where they are willing to say "this is safe: you can feed in a string of untrusted JavaScript and we are confident it won't break out again".

        I think I might be able to get there via WebAssembly (e.g. with QuickJS or MicroQuickJS compiled to WASM) because the whole point of WebAssembly is to solve this one problem.

        > But if you're not literally accepting code directly from anonymous internet users then the risk may be a lot lower

        That's the problem: this is exactly what I want to be able to do!

        I want to build extension systems for my own apps such that users can run their own code or paste in code written by other people and have it execute safely. Similar to Shopify Functions: https://shopify.dev/docs/apps/build/functions

        I think the value unlocked by this kind of extension mechanism is ready to skyrocket, because users can use LLMs to help write that code for them.

        • aardvark179 14 hours ago
          You need more than a simple sandbox for what you describe. You also need to avoid infinite loops or other constructs from causing a DoS or similar, and if you are doing this with the intention of interacting with some other parts of a system then you need to think about how that interaction works and whether there is a way to execute something outside of that sandbox.

          Even if you go with something backed by a full time team there is still going to be a chance you have to deal with a security issue in a hurry, maybe in the run up to Christmas. That is just going to come with the territory and if you don’t want to deal with that then you probably need to think about whether you really need a sandbox that can execute untrusted code.

        • laurencerowe 10 hours ago
          There's also JCO for creating JS based WebAssembly components. It's based on StarlingMonkey which I believe is slightly faster than QuickJS under web assembly. https://github.com/bytecodealliance/jco

          Benchmark numbers for request isolated JS hello world / React page rendering:

              JCO/wasmtime: 314µs / 13ms
              Bun process forking: 1.7ms / 8.2ms
              v8 isolate from snapshot: 0.7ms / 22ms
              TinyKVM: 52µs / 708µs
              Native with reuse 14µs / 640µs
          
          Numbers taken from our upcoming TinyKVM paper. Benchmark setup code for JCO/wasmtime is here: https://github.com/libriscv/kvmserver/tree/main/examples/was...

          (I suspect even if we are able to get TinyKVM into a state you'd feel comfortable with in the future it would still be an awkward fit for Datasette since nested virtualisation is not exposed on AWS EC2.)

        • kentonv 14 hours ago
          > the whole point of WebAssembly is to solve this one problem.

          For Wasm to be a secure sandbox, you have to assume a bug-free compiler/interpreter, which, alas, none of them really are. It's a somewhat easier problem than building a bug-free JavaScript runtime, but not by as much as you might expect, sadly.

          > I want to build extension systems for my own apps such that users can run their own code or paste in code written by other people and have it execute safely. Similar to Shopify Functions: https://shopify.dev/docs/apps/build/functions

          Ah, this is exactly the Workers for Platforms use case: https://developers.cloudflare.com/cloudflare-for-platforms/w...

          And indeed, Shopify uses it: https://shopify.engineering/how-we-built-oxygen

          (There's also the upcoming Dynamic Worker Loader API: https://developers.cloudflare.com/workers/runtime-apis/bindi...)

          But it sounds like you really do want to self-host? I don't blame you, but that does make it tough. I'm not sure there's any such thing as a secure sandbox that doesn't require some level of monitoring and daily maintenance, sadly. (But admittedly I may be biased.)

          • simonw 14 hours ago
            Yeah my ideal is to have something that cleanly "pip installs" as a dependency such that users of my open source Python projects can self host tools that let them extend using arbitrary code, including code written by LLMs.

            I've been picking at this problem for a few years now!

            On the one hand I get why it's so hard. But it really feels like it should be possible to solve this in 2026 - executing arbitrary code in a way that constrains its memory and CPU time usage is a problem our industry solves in browsers and hosting platforms and databases and all sorts of other places, and has done for decades.

            The whole LLM-assisted end-user programming thing makes solving this with the right developer affordances so valuable!

            • rattray 8 hours ago
              Ah, in that context, why not just give the people workerd? People using & running OSS libraries are used to the fact that there might be vulns in libraries they're using, right?
              • kentonv 6 hours ago
                Or put another way:

                If Simon's users choose to self-host the open source version of his service, they are probably using it to run their own code, and so the sandbox security matters less, and workerd may be fine. The sandbox only matters when Simon himself offers his software as a service, which he could do using Workers for Platforms.

                (But this is a self-serving argument coming from me.)

        • neildhar 14 hours ago
          I worked on a sandbox of Hermes that compiles the engine to wasm, and then converts the wasm to C (like Mozilla's RLBox). It exposes the same C++ API as Hermes so it is pretty convenient to drop in, and should be fairly secure.

          It hasn't been updated in some time, but it should still be working, and can probably be brought up to date with some small effort: https://github.com/facebook/hermes/tree/static_h/API/hermes_...

          EDIT: Reading some of your other comments, I should point out that this is more like a component of a possible solution. It does not attempt to prevent resource exhaustion or crashes due to corrupted internal state.

        • rattray 8 hours ago
          Wait, why not just actually use the Cloudflare Sandboxes product then? Is it too costly or something? Or you need to be able to run without a connection to their cloud?

          https://developers.cloudflare.com/sandbox/

          • simonw 59 minutes ago
            I'm building software I want other people to be able to run themselves, I don't want to have to tell them to create a Cloudflare account as part of running that software.
    • ivankra 16 hours ago
      Put them in a container or VM? Security benefits from layering: engine/runtime is one layer, container/VM is another - an attacker would need two independent high-value exploits to breach both of them.

      High budget is no guarantee for absence of critical bugs in an engine, maybe even somewhat opposite - on a big team the incentives are aligned with shipping more features (since nobody gets promoted for maintenance, especially at Google) -> increasing complexity -> increasing bug surface.

      If speed is less important and you can live without JIT, that expands your options dramatically and eliminates a large class of bugs. You could take a lightweight engine and compile it to a memory-safe runtime, that'd give you yet another security layer for peace of mind. Several projects did such ports to Wasm/JS/Go - for example your browser likely runs QuickJS to interpret JavaScript inside .pdf (https://github.com/mozilla/pdf.js.quickjs)

    • 15155 16 hours ago
      https://github.com/bellard/mquickjs

      Featured recently on HN.

    • pastage 17 hours ago
      One process per sandbox will get you far, if all you want is to execute something. I would go as far as say it is pretty easy.
      • simonw 17 hours ago
        I want to execute untrusted code. This makes it very difficult indeed.
        • mike_hearn 16 hours ago
          What's wrong with V8?

          You could also look at GraalJS. It's shipped as part of the Oracle Database, there's a security team, patching process etc. It's used in production by Amazon amongst others. It's got flexible sandbox features too.

          https://www.graalvm.org/latest/reference-manual/embed-langua...

          The way it's written is good for security as well:

          https://medium.com/graalvm/writing-truly-memory-safe-jit-com...

          Disclosure: I sit next to the GraalVM team.

          • simonw 16 hours ago
            The challenge with V8 is finding a wrapper for it that doesn't come with a big warning NOT to use it as a sandbox for untrusted code - here's the workerd one https://github.com/cloudflare/workerd?tab=readme-ov-file#war... and here's the PyMiniRacer section: https://bpcreech.com/PyMiniRacer/architecture/#security-goal...

            I looked at GraalVM but was put off by the licensing situation: https://www.graalvm.org/22.3/reference-manual/embed-language...

            > GraalVM Enterprise provides the experimental Sandbox Resource Limits feature that allows for the limiting of resources used by guest applications. These resource limits are not available in the Community Edition of GraalVM.

            Part of my requirements for a sandbox are strong guarantees against memory or CPU exhaustion from poorly written or malicious code.

            • mike_hearn 16 hours ago
              Licensing has changed since that release. You can use the EE for free, both for personal and commercial use cases:

              https://www.graalvm.org/latest/introduction/#licensing-and-s...

              > Oracle GraalVM is licensed under GraalVM Free Terms and Conditions (GFTC) including License for Early Adopter Versions. Subject to the conditions in the license, including the License for Early Adopter Versions, the GFTC is intended to permit use by any user including commercial and production use.

              It has all the sandboxing features you might want. I don't know if the disclaimers on the other engines changes much, open source software always disclaims all liability. Nobody will stand behind something security sensitive unless it's commercial because otherwise there's no way to pay for the security team it requires.

    • HatchedLake721 16 hours ago
      Not a silver bullet, but did you look into isolated-vm? https://github.com/laverdet/isolated-vm

      But generally, I think best bet is to offload such things to e.g. Lambda per tenant.

      • simonw 16 hours ago
        The README says it's in maintenance mode and the single author doesn't have time to dedicate to the project.
  • gurgunday 20 hours ago
    You can see when JIT is disabled, the upcoming Static Hermes (Hermes V1) engine from Meta, built specifically for React Native, outperforms both V8 and JSCore on Apple Silicon

    It'll be interesting to see how much it will affect React Native apps as it gets more and more optimized for this use case

    • no_wizard 18 hours ago
      React Native continues to be one of the best technology bets I’ve ever made.

      At one point I really thought that Flutter would outclass it but typical Google project stuff has really put a damper on it from all I can see.

      It’s not better than native apps, but as far as cross platform GuIs go it’s still very very good

      • port11 16 hours ago
        Flutter and KMM are actually very good and better to use than the debacle that React Native can be. But they’re worlds behind in community support, and React Native became the ‘kitchen sink’ that works for most needs.

        As a React Native developer for, what, 6 years, I don’t have much positivity left to offer. Bug reports to the core team that went nowhere, the Android crash on remote images without dimensions, all the work offloaded to Expo, etc.

        Google couldn’t really done better, maybe Flutter should’ve become independent after the initial release.

      • wiseowise 18 hours ago
        > Flutter would outclass it but typical Google project stuff has really put a damper on it from all I can see.

        Flutter is amazing, but they really shot themselves in the foot with Dart (and I say that as someone who doesn't mind Dart).

  • gunwd 22 hours ago
    This is super cool, I didn't know JavaScriptCore consistently outperformed V8

    And SpiderMonkey seems... not up there compared to the other 2

    • aurareturn 20 hours ago
      That’s the promise of Bun - that it is faster because it uses JavascriptCore.
      • gurgunday 20 hours ago
        Bun is faster because it implements pretty much everything natively and just exposes them in JS, not because it uses JSCore

        I believe long term, V8 will become the undisputed champ again as Google has a lot more incentive than Apple to make the fastest engine, but this is just a wild guess of mine, and I'm biased being a Node.js Collaborator

        I've been hearing for a while that JSCore has a more elegant internal architecture than V8, and seeing the V8 team make big architectural changes as we speak seems to support it [1], but like I said, hopefully they will pay off long term

        [1]

        https://v8.dev/blog/leaving-the-sea-of-nodes

        https://v8.dev/blog/maglev

        • aurareturn 14 hours ago
          Bun's original marketing used JSCore's superior performance as a main benefit over Node.js.[0]

          Why would Google have more incentive than Apple to make the fastest engine? Safari being the fastest mobile browser is important to Apple.

          If Google had a stronger incentive than Apple, we would have seen V8 being more performant by now.

          [0]https://web.archive.org/web/20220724110148/https://bun.sh/

        • lionkor 19 hours ago
          > Google has a lot more incentive than Apple to make the fastest engine

          What are those incentives? I see no incentive for Google to make something fast.

          • gurgunday 19 hours ago
            A significant part of Google’s business (Ads, YouTube, Workspace) runs inside a browser, so if the web is slow, Google loses money
            • Octoth0rpe 18 hours ago
              And the faster that a page finishes rendering on an iphone, the faster that the cpu can idle, which hugely benefits battery life. That's a pretty strong motivation on Apple's side. I don't think the proposed motivation on google's side is stronger.
            • johannes1234321 17 hours ago
              What are the marginal gains in business for them from the likely improvement of the runtime? It's not like the web (or: web-technology-based apps) don't capture a lot of time already.
          • charcircuit 19 hours ago
            Faster page load times increases engagement with the web. More engagement on the web leads to more engagement with Google's ads.
            • lionkor 23 minutes ago
              I don't agree. Page load times do not matter when everything is so locked down that most people don't even know there's an alternative.
        • attractivechaos 18 hours ago
          I am not sure how "long term" you are thinking about. Making big architectural changes does not necessarily lead to better performance. JSC has been the fastest JS engine in the past 5-10 years as I remember. If google had a solution, they would have it now.
    • forgotpwd16 21 hours ago
      Interesting how V8 to JSC ~2x LOC but ~2/3 the binary size.
      • esprehn 20 hours ago
        The size difference is so large it makes me wonder if one is being compiled with ICU and the other without.
    • DarkFuture 21 hours ago
      Disappointing for Firefox for such lower performance.

      I just ran the JetStream2 benchmark and got:

      - Firefox: 159 score

      - Chromium: 235 score

      That's on latest Fedora Linux and Ryzen 3600 CPU.

      • tralarpa 19 hours ago
        Similar results here.

        I'm curious to know what the problem of Firefox is. For example, the 3d-raytrace-SP benchmark is nearly three times faster on Edge than on Firefox on my i7 laptop. The code of that benchmark is very simple and mostly consists of basic math operations and array accesses. Maybe the canvas operations are particularly slow on Firefox? This seems to be an example that developers should take a look at.

        • nicoburns 14 hours ago
          > Maybe the canvas operations are particularly slow on Firefox

          That seems likely. WebRender (Firefox's GPU accellerated rendering backend) doesn't do vector rasterization. So Firefox rasterizes vectors using the CPU-only version of Skia and then uploads them to the GPU as textures. Apparently the upload process is often the bottleneck.

          In contrast, Chrome uses (GPU-accelerated) Skia for everything. And Skia can render vector graphics directly into GPU memory (at least part of the rasterization pipeline is GPU accelerated). I would expect this to be quite a bit faster under load.

          It's a known problem, but I hear that almost all of the Gecko graphics team's capacity beyond general maintenance is going towards implementing WebGPU.

          ---

          SpiderMonkey is also now just quite a bit slower than V8 which may contribute.

        • 360MustangScope 14 hours ago
          The developers are busy ramming AI into it by management. This is probably never going to get looked into.
      • p_ing 20 hours ago
        M2 Air w/ 24GB RAM macOS 26.2:

        - Firefox: 253.584

        - Safari: 377.470

        - Chrome: 408.332

        - Edge: 412.005

  • mikehall314 21 hours ago
    I assume the 98% compatibility on ES6 for V8 is because they don't have tail call optimisation?
    • ivankra 20 hours ago
      Pretty much. ES6+ scores are from running compat-table's test suite (https://compat-table.github.io/compat-table/es6/), along with their weighting. If you click on an engine's name to go to a page about it, there's a report at the bottom with failing tests.
    • senfiaj 20 hours ago
      Maybe because with tail call optimization you wouldn't have a proper stack trace?
      • ggggffggggg 19 hours ago
        I never understood this complaint. You won’t get a “loop trace” when you convert your tail calls into an iterative algorithm. And your code will be less readable to boot.
        • senfiaj 18 hours ago
          I don't know fast it would be if it was done iteratively. But Apple's implementation has negative implications for debuggability: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe... https://webkit.org/blog/6240/ecmascript-6-proper-tail-calls-... .

          V8 team decided that it's not worth it, since proper stack traces (such as Error.stack) are essential for some libraries, such as Sentry (!). Removing some stack trace info can break some code. Also, imagine you have missing info from the error stack trace in production code running on NodeJS. that's not good. If you need TCO, you can compile that code in WASM. V8 does TCO in WASM.

          • pygy_ 18 hours ago
            That argument was vaguely plausible until WebKit/JavaScriptCore shipped PTC and literally no one bat an eye.

            Bun users don’t care either.

            At this point it is pure BS.

            • senfiaj 16 hours ago
              > Bun users don’t care either.

              Most Bun users don't even know about this (unless they are bitten by this). That doesn't mean absolutely no one cares or would not care even though such complaints might be uncommon.

        • dataflow 18 hours ago
          The difference is loops don't normally have traces but function calls do.
      • mikehall314 20 hours ago
        Supposedly, although the team at Apple were able to implement it. I think they had some oddly named technology like Chicken which created a shadow stack trace? Half remembered.
        • senfiaj 18 hours ago
          Yes, It's called ShadowChicken, and it has negative implications for debuggability. To make debugging tolerable, JavaScriptCore added an (intentionally silly) mechanism called ShadowChicken: a shadow stack used by Web Inspector that can show a finite number of tail-deleted frames (they mention 128). It's has some tradeoff.

          https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe... .

          https://webkit.org/blog/6240/ecmascript-6-proper-tail-calls-...

          V8 team decided that it's not worth it, since proper stack traces (such as Error.stack) are essential for some libraries, such as Sentry (!). Removing some stack trace info can break some code. Also imagine you have missing info from the error stack trace in production code running on NodeJS, that's not good. If you need TCO, you can compile that code in WASM. V8 does TCO in WASM.

  • callc 15 hours ago
    I got a question for everyone: as a web user, have you been affected by performance limitations of a particular JS engine? Have you switched browsers b/c of JS speed?

    My n=1 as a long time Firefox user is that performance is a non-issue (for the sites I frequent). I’m much more likely to switch browsers because of annoying bugs, like crashes due to FF installed as a snap.

    It honestly is pretty surprising, given that JS runtime runs website code single-threaded.

    • creatonez 12 hours ago
      When Chrome first came out in 2008, it was noticeably faster than any competitors. Users with only moderate tech knowledge were switching in droves because it was faster. Part of this was that it had a process-per-tab model properly making use of multi core CPUs for the first time, but much of it was because V8 was fast.

      The gap is not so big these days. JavaScriptCore, Spidermonkey, and V8 are all competent.

    • mock-possum 15 hours ago
      No, speed / performance of JavaScript has never, in my entire history of web use, been a driving factor in picking a browser - there may be one-offs here and there where I’m annoyed I have to switch to a different browser for a few minutes due to feature support or extension availability - but I can’t remember thinking “boy I wish JavaScript didn’t run so slow”
  • donatj 18 hours ago
    I am pleased to see how complete this table really is. I recently migrated a tool from Otto to Modernrc's QuickJS transpile of QuickJS to pure Go. Both are represented.
  • ChocolateGod 18 hours ago
    Is there any benchmarks between engines that record memory usage?

    How many of these engines are chasing benchmarks at the cost of increased memory usage?

    • ivankra 15 hours ago
      I captured max RSS size while running benchmarks as a rough approximation, but it's not exposed anywhere. If you go to the repo, you can run `./bench/compare -f rss_mb -lT bench/amd64/*.json` to see a table in the terminal. No big surprises there, Java engines (Rhino, Nashorn, GraalJS) are most memory-hungry.
  • _alastair 17 hours ago
    It’s fascinating to see so many implementations targeting the same thing, along with the crazy variation in runtime size. I’d love to see memory usage comparisons too but I suppose you’d need to establish what you’re actually measuring first.

    A few years ago I started work on a kind of abstraction layer that would let you plug Rust code into multiple different engines. Got as far as a proof of concept for JavascriptCore and QuickJS (at the time I had iOS and Android in mind as targets). I still think there’s some value in the idea, to avoid making too heavy a bet on one single JS engine.

    https://github.com/alastaircoote/esperanto

    • ivankra 17 hours ago
      I actually captured max RSS size while running benchmarks as a rough approximation, but it's not exposed anywhere. If you go to the repo, you can run `./bench/compare -f rss_mb -lT bench/amd64/*.json` to see a table in the terminal. No big surprises there, Java engines (Rhino, Nashorn, GraalJS) are most memory-hungry.
      • bflesch 14 hours ago
        thanks for your work!
  • csmantle 17 hours ago
    What surprises me is that under the "Show variants" checkbox, SpiderMonkey 24 from 2013 outperforms 147alpha by ~2000 pts -- almost 10% --, while having 1/4 LOC, 1/3 binary size and almost 1:1 on other metrics. (SM 24 targets ES5, however)
  • maelito 21 hours ago
    That's a lot of duplicate code. Différent hardware constraints and history I guess.
  • vivzkestrel 7 hours ago
    genuine question, let us say you took the source code of every single engine you see here and feed it to all the 10000 llms and ask them to analyze the code, optimize every function the best way they see fit, make architectural changes as and when they see appropriate, what do you think will be the result from cutting edge models?
  • ForHackernews 21 hours ago
    Is this right? Brimstone has a single contributor, 74k LoC (vs 1.3M for V8) and it's 97% compatible with ES6?

    That's a staggering accomplishment.

    https://github.com/Hans-Halverson/brimstone

  • sorentwo 20 hours ago
    Before looking at the zoo I figured there would be a dozen or so engines compared. Seeing the actual comparison is astounding!

    The amount of work just to aggregate and compare is admirable, let alone the effort behind the engines themselves.

  • td2 14 hours ago
    Its cool, but is there any explenation how score is calculated?
  • pmkary 20 hours ago
    I never thought they are so many!
  • pastage 17 hours ago
    Now run the "Which programming language is fastest?" Benchmark on all of them.

    https://benchmarksgame-team.pages.debian.net/benchmarksgame/...

    • ivankra 16 hours ago
      You can use this docker image with all the pre-built binaries as a starting point: https://hub.docker.com/r/ivankra/javascript-zoo

      Just keep benchmark code limited to standard ECMAScript, don't expect any browser or Node APIs besides console.log() or print().

  • bschmidt25011 13 hours ago
    [dead]
  • bschmidt25003 13 hours ago
    [dead]