diff --git a/src/pentesting-web/browser-extension-pentesting-methodology/README.md b/src/pentesting-web/browser-extension-pentesting-methodology/README.md index b27c8d8aa32..6ded1a58fea 100644 --- a/src/pentesting-web/browser-extension-pentesting-methodology/README.md +++ b/src/pentesting-web/browser-extension-pentesting-methodology/README.md @@ -375,6 +375,69 @@ The **less extensions and URLs** indicated here, the **smaller the attack surfac > > Moreover, if the client installs a rouge extension, even if it isn't allowed to communicate with the vulnerable extension, it could inject **XSS data in an allowed web page** or abuse **`WebRequest`** or **`DeclarativeNetRequest`** APIs to manipulate requests on a targeted domain altering a page's request for a **JavaScript file**. (Note that CSP on the targeted page could prevent these attacks). This idea comes [**from this writeup**](https://www.darkrelay.com/post/opera-zero-day-rce-vulnerability). +#### Wildcard-trusted web origins to privileged action injection + +If an extension exposes a **high-privilege message handler** to the web via `externally_connectable`, avoid trusting a broad pattern such as `https://*.example.com/*`. A single **XSS**, **subdomain takeover**, or **vendor widget compromise** on any matching subdomain becomes equivalent to owning the extension's web-facing API. + +Typical exploitation path: + +1. Find the extension ID and enumerate `externally_connectable.matches`. +2. Identify a message type that triggers a **privileged action** (`open tab`, `read page`, `submit prompt`, `fetch with extension privileges`, `native messaging`, and so on). +3. Get JavaScript execution in **any** trusted origin. +4. Send the request directly to the extension: + +```javascript +chrome.runtime.sendMessage("", { + type: "privileged_action", + payload: { attacker: "controlled" }, +}) +``` + +This is especially dangerous in **agentic extensions** or assistants because the "message" might be a full **instruction prompt** that is executed with the extension's host permissions. + +> [!CAUTION] +> Treat **vendor code hosted on a first-party trusted subdomain** as part of the trust boundary. If `captcha.example.com`, `cdn.example.com`, or a support widget origin is allowed by `externally_connectable`, an XSS in that third-party component can pivot into the extension exactly as if the bug existed on the main application. + +#### Auditing `chrome.runtime.sendMessage` / `onMessageExternal` trust + +When reviewing a browser extension that accepts messages from web pages: + +- Search for `chrome.runtime.onMessageExternal.addListener`, `chrome.runtime.onConnectExternal.addListener`, and sensitive handlers reachable from those listeners. +- Verify the extension performs **exact origin equality** checks on the sender instead of suffix, regex, or wildcard matching. +- Verify the handler authorizes **message type + origin** together. A safe origin for telemetry or onboarding is not automatically safe for privileged actions. +- Confirm the extension does not trust a subdomain just because it shares the parent eTLD+1. +- Check whether any allowed origin hosts **third-party JavaScript**, **user-generated content**, or **legacy static assets**. + +Bad patterns: + +```javascript +if (sender.origin.endsWith(".example.com")) { /* trust */ } +if (/^https:\/\/.*\.example\.com$/.test(sender.origin)) { /* trust */ } +``` + +Prefer strict matching to the minimal set of origins: + +```javascript +if (sender.origin !== "https://app.example.com") return +``` + +#### Rollback hunting on trusted static assets + +If the trusted origin serves **versioned static assets** or embedded widgets from predictable paths, try walking older versions looking for still-reachable vulnerable builds. This is useful when the current version is patched but the extension still trusts the origin hosting archived assets. + +Common patterns: + +- `/assets/widget/1.26.0/index.html` +- `/static/app-2024.12.1/` +- `/cdn/component/v1234/` + +Practical checks: + +- Start from a version observed in network traffic or page source. +- Decrement semantic versions / build numbers and request older paths. +- Look for `200`, `301`, or cache hits on old builds. +- Review older JS bundles for DOM XSS, unsafe message handlers, or gadget endpoints that can re-establish JavaScript execution on the trusted origin. + ## Communication summary ### Extension <--> WebApp @@ -743,6 +806,8 @@ Even though Browser Extensions have a **limited attack surface**, some of them m - [ ] Use a **strong** **`content_security_policy`** - [ ] **Limit** as much as possible the **`externally_connectable`**, if none is needed and possible, do not leave it by default, specify **`{}`** - [ ] If **URL vulnerable to XSS or to takeover** is mentioned here, an attacker will be able to **send messages to the background scripts directly**. Very powerful bypass. + - [ ] Reject wildcard or suffix trust such as `*.example.com` for **privileged** external message handlers. + - [ ] Review whether any allowed origin serves **vendor-hosted widgets**, **user content**, or **versioned legacy assets** that could restore code execution on a trusted subdomain. - [ ] **Limit** as much as possible the **`web_accessible_resources`**, even empty if possible. - [ ] If **`web_accessible_resources`** is not none, check for [**ClickJacking**](browext-clickjacking.md) - [ ] If any **communication** occurs from the **extension** to the **web page**, [**check for XSS**](browext-xss-example.md) **vulnerabilities** caused in the communication. @@ -798,9 +863,11 @@ Project Neto is a Python 3 package conceived to analyse and unravel hidden featu - [https://palant.info/2022/08/31/when-extension-pages-are-web-accessible/](https://palant.info/2022/08/31/when-extension-pages-are-web-accessible/) - [https://help.passbolt.com/assets/files/PBL-02-report.pdf](https://help.passbolt.com/assets/files/PBL-02-report.pdf) - [https://developer.chrome.com/docs/extensions/develop/concepts/content-scripts](https://developer.chrome.com/docs/extensions/develop/concepts/content-scripts) +- [https://developer.chrome.com/docs/extensions/reference/manifest/externally-connectable](https://developer.chrome.com/docs/extensions/reference/manifest/externally-connectable) - [https://developer.chrome.com/docs/extensions/mv2/background-pages](https://developer.chrome.com/docs/extensions/mv2/background-pages) - [https://thehackerblog.com/kicking-the-rims-a-guide-for-securely-writing-and-auditing-chrome-extensions/](https://thehackerblog.com/kicking-the-rims-a-guide-for-securely-writing-and-auditing-chrome-extensions/) - [https://gist.github.com/LongJohnCoder/9ddf5735df3a4f2e9559665fb864eac0](https://gist.github.com/LongJohnCoder/9ddf5735df3a4f2e9559665fb864eac0) - [https://redcanary.com/blog/threat-detection/assemblyline-browser-extensions/](https://redcanary.com/blog/threat-detection/assemblyline-browser-extensions/) +- [https://www.koi.ai/blog/shadowprompt-how-any-website-could-have-hijacked-anthropic-claude-chrome-extension](https://www.koi.ai/blog/shadowprompt-how-any-website-could-have-hijacked-anthropic-claude-chrome-extension) {{#include ../../banners/hacktricks-training.md}}