Discord Desktop App RCE
mksben.l0.cm
mksben.l0.cm
9:21 PM on July 16, 2020 we received a very detailed report from Masato outlining this exploit.
9:34 PM: Ticket acknowledged - and we began a deploy that would disable sketchfab embeds within the app, to remediate this known attack vector.
10:00 PM: Update pushed to stable to disable all existing sketchfab embeds.
Thanks to the detailed report, we were able to go from a report to a fix deployed to stable in ~40 minutes!
Following that, the next day we deployed a better update as we understood more about the issue (which was the sandbox attribute on the iframe.) In addition, we also paid out $5,000 for this bounty, even though the main fault that lead to RCE was due to a bug in Electron (CVE-2020-15174) which allowed for a bypass of our CSP, by allowing the main window to be navigated to a different domain.
----
As for context isolation, a lot of the code that had been written was not compatible with contextIsolation - and required significant work to refactor. For example, due to the way that objects needed to be cloned to pass through the bridge, the internal APIs that existed needed to be entirely reworked, as they were not really compatible with this model. We began this work in April shortly after we worked out all the quirks required to upgrade to Electron 7 which is when contextBridge would be available for us to turn on contextIsolation. It was not as simple as flipping a boolean from false -> true, and required a re-work of our native modules and their internal APIs, and also doing so in a way that would be backwards & forwards compatible with the various app versions that we had shipped in the wild - in addition to dealing with some performance regressions that needed work-arounds in the new context isolated world.
In August, we shipped context isolation to our Stable release channel and gave Masato the green light for disclosure - which leads us to today!
> In addition, we also paid out $5,000 for this bounty, even though the main fault that lead to RCE was due to a bug in Electron
You seem to imply that because the bug was in a library that you use as opposed to code your own developers wrote, that it's gracious of you to even pay out $5000 for this bounty. Surely that's not actually what you're saying and I'm merely misunderstanding you? Regardless of who wrote the bug, Discord ships the binary and the impact of the vulnerability remains the same.
Our bug bounty page on H1 (invite only currently) lists critical vulnerabilities at $3,000 for a bounty, we decided to up the pay-out to $5,000 for the thorough report on the exploit - even though the vulnerability was not in our code, we paid extra (from our perspective...) because the vulnerability did after all ship in our software.
I compared this to similar payouts for RCE's, for example, slack paid out $1750 for a similar RCE earlier this year, due to lack of context isolation (https://hackerone.com/reports/783877) - although this did get published after we paid bounty - so it did not influence our decision.
Clearly there is some discussion to be had about what is fair. For context (which might be missing), this was not a 0-click drive-by RCE, and to exploit involved 4-clicks you had to be sent the embed, (1) click the "play" button to launch the iframe [we never load iframes with 0click], (2) click play within sketch-fab to load the 3d model, (3) click a small "1", and then (4) click a "+" in the tooltip that pops up in order to trigger the exploit. I'm curious if anyone has prior art or opinions on what would be a more appropriate bounty?
What is the cost in the exploit being used in the wild?
What is the cost of the PR shitstorm that would come your way?
How much business could you lose? Customer confidence?
Is this an exploit that could be devastating to your continued operations? Would it lead to legal action? What are your duties to inform customers/users/legal bodies? Will there be any fines involved? You may need to retain an expert PR firm to handle the communication to the world to put a good spin on the story, another cost. Did you breach GDPR? Does the data that could have been leaked reveal business practices you'd rather keep secret? Is there any kind of internal risk of leakage? How far does the exploit go? Can it be combined with other exploits that could be used to gain access to internal systems?
The industry has collectively decided that exploits have a value and I'm not sure these factors are taken into account. You should look at examples of companies that have suffered an attack and look the damaged caused (for example, Experian, Blackbaud come to mind) to understand the impact it can have.
How much does it cost to have a CEO tweet the stock price is "too high imo" and causes a dip? That may cost him potential investors to think again.
Of course, you can't know that person who was just about to give you $50,000 worth of business decided not to because of how you handled the situation but it's always a possibility.
I know I've made (small) decisions like this because I didn't like how it was handled or didn't agree with some of the details, and I no longer consider myself a possible customer as a result.
Discord is valued at several billion dollars, and their last funding round was over a hundred million. They are a key component in the lives of at least a hundred million people. Given this, $5,000 is, in my opinion, negligible, and the proper payout would have been at least double.
Given that Discord permanently stores so many chat logs, personal information, analytics, etc, there should be no higher priority than maximizing security and user trust, and $5K would make me, as a potential user, think it's a second priority.
> 9:34 PM: Ticket acknowledged - and we began a deploy that would disable sketchfab embeds within the app, to remediate this known attack vector.
Did you have time to verify the claims in the bug report in this short window?
I work at a very small company, so small that a security researcher would never accidentally stumble on our products to test them and if my boss asked me what would be an appropriate pay out for this, I'd say easily $25k, but more likely 30-35k if we can afford it.
What you guys have accomplished here is set a precedence that you pay so little that researchers should either a) not bother with discord or b) should sell on the darknet.
As a discord app user, I'm very concerned about both of those cases.
Imagine if a food company was like, "Oh, well, the marble dust sold to us as flour was from a supplier so we're not really responsible."
> even though the main fault that lead to RCE was due to a bug in Electron (CVE-2020-15174)
This may seem like an irrelevant detail if you’ve never operated a bug bounty program before, but you have to consider the incentives.
Paying researchers for bugs in 3rd-party open source software creates misaligned incentives. If you’re a security researcher and you discover a security bug in Electron, you have two choices:
1) Follow proper protocol to create a CVE, coordinate a fix, and properly disclose the issue through appropriate channels.
2) Keep the vulnerability secret and unfixed while you shop it around bug bounty programs looking for kind companies who will pay out for 3rd-party issues. To maximize profits, it’s important that you keep the security issue unfixed and secret as long as possible while you work your way across bug bounty programs.
The second option is a little publicized negative externality of bug bounty programs that don’t draw the line at 3rd-party dependencies. I’ve even had bug bounty participants beg us to not fix upstream code yet because they were still trying to collect bounties from other companies.
This is also why it’s important to have your security team read every CVE immediately and check against your software. It’s also why bug bounty programs don’t pay out as much, or even at all, for security issues that come from popular 3rd-party dependencies used across the industry.
I see nothing wrong with submitting it in multiple places, it's still better then being sold darknet.
If I get hacked and find out Discord was the vector, I'm not going to let them off the hook when they shrug and say "3rd party code man, it happens". In the end, I'm a discord user, I don't want RCE exploits in software I use.
hope the OpenFeint 2.0 privacy scandal bursts soon. users had enough data stolen.
This is one huge lever to help with the maxime “XSS is RCE in electron” and yet they default to not helping.
I know this is about backwards compatibility, but they could easily have decided to throw if the property is unset. Security-minded people would have set it to true and dealt with the fallout, whereas others could have set it to false and shipped their update still.
But by defaulting to false, this security tool is hidden from both existing and new users. Old code will not even have the chance to get fixed and new code will be written in an insecure state.
I’m sure the release notes talked about this feature, but who reads release notes? Especially not past release notes (when starting fresh today).
The backwards compatibility cost of throwing and in the message even suggesting setting to false as an emergency out would have been minimal compared to the fallout this is causing.
> Getting everything to work in a context isolated world was a many month effort, which had begun long before this bug was reported to our team.
People wanting to do it the "easy" way (using scare quotes because turning any XSS into an RCE feels like hard mode to me) set contextIsolation to false and they are done.
Also consider newly created applications: when the limitations exist from the start, it's much easier to build this correctly (the same way it's easier to get to 100% test coverage if you start with TDD than if you have to refactor years of static methods and global state and implicit dependencies).
By having a default setting and having it default to insecure, even newly created applications will be unsafe and will require refactoring in the future.
[0] https://www.electronjs.org/docs/tutorial/context-isolation#w...
So I assign to textContent liberally, don't manipulate URLs as text, but via browser APIs, and avoid everything that allows code execution. It's really stupid simple to follow safe practices for absolute majority of apps.
And this makes writing a electron app with direct access to local PostgreSQL database trivial, fun, and makes writing useful apps without a separate HTTP backend a breeze.
I don't have a need to split privileged code out to separate process, and go back to acting like there's trusted/untrusted split, just like with regular website. Having to do that would kill all the allure of Electron, for me. I use electron precisely because I don't have to do this, and can depend on the HTML/JS code to be trusted.
That’s what C programmers tell me about memory management and buffer sizing.
And yet: https://www.zdnet.com/google-amp/article/microsoft-70-percen...
Thing is: even if you are careful, you only need to make a single mistake to lose everything.
Just like there’s is benefit in memory-safe languages, there is benefit in environments where a single .innerHTML instead of a .innerText doesn’t mean an RCE.
But that wasn’t really the point of my initial comment. Just as I can accept C programmers thinking they don’t make mistakes, I can accept you believing never making any mistakes either and thus I can even accept electron having a footgun mode.
What I took issue with wasn’t the general availability of such a mode but the fact that this mode is a silently chosen default.
Have people explicitly opt in or out of this safety feature. Don’t assume they want to shoot themselves in the foot by default.
That was my concern and this is the pet I hope we can all agree about.
That I personally also think that turning off context isolation should be impossible is another matter and not really part of this discussion and I’m even willing to accept that people could change my mind about that one.
But having an unsafe default is craziness in my book.
There's nothing unsafe about having context isolation off, per se. Yes, you can do stupid stuff like run code directly from the internet, but context isolation doesn't prevent that. It still allows RCE. It just limits the fallout to just stealing your data, like with any other XSS on regular websites.
And if programmers can't be trusted to not execute untrusted input as code in more secure context, adding an extra hop via some IPC will not save them, if they make the same mistakes in less secure context.
But I have to disagree with your point about reading release notes, this should be the expected behavior from developers working on the product, maybe not every single dependency but at least the main ones. Being an Electron app mainly, discord devs should’ve known and understood what they’re working with. Of course mistakes happen, but the main issue here is developers missed reading the docs properly, not whatever the default value is.
Unfortunately, the world disagrees - they really want to wrap websites using Electron, so now we need to default to options that make Electron apps far less compelling as a platform
that's only true for applications that strictly only ever work on and display content that the user has created themselves.
This is an increasingly rare type of application in the age of the internet and social media to the point where I would argue that most applications these days interact with data created by other users (think opening an image file, displaying a chat message, displaying an email, etc).
With Electron you're setting yourself up in a way where a single case of a forgotten input escaping automatically means a remote code execution attack.
On websites, XSS certainly are a bad thing, but they are still somewhat limited in scope and generic mitigations exists in many browsers.
In Electron apps, an XSS means an RCE unless you make use of features like `conextIsolation`.
Reading your comment makes it obvious to me that this isn't already a well-known issue. People generally aren't aware or believe their type of application to be immune and thus it would, and that's the point of my initial comment, make sense to either default to secure or at least default to asking the user to specifically make the decision to be insecure.
Defaulting to turning every XSS attack into an RCE seems to me like a very bad decision.
And most importantly in the browser I can have full ad blocking/tracking protections enabled.
In contrast, I often organize my browser tabs onto multiple separate windows (even when I don't have that many open), because opening programs in windows and jumping between them is something I do a lot, and it's baked in very nicely to my window manager :)
To avoid misinterpretation since text is horrible this way: I am NOT disparaging or even really disagreeing with the parent comment. They're just two different workflows, and while I appreciate the advantages of the browser, apps work better in mine.
Firefox recently learned --ssb (after you enable that in about:config), but it's use is much more limited, geared towards kiosks. Things like right mouse button and extensions are disabled, and you cannot open external links.
https://superuser.com/questions/101395/is-it-possible-to-hav...
https://www.howtogeek.com/403399/how-to-make-chrome-open-as-...
So it's like having an Electron app with stricter sandboxing, less memory usage, and an easier installation / upgrade process.
In case of Discord, there are three key causes for preferring the desktop version - and I don't see any easy workaround to them without adding explicit support to web standards:
1) custom audio codecs & filters; Discord is primarily a gaming VC app and the codecs available on the desktop version are superior for purpose of cancelling echo, noise etc. at low latency,
2) ability to capture any keyboard & mouse shortcuts for VC activation
3) ability to use voice & keyboard shortcut while the browser window is not focused (in particular while in game)
Incidentally adding general support for those to general browsers would lead to subtle security bugs & gotchas.
Why would a custom audio codec be noticeably better than browser supported ones?
This is extremely important because otherwise I don't think I'd be able to play a game in VM like Hyper-V and still talk to friends via Discord.
The only problem is that I have to run as admin the discord.exe that's hidden in its folder instead of that default Discord icon (updater.exe I guess?)
Also I just generally hate electron.
https://github.com/reZach/secure-electron-template
*contextIsolation is turned on in this template, so the RCE as described in the article is prevented.
They send a tracking request for every single thing you do in their client. Clicked on someone's profile, clicked on a channel, clicked on a server, etc. The URL was named /track before but they renamed it to "/events" and then recently "/science" (but it's still a POST with no response).
Also their desktop client is literally a remote administration toolkit, it has full access to FS (electron app) and it loads every script from their servers. On launch the desktop client opens websocket server for command and control listening.
They can just add something like require('fs').readFileSync(process.env.HOME + '/.ssh/id_rsa').toString() and send this to their servers, and you won't even notice that (since it doesn't require an update on client because the client is just a browser with full permissions that loads obfuscated code from their servers every time you launch it).
How is this at all surprising? Any non-open source program can do everything you just listen and more. Discord may have been dumb for naming their analytics request point "/track" but that doesn't make them worse than anyone else. I wouldn't be surprised if Word sent every button press to Microsoft. And besides, all the chat data is stored on their servers anyways, so it's not like they get a whole bunch of new data through this.
But in particular the problem is that it's web crap and it pulls down it's code every time you run it. And now with the websocket backdoor it doesn't even have to do that. This is very different from a compiled program.
It's not surprising but it is also not acceptable. I chose not to use it and encourage others to avoid it.
I wish people would stop touting this. Just because you pay for it doesn't mean you aren't being tracked. I would say MS Word is considerably worse because you have to pay for it and it still tracks you.
Every application that you run can do everything that you can do. You aren't just trusting Discord not to suck up your keys, you are trusting every application on your system, and maybe even the OS itself.
I prioritized moving to iOS the same day I realized that every application would be restricted to a sandbox. It'd be nice if every application on windows had to beg for permission to read outside of its own sandbox as well, but I doubt we will ever get there due to the sheer amount of legacy stuff hanging around.
Although it makes sense, I'm almost surprised Discord paid out given that biggest reason the RCE exists was due to the Electron top-level navigation bug allowing XSS despite Discord's existing mitigations in the first place.
A RCE is a RCE.
And who other than Discord would be poised to take charge and fix it? They need a desktop client almost like no other Electron user. Time to grow up and take some responsibility for the stuff you ship. Instead we have
$ git log --oneline --author "discordapp.com" | wc -l
7
They are building their business centerpiece software around something they don't understand and don't maintain.Discord didn’t set contextIsolation to true. Why? No idea. Would it have been enough if they did? No idea.
Getting everything to work in a context isolated world was a many month effort, which had begun long before this bug was reported to our team.
(The majority of this code was written before context isolation even existed :P)
Our video rendering implementation needed to copy frame buffers to the renderer. Doing this over context bridge would have been quite expensive.
A more ideal approach which the team is working on keeps the buffers on the GPU - which should solve all the performance woes and more.
More on this here: https://www.electronjs.org/docs/api/context-bridge
Reasoning: as a user I want my apps to be secure. Proportionate bounties do that.
Disclosure at this point is moot, you'd only look like an ass and probably wouldn't get the check.
What you're describing is more like a darknet marketplace when you describe the vulnerability in the fewest words possible and never giving up code until the Bitcoin deposit is confirmed. I seriously doubt most companies would deal with an individual like this, it's closer to blackmail than it is a bug bounty.
One of the touted advantages of Electron is that you can use web technologies and thus have engineers familiar with web technologies working on your application.
It’s very easy to see a web developer do what is perfectly fine on the web.
Heck, this feature might even have been added for their web client and then brought over to the electron version, possibly unbeknownst to the original author of the feature.
No. I wouldn’t call this a bug screwup. Just another effect of the footgun that is electron
Slack doesn't do anything so amazing that cannot be a portable Web application, with the browser I already have installed.
This is a dubious claim; not sure how long you've been developing for the web, but iframes have had many many exploits fixed over the years. That's neither here nor there though, as Discord purports to be a native application and therefore should be extra careful.
But on one hand we have an app made by a company valued at 2 billion $, with hundred of millions of $ in funding, made with a tech stack that is sold as the best thing since sliced bread, and on the other we have a one-person-show coding an app in C++/Qt in their free time, which is also compatible with Slack, much faster than the official Discord client, and which does not seem to have any CVEs reported against it (yet, of course, but still :-)).
At some point the supposed amazing development efficiency of the web stack ought to be put in that perspective.
> All 3rd party apps or client modifiers are against our ToS, and the use of them can result in your account being disabled. I don't recommend using them. - https://mobile.twitter.com/discord/status/122935719891819724...
They make their money by selling their users and they can't do that if they allow other clients. So they have their policy of not allowing it and banning all third party. Of course they only act when it begins to effect their money. So for now ripcord is usable.
If you're gonna continue with this anti-discord narrative you've built for yourself, at least don't base it on conspiracy nonsense: