Why Electron apps can’t store your secrets confidentially: ` — inspect`option

Use web apps and PWAs whenever it’s possible. Stop using Electron for any confidential things.

This is a continuation of the first post about security in Electron apps.

`— inspect=port` to steal all your secrets.

Try to invoke any Electron app with —-inspect

/Applications/Signal.app/Contents/MacOS/Signal --inspect=9229

You’ll probably notice some strange output to stdout, like that

Debugger listening on ws://127.0.0.1:9229/e74f58cb-a940-456e-a57e-fb0a1821b778For help, see: https://nodejs.org/en/docs/inspector

What’s this? This is a debugging server, which allows executing arbitrary code on behalf of the app. Sometimes, developers forget to disable the debugging server in production, and it leads to nice bugs like this one in VS Code.

Now, go to chrome://inspect in your Chrome and click inspect near “Signal” label. Alternatively, you could connect to the debugging server with CDP.

Switch context to “Electron Main Context”

Execute this PoC in the REPL:

process.mainModule.require('child_process').execSync('/System/Applications/Calculator.app/Contents/MacOS/Calculator')

This command asks Signal to start a new Calculator process.

What’s the impact here?

A local application can execute code on behalf of any installed Electron app to disclose application secrets, data, bypass firewall rules, etc.

theevilbit correctly pointed that it’s also a TCC bypass issue:

2. It’s also a TCC bypass issue. Apps granted access to certain privacy sensitive locations, which not every app has. If you can run code on behalf of an app that was granted e.g. full disk access, you get that with this. So yes, this is a problem.

You can PoC this on Slack, WhatsApp, Signal, any other Electron app.

Feature or bug?

Some products abuse this feature to run UI tests. Thus, it’s unlikely this feature will be removed or deprecated any time soon.

macOS apps should have a specific entitlement to be debuggable in production. Try to debug some secure apps (e.g. CleanMyMac) with lldb as root and you’ll notice SIP disallows this to prevent LPE.

It’s up to decide how to interpret this functionality. But try to answer these questions before saying it is expected behavior.

  • Why did library validation become a part of Apple notarization process?
  • Why only Electron apps have “debug-me-how-you-want” interface, and other macOS apps don’t?
  • Why can any local process instrument the Electron app?
  • Why may this be escalated to LPE sometimes?
  • Is it a “game over”, if you can control process arguments? (lol, say these to guys working on LPEs 24/7)

Response from affected products

I reported this to WhatsApp, Slack, MS, and some crypto wallets. Their response was like: “uh, you know, it’s an electron feature, we don’t really care.” As usual, nobody cares.

codecolorist suggested leveraging --inspect for LPE in Keybase in this report

Abuse trusted Electron to load evil library and run the exploit.

Keybase gui is based on Electron, which has built in debugg option like — inspect=[port] or — inspect-brk=[port]
Then it will expose the debug protocol on localhost that can be interacted via WebSocket
Through this debug protocol

We should NEVER trust such script language interpreters like Electron, node.js, or even lua or something.What devs say?

Chrome is affected too

  1. Run chrome with --remote-debugging-port=$PORT option: /Applications/Google\ Chrome\ Canary.app/Contents/MacOS/Google\ Chrome\ Canary --remote-debugging-port=9229
  2. Now you can debug your chrome from another chrome
  3. Google Chrome explicitly declares that local (malware) attacks are out of the scope of their threat model. However, Electron doesn’t warn developers of crypto wallets and messengers about it.

Some people install local apps for enhanced security, but with Electron, they receive an app with a worse security posture compared to what Chrome can offer.

Common Electron bugs aka (best bug bounty tricks)

  • Many apps try to prevent JS code execution by disallowing navigation to untrusted origins.
  • Always check Electron version
  • Drag’n’Drop behavior is enabled in Electron by default
  • Local file reading is possible in Electron apps because Electron serves file:// resources with a wildcard CORS. — https://hackerone.com/reports/390013
  • Check shell.openExternal and shell.open
  • use--inspect to start Electron apps in debug mode
  • Some production app may run debugging server on the start