# `open-url` command allows opening unlimited number of tabs pointing to arbitrary URLs

Grammarly extension's open-url command let any page open unlimited tabs to arbitrary URLs including file:// and chrome:// without user gesture.

- Payout: hidden
- Severity: medium
- Program: Superhuman (formerly Grammarly)
- Found by: metnew
- Disclosed: 2019-04-23
- Write-up quality: 6/10
- Original: https://hackerone.com/reports/389076
- Library page: https://bugbountylibrary.com/r/h1%3A389076
- Tags: area:os domain:browser impact:dos kind:bounty platform:hackerone sev:medium tech:chromium technique:js-analysis technique:source-review vuln:access-control vuln:dos

**Target:** Browser extension content script and background page (chrome.tabs)
**Root cause:** Content script accepts window.postMessage commands including open-url and forwards them to the background page, which calls chrome.tabs.create with the attacker-supplied URL and no origin/gesture validation.
**Steps:**
1. Page initiates Grammarly popup editor to make background page reachable from content script.
2. Page sends `window.postMessage({grammarly: true, action: 'open-url', url: 'file:///etc/passwd'}, "*")`.
3. Content script handler Z() matches action 'open-url' and calls `p.emitBackground("open-url", e.url)`.
4. Background page open() calls `chrome.tabs.create({url: e, active: t})` opening the attacker URL.
**How found:** Noticed events have isTrusted and that popup editor could be initiated without user gesture, then read content script command dispatcher and traced open-url to chrome.tabs.create in background.
**Exploitation:** Malicious page or ad opens unlimited tabs to restricted origins (file://, chrome://, chrome-devtools://) since chrome.tabs has no gesture tab limit; pinning a page that navigates to chrome://quit causes a browser restart loop DoS.
**Escalation:** Restricted-origin navigation can be used to trigger Chrome or other extension vulnerabilities; pinned chrome://quit tab yields persistent DoS loop.
**Insight:** Extension content scripts that accept window.postMessage commands often forward them to privileged background APIs; check whether chrome.tabs/window.open wrappers validate sender origin and user gesture, and whether <all_urls> host permissions allow navigating to file:// or chrome:// schemes.

