76

JavaScript has certain limitations such as preventing reading and writing to disk and not allowing access to other browser windows or domains. But is that all that's needed to prevent malicious code from running?

JavaScript is pretty powerful, and it seems odd that browsers will unquestioningly run all JavaScript code they are given. How is that safe?

10 Answers 10

104

The standard is designed to be safe. The implementation may not be.

The browser isolates JavaScript, as it executes within a browser process itself. It cannot do anything which is not permitted by the browser JavaScript interpreter or JIT compiler. However, owing to its complexity, it's not at all uncommon for vulnerabilities to be found that allow JavaScript to compromise the browser and gain arbitrary code execution with the privileges of the browser process.

Because these types of security bugs are so common, many browsers will implement a sandbox. This is a protection mechanism that attempts to isolate a compromised browser process and prevent it from causing further harm. The way the sandbox works depends on the browser. Firefox has very limited sandboxing, whereas Chrome and Edge have significant sandboxing. However, despite this defense in depth, browser vulnerabilities can often be combined with sandbox escape vulnerabilities.

  • 18
    Thats exactly the point: Javascript itself is not "unsafe" (in terms of harming the pc - for webapplications, Javascript can be a big challange). Problem is, the increase in complexity, functionality and pure size of browsers is huge - within a few years browsers grew from simple html-display-tools to OS-like software. So its very likely that there are and always will be vulnerabilities in the browser which can be exploited through Javascript. Another point: plugins. Written by "someone" but excuted by the browser, so you have additional surface for vulnerabilities. – Alex Nov 30 '18 at 7:06
  • 1
    @forest There is a difference between the sandbox provided by the OS and the sandbox provided by the browser. The first one may be utilized by the browser. But if an OS sandbox e.g. offers access to any file on an FAT32 partition, that doesn't mean that the browser will allow JS to read it. E.g. firefox will still run JS in a restricted environment, but it may not use the OS to provide (additional) protection. – Maarten Bodewes Nov 30 '18 at 7:15
  • 1
    "Firefox has very limited sandboxing, whereas Chrome and Edge have significant sandboxing": interesting, I would like to know more about this. For example, this answer states the opposite. Do you have any source? Or should I ask another question? – Fabio Turati Nov 30 '18 at 22:15
  • 2
    @FabioTurati That answer is incorrect. The sandboxing in Firefox they speak of is designed to prevent individual crashing tabs from crashing the whole browser, not isolating compromise. For example, Chrome/Chromium sandbox the GPU, whereas Firefox does not (last I checked). Firefox (on *nix) uses jemalloc with 4 MiB heaps which makes heap spraying attacks to disable ASLR easier, whereas Chromium does not. Firefox's PresArena is also inferior to Chromium's PartitionAlloc. Firefox has testing done on it, whereas Chromium is working on CFI and has hundreds of cores fuzzing it 24/7. – forest Dec 1 '18 at 2:19
  • 3
    Also note though that JavaScript inside of the browser can always be "malicious" and do "malicious things" as it is a Turing-complete language. However, it depends on how you define "malicious". It can e.g. easily open popups ("adware") or display similar items inside of the browser window. Malicious JS can also steal your login credentials if injected into the site via ads e.g. Of course JS "breaking out" of the browser is a different way of being "malicious" though. – rugk Dec 2 '18 at 18:53
49

How is it safe?

It is not. Or more exactly it is as safe as the browser implementation is. Browsers (including their JavaScript engine) are complex pieces of software, with regular addition of new features - because users want them.

That means that, even if well-known ones certainly have quality procedure to test their code against known vulnerabilities, the risk of an undetected flaw in implementing a feature always exists.

Currently, the accepted way is that as soon as a breach is detected, a new version containing a fix is released. But between the discovery of the breach and the installation of the fix, the browser is vulnerable.That is the reason why it is recommended to keep one's browser up to date, in order to only be exposed to zero-day vulnerabilities.

  • 4
    Well… "nothing is 100% safe". As such, you can answer "It is not." to everything. I think the OP really wants an answer considering practical/realistic aspects. You do e.g. not even mention sandboxes and other features browser's had built-in for a long time. – rugk Dec 2 '18 at 18:45
  • 2
    @rugk: sandboxing is just to tool to try to protect the system from malicious code, and it is efficient... until an attacker finds a vulnerability! That is the reason why I prefere to insist on keeping a browser up to date than on the various tools used to secure it. – Serge Ballesta Dec 2 '18 at 22:56
19

It's true that at the JavaScript level the browsers are designed to sandbox the code under execution (primarily by not exposing any dangerous API), but JavaScript is a very complex language to parse and execute.

ECMAScript is the standard behind JavaScript, due to the huge marketing inflation around beginner-friendly programming languages we are experiencing today, the ECMAScript is updating fast and introducing more and more complex functionality to implement for a runtime.
This, in turn, widen the surface of attack and allow bugs to creep in.

A wonderful example is the recent work of Patrick Biernat, Markus Gaasedelen, Amy Burnett for the pwn2own 2018.

http://blog.ret2.io/2018/06/05/pwn2own-2018-exploit-development/

The blog describe the discovery of a 0day that allows arbitrary code execution in WebKit and how that's used to exploit another 0day in the macOS Window Manager to escape the sanbox Safari is running in (that's a macOS sandbox, not a Safari's one) to escalate to "root" and own the system.
Long story short, by simply visiting a link while having JavaScript enabled, a macOS system can be totally compromised without a single glitch visible to the user.
That's how safe JavaScript can be: As safe as a complex piece of software as WebKit's JSCore can be.
That's why users that require high security are advised to disable JavaScript (that's a fairly common requirement in the DarkWeb, for example).

The vulnerability in WebKit discovered by the authors above is a race condition between the newly introduced garbage collector and the array.reverse function: if the GC starts marking an array while it is being reversed it could lead to a UAF (Use After Free) exploit. The mark is done sequentially on the array, suppose the GC is right at the middle of the array when this is reversed, then second half is never marked and thus elected for collection, resulting in a UAF (the array object itself is not collected, only its element).

How an UAF is used to make more powerful exploit primitives that can lead to arbitrary code execution is more or less a variation of the same techniques: first an interesting object is allocated in the newly freed space (e.g. an array) then a RW primitive is created (e.g. by altering the boundary of the array) and finally arbitrary opcodes are written in memory (e.g in a JITted page).
The details for this particular 0day are in the linked blog.

The interesting part is the way this 0day was found: since WebKit is so big an in depth code review is impossible without an huge amount of effort so and automated jitter was set up.
This must make us reflect on the fact that when we have hundred thousand or millions of lines of code, it's very hard to make each one behave nicely with respect to every other one.

9

As stated in other answers, each browser has its own script engine that is designed to sandbox JavaScript execution and each engine attempts to limit JavaScript functionality that could lead to malicious behavior.

But as a rule JavaScript has never been safe within the browser. Malicious code developers are constantly finding ways to exploit how each engine works as well as its available JavaScript functionality to achieve malicious goals.

In the first few years, JavaScript was rather dangerous within the browser. Now it is a constant race between malicious code developers and the browser/engine developers and eventually the malicious developers always win, even if just for a short time. So JavaScript can hardly be called safe. "Should be safe for now" is a more accurate way to put it.

8

JavaScript is pretty powerful

It is which is why many users consider it unsafe and block it using browser extensions. JavaScript allows websites to track users in ways not possible without it including identifying users after they have deleted their cookies by fingerprinting the browser. Many of the newer web APIs like WebUSB allow things that are not at all safe but browsers will request user permission when accessing unsafe APIs like USB and camera.

  • Exactly! That's why I use NoScript for Firefox. Have for years. – Mike Waters Dec 3 '18 at 22:54
  • I believe all browsers ask before letting Website access the microphone, camera, GPS... – curiousguy Dec 18 '18 at 6:19
  • 1
    @curiousguy There are still a plentiful number of JS APIs that don't need permission that can be used in combination to identify you such as battery API – Qwertie Dec 18 '18 at 23:11
  • @Qwertie Yes, the Mozilla FF team just claims to be privacy conscious. They let a trivially obvious way to check whether a link was :visited, without even JS, be usable for years. They just don't really care! – curiousguy Dec 18 '18 at 23:37
4

There is nothing inherently safe about JavaScript, in many ways it is less safe than other languages:

  • eval statement
  • dynamic typing

It is the sandbox where the browser executes the JavaScript that provides the safety. See documentation on the Chrome sandbox here, notice there is no reference to JavaScript or ECMA script.

Today, the great majority of code executing in the browser is written in JavaScript. With the rise of WebAssembly, we will likely see the browser platform switch from the primarily single language lock in of today (like a mainframe of the past) to an open platform where any WebAssembly compliant language can be used. This will, in a way, prove that JavaScript isn't particularly safe/special, as at that point many languages will be executing in the browser. All of these languages will use the sandbox provided by the browser to execute.

  • The eval statement doesn't really make things less safe in this case. Eval poses a threat when an attacker is able to pass unfiltered strings to it, thus allowing them to run arbitrary code on the target system. In this case, the attacker is the one who wrote the Javascript and the target system is the browser on which it runs. The attacker is already running arbitrary code on the target system, and the question is how secure the sandbox is. – Ray Dec 4 '18 at 0:16
3

It is safe compared to machine-level executable code, like ActiveX uses.

A machine code program has unmitigated access to any interface the operating system and libraries provide to any program running under that user account, is only REALLY restricted in what it can do by what the hardware and operating system restrict it to - essentially making such a program as powerful as the user running it. There might be tools that try and restrict it by intercepting some of the interfaces provided, but it is hard to stop a program aware of such measures to circumvent them.

The javascript interpreter is part of the browser, and written in a way that it only offers the program it is running the interfaces and powers it wants to offer them.

  • 1
    But JavaScript can be compiled and run as machine code. In fact it usually is. – forest Dec 3 '18 at 7:16
  • 1
    With a compiler that is controlled by the USER, not the DEVELOPER. – rackandboneman Dec 3 '18 at 9:11
  • 1
    True, the JIT compiler does limit the bytecode it can spit out. – forest Dec 3 '18 at 9:15
3

JavaScript is "relatively safe," but not "absolutely safe." Any code you run on your system has a potential to do harm. There is no perfectly safe system, except for the one that never used. JavaScript is safer than putting an unknown USB device in your computer, and safer than a binary you download from a shady website or get in a suspect email attachment, and much safer than some of the scripts you'll find on websites that tell you to copy-paste them in to your shell.

It has safety features: a sandbox to help isolate the process, a relatively limited API that has security constraints to help avoid running arbitrary computer instructions, and security controls meant to limit exposure of sensitive data like fingerprints or cross-domain data sharing. These are on top of your operating system's controls applied to the browser binary to limit bad behavior, and anti-virus applications that can help stop such attacks.

However, it is not absolutely safe. Bugs in the browser's runtime engine, the browser itself, the anti-virus, or even the processor itself can all compromise JavaScript's security. The system is only as secure as its weakest security. The security of JavaScript is mostly meant to prevent "casual" exploits (such as an 8-year-old learning JavaScript for the first time and accidentally writing an exploit), but doesn't stand a chance against dedicated attackers. JavaScript is complicated enough that there are bound to be bugs, perhaps in weird and unexpected ways.

Those experienced in hacking, pen testing, and security can, and do, browse through source code, debug executables, and do whatever else they can to try and find chinks in the armor. The weak points of the JavaScript implementation. And JavaScript is big enough that such chinks exist to begin with, since it is virtually impossible to even automate all the possible tests that would find these bugs.

Generally speaking, any typical script you might run in to on a typical website is probably "safe", especially those linked to by major search engines. However, once you start going off the beaten path, it is incredibly likely you'll get your system compromised at some point if there's even a single weak point. It only takes one really good exploit, or sometimes two or three in tandem, to completely take over a system.

As it is, only enable JavaScript for sites you trust (I personally use NoScript for this purpose), always keep all your software up to date, and always pay attention to browser warnings like invalid certificates and so on. Even then, you won't be 100% safe, but you'll be taking an active part in your own mitigation strategy.

2

This answer will address two points raised at the question and one browser "feature" not raised in the question.

JavaScript has certain limitations such as preventing reading and writing to disk

such limitation does not technically exist at Chromium/Chrome browsers where requestFileSystem is defined, which writes directly to disk; that is, the File System folder of the Chromium/Chrome configuration directory at the users' file system.

See How to Write in file (user directory) using JavaScript?

and not allowing access to other browser windows or domains.

If a window is opened from an already opened window, communication between windows is possible using, including, but not limited to, postMessage, MessageChannel, SharedWorker, or simply query string parameters.

See How can I load a shared web worker with a user-script?


One other point not mentioned at the OP that must be raised here specific to Chromium/Chrome is the fact that the SpeechRecognition implementation of Web Speech API at those browsers records the users' voice (biometric identifier) and sends that recording to a remote service, without directly advising the user that is what is taking place. It is not immediately clear if the recording(s) are retained (forever) by the undisclosed "web service" or "deleted" at some point.

See Does webkitSpeechRecognition send recorded audio to a remote web service by default?

-3

It's safe because it was designed to be safe. Or at least it's safe to the point where a less than formal "JavaScript is pretty powerful" does suggest the it's probably sufficiently safe to reassure you. In practice, no piece of software is perfectly safe, so it's a matter of degree. Javascript is safe enough that most corporations are willing to let employees visit websites using company hardware.

JavaScript is designed to prevent attackers from gaining access to your files or any private information. For example, it has support to prevent a script on one site from looking at data from another site (known as a cross-site attack).

Of course, this is not perfect. There was a recent scare with Spectre and Meltdown, a pair of exploits which relied on a flaw in some processors to break free of the sandbox JavaScript runs in. That had to be patched with some rather ugly software hacks to cover for the flawed processors.

But in general, it is "safe" to execute such scripts because lots of security experts have spent a lot of time making sure that feeling of safety is justified. But it all depends on your threat model. If you had billions of dollars on the line, you might not even want to trust JavaScript's safety!

So the real question is what is your bar for "safe?" Do you consider Windows to be safe? What about Internet Explorer? Adobe Acrobat Reader? OpenJPEG? The Linux kernel? OpenSSL? Safety and usability are always at odds. You have to use something (or maybe you don't. The Amish haven't been hit with a 0-day yet... unless you count a new strain of Influenza) To really understand if you can call something "safe" or not you need a threat model, defining how someone might attack you, and a usability model defining what usability you need to achieve while mitigating the threat model. Without those, we have to read into your words and your history to guess what "safe" means.

  • 3
    To downvoters: an explaination for why you think this correct answer should be downvoted would be appreciated. – Cort Ammon Dec 2 '18 at 17:37
  • 8
    I downvoted because you overestimate the security of JavaScript by a large margin, especially when each and every release of a new browser is needed to fix numerous newly discovered vulnerabilities in the JS engine. The fact that a JS exploit can be purchased for around $30k in some countries shows that it's far too optimistic to assume that it's so safe that it takes a billion dollars of assets for it to be worthwhile to break. Your original premise, that JavaScript is "safe" because it was designed to be safe, is incorrect. – forest Dec 3 '18 at 3:16
  • 4
    I downvoted because it begins with the affirmative statement "It's Safe" which is untrue. It's only relatively safe, as you go on to point out. – Ben Dec 3 '18 at 11:54
  • @Ben Thank you. That explains a lot. I've added text to point out why I called it "safe," which was with respect to the bar it appeared the OP was drawing. – Cort Ammon Dec 3 '18 at 16:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.