Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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("<extension-id>", {
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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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}}