One of our security engineers discovered a remote code execution vulnerability in the Symbol desktop wallet and reported the vulnerability through their bug bounty program. Given the nature of the issue, the Symbol team took immediate action to update their code, and a fix was deployed in the v0.9.11 release.
Though the HackerOne report is not yet public, we give many thanks to the Symbol team for allowing us to disclose and share our findings.
The Symbol wallet is an Electron-based desktop application, and the vulnerability we found was in the Electron configuration itself. Before jumping into the finding, let’s briefly review what Electron is and the security aspects of its application.
There are a couple benefits to using Electron:
Electron-based applications are essentially web applications, so they contain common web vulnerabilities such as cross-site scripting (XSS), SQL injection, and authentication and authorization flaws.
To check whether Node.js is enabled in the Electron application, users can send the module import function
require in the development console. The development console can be opened with “option+command+i” on macOS.
If Node.js is disabled, the console will return an error message, “require is not defined”, as seen in the following screenshot:
But if Node.js is enabled, users will see the following:
For an example of how this would work, you can try sending the following command in the development console to open the calculator program in macOS:
nodeIntegration to true in the build configuration file (though this is not recommended!).
Note that in 2018, a critical vulnerability was also discovered in Electron that allows attackers to re-enable Node.js integration at runtime, which would potentially lead to remote code execution. This blog explains more in detail. The point here is that it’s important to keep your application up-to-date with the latest Electron framework release.
Now that we know one of the items to look for when testing an Electron-based application, let’s dive into the vulnerability we discovered in the Symbol wallet.
The Symbol desktop wallet is open-source, and the source code for the application can be found in their Github repository.
The build.js file is the Electron build configuration file for their application. The code snippet below checks if the application runs on Darwin (macOS); if not, app.on creates a new browser window with the
createwindow function, the
windowOptions variable inside the function contains browser window configuration options. Notice the line highlighted in red—the
nodeIntegration variable is set to true, which enables Node.js in the Electron application:
Luckily for us, the Symbol desktop wallet (release v9.7) provides a feature to view “News”. Once the user clicks a link in the news feed, the application will navigate away from the wallet interface and loads the external website (Github, in this case) inside the current window.
To demonstrate, you can host the code snippet below on your website; it will be a trivial task to inject the URL to a website over Github. With
After the user visits the infected page and clicks the “Close” button, the calculator will open on the user's computer. The calculator itself is harmless, but in this example, the fact that it even opened in the target system means that the application was vulnerable and successfully exploited.
To see the exploit in action, check out the proof-of-concept video: https://www.youtube.com/watch?v=X5R2xC3Jcy0
Proof-of-Concept code snippet:
This example presents the steps of the exploit pretty obviously; the payload requires the user to click the button to trigger the system command. In reality, an attacker may host a malicious script that triggers the system command execution automatically and inconspicuously when users visit the page.
Symbol resolved the issue that we detected by setting
As a security researcher, when you exploit a vulnerability in one application, you always want to see if the same type of vulnerability exists elsewhere. With just a quick search, we found another notable Electron-based cryptocurrency wallet: MyCrypto.
At the time of testing, we discovered MyCrypto had
nodeIntegration set to true and Node.js enabled. Though we didn’t find a way to exploit the vulnerability with cross-site scripting or arbitrary page redirection inside the application, we know best practice is to prevent hackers from turning “self-xss” into a command code execution.
True to our and CertiK’s core values, we reported the issue to MyCrypto as well via their Github repository: https://github.com/MyCryptoHQ/MyCrypto/issues/3261
After we reported the issue, MyCrypto stated the vulnerability will be fixed in the next release.
With the time we spent learning the ins-and-outs of the Electron framework, we’ve put together a quick list that you can reference to improve the security of Electron-based applications:
nodeIntegrationto false unless the application absolutely requires it.
Additionally, performing security audits and penetration tests, whether by an internal security team or third-party firm, are important to ensure the security of your system. Security professionals will attempt to break the system with a malicious hacker’s mindset, helping identify and remediate vulnerabilities before a bad actor exploits them.
CertiK is deep-rooted in academia, but our strength is in taking the research that’s available and applying them to real-world situations. We aim to provide value with our security-first philosophy through the use of rigorous techniques, creative thinking, and adaptability. It is our goal and responsibility to contribute to the crypto & blockchain community and help companies secure their users’ assets for a more secure experience.