Skip to content

Commit 917fd05

Browse files
author
HackTricks News Bot
committed
Add content from: ShadowPrompt: How Any Website Could Have Hijacked Claude's C...
1 parent 4be4a33 commit 917fd05

1 file changed

Lines changed: 67 additions & 0 deletions

File tree

  • src/pentesting-web/browser-extension-pentesting-methodology

src/pentesting-web/browser-extension-pentesting-methodology/README.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,69 @@ The **less extensions and URLs** indicated here, the **smaller the attack surfac
375375
>
376376
> 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).
377377

378+
#### Wildcard-trusted web origins to privileged action injection
379+
380+
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.
381+
382+
Typical exploitation path:
383+
384+
1. Find the extension ID and enumerate `externally_connectable.matches`.
385+
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).
386+
3. Get JavaScript execution in **any** trusted origin.
387+
4. Send the request directly to the extension:
388+
389+
```javascript
390+
chrome.runtime.sendMessage("<extension-id>", {
391+
type: "privileged_action",
392+
payload: { attacker: "controlled" },
393+
})
394+
```
395+
396+
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.
397+
398+
> [!CAUTION]
399+
> 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.
400+
401+
#### Auditing `chrome.runtime.sendMessage` / `onMessageExternal` trust
402+
403+
When reviewing a browser extension that accepts messages from web pages:
404+
405+
- Search for `chrome.runtime.onMessageExternal.addListener`, `chrome.runtime.onConnectExternal.addListener`, and sensitive handlers reachable from those listeners.
406+
- Verify the extension performs **exact origin equality** checks on the sender instead of suffix, regex, or wildcard matching.
407+
- Verify the handler authorizes **message type + origin** together. A safe origin for telemetry or onboarding is not automatically safe for privileged actions.
408+
- Confirm the extension does not trust a subdomain just because it shares the parent eTLD+1.
409+
- Check whether any allowed origin hosts **third-party JavaScript**, **user-generated content**, or **legacy static assets**.
410+
411+
Bad patterns:
412+
413+
```javascript
414+
if (sender.origin.endsWith(".example.com")) { /* trust */ }
415+
if (/^https:\/\/.*\.example\.com$/.test(sender.origin)) { /* trust */ }
416+
```
417+
418+
Prefer strict matching to the minimal set of origins:
419+
420+
```javascript
421+
if (sender.origin !== "https://app.example.com") return
422+
```
423+
424+
#### Rollback hunting on trusted static assets
425+
426+
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.
427+
428+
Common patterns:
429+
430+
- `/assets/widget/1.26.0/index.html`
431+
- `/static/app-2024.12.1/`
432+
- `/cdn/component/v1234/`
433+
434+
Practical checks:
435+
436+
- Start from a version observed in network traffic or page source.
437+
- Decrement semantic versions / build numbers and request older paths.
438+
- Look for `200`, `301`, or cache hits on old builds.
439+
- Review older JS bundles for DOM XSS, unsafe message handlers, or gadget endpoints that can re-establish JavaScript execution on the trusted origin.
440+
378441
## Communication summary
379442

380443
### Extension <--> WebApp
@@ -743,6 +806,8 @@ Even though Browser Extensions have a **limited attack surface**, some of them m
743806
- [ ] Use a **strong** **`content_security_policy`**
744807
- [ ] **Limit** as much as possible the **`externally_connectable`**, if none is needed and possible, do not leave it by default, specify **`{}`**
745808
- [ ] 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.
809+
- [ ] Reject wildcard or suffix trust such as `*.example.com` for **privileged** external message handlers.
810+
- [ ] Review whether any allowed origin serves **vendor-hosted widgets**, **user content**, or **versioned legacy assets** that could restore code execution on a trusted subdomain.
746811
- [ ] **Limit** as much as possible the **`web_accessible_resources`**, even empty if possible.
747812
- [ ] If **`web_accessible_resources`** is not none, check for [**ClickJacking**](browext-clickjacking.md)
748813
- [ ] 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
798863
- [https://palant.info/2022/08/31/when-extension-pages-are-web-accessible/](https://palant.info/2022/08/31/when-extension-pages-are-web-accessible/)
799864
- [https://help.passbolt.com/assets/files/PBL-02-report.pdf](https://help.passbolt.com/assets/files/PBL-02-report.pdf)
800865
- [https://developer.chrome.com/docs/extensions/develop/concepts/content-scripts](https://developer.chrome.com/docs/extensions/develop/concepts/content-scripts)
866+
- [https://developer.chrome.com/docs/extensions/reference/manifest/externally-connectable](https://developer.chrome.com/docs/extensions/reference/manifest/externally-connectable)
801867
- [https://developer.chrome.com/docs/extensions/mv2/background-pages](https://developer.chrome.com/docs/extensions/mv2/background-pages)
802868
- [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/)
803869
- [https://gist.github.com/LongJohnCoder/9ddf5735df3a4f2e9559665fb864eac0](https://gist.github.com/LongJohnCoder/9ddf5735df3a4f2e9559665fb864eac0)
804870
- [https://redcanary.com/blog/threat-detection/assemblyline-browser-extensions/](https://redcanary.com/blog/threat-detection/assemblyline-browser-extensions/)
871+
- [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)
805872

806873
{{#include ../../banners/hacktricks-training.md}}

0 commit comments

Comments
 (0)