Security Alert: Confirmed Malware
PageImprove by Semrush
ID: cbllkmdbdpmfbodkeljlikmgfjpobbdi
Supported Languages
Extension Info & Metadata
Publisher Contextual Analysis
- Author
- https://www.semrush.comView Profile
- Privacy
- Privacy Policy
- Help
- Help Center
- Country
- US
- MX records exist
- Yes
- Domain exists
- Yes
- Is disposable
- No
- Is role-based
- No
- Mailbox exists
- Yes
- Address
- 800 Boylston St Suite 2475 Boston, MA 02199-8051 US
- Website
- Visit
Bypass the bottleneck and make simple, reversible SEO changes with PageImprove.
Improve your website's SEO directly from your browser. Edit canonicals, H1, links, titles, metadata, and more with our browser extension. PageImprove is perfect for you if… + You often need to update hundreds of pages of your e-commerce website or a marketplace + You wait weeks or months for SEO implementation because developer resources are limited + Your CMS is difficult to update How to use PageImprove To use PageImprove, you need to be registered with Semrush. + Download the Chrome extension and install a 5kb javascript snippet. + Update canonicals, image “alt” tags, meta tags, links, and more. + Update titles and descriptions on multiple pages at once. + Publish the changes. Once you do that, PageImprove immediately deploys them and make them visible to visitors and bots. To make permanent changes on the back end, export a CSV file with the changes you published and send it to your developers. Does PageImprove work with every kind of website? PageImprove does not work with websites built on Shopify and we do not recommend using PageImprove on websites based on frameworks like Angular, VueJS, or NextJS because of potential conflicts. What is Semrush? Semrush is a leading digital marketing toolkit for SEO, PPC, SMM and content marketing professionals worldwide. With over 40 tools within the software, search data for 140 countries and seamless integration with Google services, Semrush provides solutions for in-house marketing teams and agencies working with clients in any industry.
The extension claims full host access to every http(s) site and injects a content script into every frame at document_start. Combined with chrome.scripting.executeScript and tabs permission, it can read or modify any page the user visits before page scripts run. This is the maximum possible web-content privilege an MV3 extension can hold and is the core driver of the high ML risk score.
{ "content_scripts": [ { "matches": [ "http://*/*", "https://*/*" ], "js": [ "contentInjector.js" ], "css": [ "assets/fonts/include-font.css" ] }, { "matches": [ "http://*/*", "https://*/*" ], "all_frames": true, "run_at": "document_start", "js": [ "contentPageRuntimeInjector.js" ] } ], "host_permissions": [ "http://*/*", "https://*/*" ], "permissions": [ "storage", "scripting", "activeTab", "tabs" ]}The background service worker exfiltrates user-level analytics (user_id, device_id, event properties) to Amplitude on both the /identify and /2/httpapi endpoints with an embedded API key. The device_id is persisted in chrome.storage.local under the _ampl key, providing stable cross-session tracking of users.
var Na = "https://api.amplitude.com/2/httpapi", $a = "https://api.amplitude.com/identify", ... key: "sendUserProperties", value: function(t) { var e = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "set", r = JSON.stringify([{ user_id: Le(this.userId), device_id: this.deviceId, user_properties: n({}, "$" + e, t) }]); return fetch($a, { method: "POST", headers: { Accept: "application/json" }, body: "api_key=".concat(this.apiKey, "&identification=") .concat(encodeURIComponent(r)) }), this }}, { key: "logEvent", value: function(t) { var e = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}; return fetch(Na, { method: "POST", ... body: JSON.stringify({ api_key: this.apiKey, events: [{ event_type: t, user_id: Le(this.userId), device_id: this.deviceId, event_properties: e }], options: { min_id_length: 1 } }) })The same Google Analytics event payload (with persistent client id stored in chrome.storage.local under _ga, plus optional Semrush user id 'uid') is duplicated to a third-party endpoint at google-analytics.bi.owox.com. OWOX is a BigQuery data-pipeline vendor; piping GA hits to a non-Google host means user activity is also flowing into a third-party data warehouse beyond the disclosed 'Semrush analytics' surface.
logEvent: function(e, r, n, o) { return Va.getClientId() .then((function(i) { var u = { method: "POST", headers: { contentType: "text/plain;charset=UTF-8" }, body: new URLSearchParams(Ja(Ja({ v: "1", tid: "UA-6197637-22", cid: i }, _e(e, Ce((function() { return {} }), (function(t) { return { uid: t } })))), {}, { t: "event", ec: "pageimprove:" + r, ea: n }, le(o) ? o : { el: "object" === t(o) ? JSON.stringify(o) : "" + o.toString() })) .toString() }; fetch("https://www.google-analytics.com/collect", u), fetch( "https://google-analytics.bi.owox.com/UA-6197637-22", u) }))}At document_start in every frame of every site, the extension injects a <script> element pointing at a web_accessible_resource (contentPageRuntimeScript.js), executing extension-controlled JavaScript directly in the page's main world. This bypasses the content-script isolated world and gives the script the page's full DOM/JS scope, a pattern frequently abused for in-page tampering even though the current payload is small.
(() => { var e = document.createElement("script"); e.src = chrome.runtime.getURL("contentPageRuntimeScript.js"), document.documentElement.appendChild(e)})();A MutationObserver continuously rewrites the onclick handler of every <a> element in the document, calling preventDefault() and routing navigation through extension-controlled logic. While intended for the SEO preview iframe, the same code path runs in the content-bundle context and effectively gives the extension the ability to intercept and redirect any link click on the page, which is a high-impact capability if abused (e.g. affiliate/redirect injection).
Rs = function(t) { ...}((function(t) { return function(t, e) { return function(r) { if (r.preventDefault(), qs.test(this.href)) return !1; ! function(t, e) { return t.protocol === e.protocol && t.host === e.host && t.pathname === e.pathname && t.hash === e.hash && t.search === e.search }(new URL(this.href), new URL(e.location.href)) ? As.test(this.href) || this.href.startsWith(t) ? e.location = this.href : window.open(this.href, "_blank"): e.location.reload() } }(function(t) { return t.location.protocol + "//" + t.location.host }(t), t)}), { resolver: pe});xc(xs).watch((function(t) { var e = ...(2e3, function(t, e) { return function() { for (var r = Rs(e), n = 0; n < t.length; n++) { var o = t[n]; Ds(o, r) && (o.onclick = r) } } }(t.document.getElementsByTagName("a"), t)); e(), new MutationObserver(e).observe(t.document.body, { childList: !0, subtree: !0, attributes: !0 })}))By severity
Versions scanned
Showing 1 of 1 scanned version with more than one unique finding. Counts are unique findings that include each version.
| Extension Version | Code Review Findings |
|---|---|
| 0.0.101 | 5 |
Files with findings
3 distinct paths — top paths by unique finding count:
- background.js3
- contentPageRuntimeInjector.js1
- manifest.json1
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.
Gain full insight into all external connections.
Upgrade for full visibility.
Browse and explore files within this extension package
Gain full insight into all external connections.
Upgrade for full visibility.