Chrome Extension CORS Security Vulnerability (fixed in 2019)
In 2018 I found a simple exploit that abuses the way Chrome extensions use CORS headers, preventing extensions from accessing remote resources loaded arbitrarily at runtime. I didn’t report it but eventually Google fixed it a year later. Note that I’m not a security researcher and not particularly sure why this bug exists, but simply found it by trying to get code execution through remote requests.
Background
In manifest v2, chrome extensions basically run loaded into your browser with a popup.html
file (the window that appears when you click the extension icon, if it’s enabled) and an optional background.js
file (a script that runs in the background of webpages you load). The vulnerability surrounds the way the browser’s local storage interacts with popup.html
and background.js
.
Attackers can abuse this exploit to not only execute obfuscated Javascript which the Chrome web store automatically rejects if detected in the extension when uploaded, but also arbitrarily execute remotely hosted code.
The exploit
If you try to make a web request for remotely loaded Javascript on the background page itself (the target), you’ll get a CORS
violation and won’t be able to load the remotely hosted resource. However, you can make a HTTP
request for the contents of the Javascript resource from popup.html
, load it into local storage and then call exec()
and execute it in background.js
. In other words, for whatever reason popup.html
however bypasses CORS and lets you do this. I believe the fact that localstorage
is shared is intentional, however.
In practice this means you can not only remotely execute code, but obfuscate your code which normally the Chrome web store blocks (because it’s loaded at runtime) and execute all your background.js
code completely remotely.
I found this when I was trying to see if I could get a remote-update system for my ~780 user chrome extension, and yeah it works (but oh boy can this be misused).
The solution
There is no reason background scripts should be able to call exec
, or even access localstorage
. Simply disabling either of these patches the exploit. Adding CORS
headers to popup.html
also works.
I didn’t publish this exploit, but Google fixed it in 2019 so they must have known about it. They removed the ability to make cross origin requests in content-scripts. In practice when I tested this popup.html
now has CORS headers so you can’t just request arbitrary data.