http://qs321.pair.com?node_id=11143020


in reply to Running user-provided JavaScript code

Years ago, when I was an active participant in the #linux channel of the local IRC network, we had a bot that could evaluate arbitrary shell commands, really handy to test one-liners. I don't know exactly how it was implemented, but one of the operators told me it was running on a custom Linux build inside QEMU running inside another QEMU instance because occasionally, despite the commands running as nobody and with various ulimits set, people would find a way to crash something or escape one sandbox... but never all of them.

Running user-provided JavaScript safely is hard. Browser vendors pour a lot of money in it, and JavaScript is still one of the leading exploitation vectors, the first step from navigating to a maliciously crafted web page to arbitrary code execution. Duktape has the benefit of not having to run JavaScript really fast and so sidesteps a whole class of JIT-related vulnerabilities (not needing to allocate writeable memory and turn it executable later helps a lot), but it does have its share of issues labelled "security". Lua is a much simpler language than JavaScript, with a whole chapter on sandboxing in PIL, and yet another double-free has been found in it just a few days ago, which might potentially lead to type confusion and sandbox escape. SQLite is probably some of the finest C code there can be, and yet they still fix crashing bugs, mostly from corrupted database files, but occasionally from SQL input too. Ethereum itself has an occasional vulnerability in its virtual machine too. For Perl, there's Safe, but with the warning at the end of the documentation page, I wouldn't want to use it alone to run arbitrary code over the Internet, either.

Admittedly, not all crashing bugs can be exploited, and not all issues labelled "security" will be exploited in the wild, and yet it feels like a fundamental problem: once we get a computer to run some code, it becomes hard to prevent it from running some other code that we don't want it to run but attackers do. I don't have a good solution, but I wish you good luck, and to proceed carefully!

Replies are listed 'Best First'.
Re^2: Running user-provided JavaScript code
by cavac (Parson) on Apr 19, 2022 at 07:59 UTC

    I'm aware that there are security considerations with any of these solutions. But i don't see much of an alternative these days, unless i want to write everything on my own and then hope&pray that i don't have a stupid fail somewhere in my code that let's the user exploit it anyway.

    Frankly, these days a user with enough smarts can probably exploit something like unicode handling. Oh wait, that stuff is already happening.

    Realistically, i don't have any answers, too.

    perl -e 'use Crypt::Digest::SHA256 qw[sha256_hex]; print substr(sha256_hex("the Answer To Life, The Universe And Everything"), 6, 2), "\n";'

      Using a turing-complete language like Javascript for user-proided code begs for trouble. Two of the most trivial ways to cause trouble are allocating all available memory and infinite loops. Yes, there are counter measures for both, but why allow getting into trouble at all? A reduced, domain-specific language that is intentionally not turing-complete might do the trick.

      Alexander

      --
      Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

        I thought about a simplified language. But nearly all my use cases require conditionals and loop constructs. Which make it turing complete.

        Plus, inventing and implementing a domain-specific language has a lot of drawbacks as well, especially if it's done by a single person. First of, it still will have ways to exploit it, as all computer code inevitably does. And secondly, it will be single-use only, so the user has to learn a specific language for that one job. And if i implement something else that also needs scripting, the user will have to learn a second, different language. I have experimented with stuff like that in the past, and it's basically a neverending maintenance nightmare.

        And frankly, i had to work with turing-complete stuff before that is way harder to properly sandbox with the usual tools available. You know, evil stuff like PDF, Ghostscript, True-Type fonts, MediaWiki Templates, Minecraft, laptop batteries, computer keyboards, printers, "smart" LED lamps, security cameras, smartphones, etc. At this point, i'm resigned to the fact that there is so much exploitable soft- and hardware around me that i'm never going to be truly secure.

        perl -e 'use Crypt::Digest::SHA256 qw[sha256_hex]; print substr(sha256_hex("the Answer To Life, The Universe And Everything"), 6, 2), "\n";'