Cursor-A custom cursor

ID: hdgdghnfcappcodemanhafioghjhlbpb

Could be malicious

Supported Languages

๐Ÿ‡ง๐Ÿ‡ฉBengali
๐Ÿ‡ง๐Ÿ‡ทBrazilian Portuguese
๐Ÿ‡ฌ๐Ÿ‡งBritish English
๐Ÿ‡ง๐Ÿ‡ฌBulgarian
๐Ÿ‡ช๐Ÿ‡ธCatalan
๐Ÿ‡จ๐Ÿ‡ณChinese (Simplified)
๐Ÿ‡น๐Ÿ‡ผChinese (Traditional)
๐Ÿ‡ญ๐Ÿ‡ทCroatian
๐Ÿ‡จ๐Ÿ‡ฟCzech
๐Ÿ‡ฉ๐Ÿ‡ฐDanish
๐Ÿ‡ณ๐Ÿ‡ฑDutch
๐Ÿ‡บ๐Ÿ‡ธEnglish
๐Ÿ‡ช๐Ÿ‡ชEstonian
๐Ÿ‡ต๐Ÿ‡ญFilipino
๐Ÿ‡ซ๐Ÿ‡ฎFinnish
๐Ÿ‡ซ๐Ÿ‡ทFrench
๐Ÿ‡ฉ๐Ÿ‡ชGerman
๐Ÿ‡ฌ๐Ÿ‡ทGreek
๐Ÿ‡ฎ๐Ÿ‡ณGujarati
๐Ÿ‡ฎ๐Ÿ‡ณHindi
๐Ÿ‡ญ๐Ÿ‡บHungarian
๐Ÿ‡ฎ๐Ÿ‡ฉIndonesian
๐Ÿ‡ฎ๐Ÿ‡นItalian
๐Ÿ‡ฏ๐Ÿ‡ตJapanese
๐Ÿ‡ฐ๐Ÿ‡ทKorean
๐Ÿ‡ฒ๐Ÿ‡ฝLatin American Spanish
๐Ÿ‡ฑ๐Ÿ‡ปLatvian
๐Ÿ‡ฑ๐Ÿ‡นLithuanian
๐Ÿ‡ฒ๐Ÿ‡พMalay
๐Ÿ‡ฎ๐Ÿ‡ณMalayalam
๐Ÿ‡ฎ๐Ÿ‡ณMarathi
๐Ÿ‡ณ๐Ÿ‡ดNorwegian
๐Ÿ‡ต๐Ÿ‡ฑPolish
๐Ÿ‡ต๐Ÿ‡นPortuguese
๐Ÿ‡ท๐Ÿ‡ดRomanian
๐Ÿ‡ท๐Ÿ‡บRussian
๐Ÿ‡ท๐Ÿ‡ธSerbian
๐Ÿ‡ธ๐Ÿ‡ฐSlovak
๐Ÿ‡ธ๐Ÿ‡ฎSlovenian
๐Ÿ‡ช๐Ÿ‡ธSpanish
๐Ÿ‡ธ๐Ÿ‡ชSwedish
๐Ÿ‡ฎ๐Ÿ‡ณTamil
๐Ÿ‡ฎ๐Ÿ‡ณTelugu
๐Ÿ‡น๐Ÿ‡ญThai
๐Ÿ‡น๐Ÿ‡ทTurkish
๐Ÿ‡บ๐Ÿ‡ฆUkrainian
๐Ÿ‡บ๐Ÿ‡ธUS English
๐Ÿ‡ป๐Ÿ‡ณVietnamese

Extension Info & Metadata

Status
Removed
Version
0.7.2
Size
3.10 MB
Rating
4.2/5
Reviews
16
Users
2,252,924
Type
Extension
Updated
Sep 11, 2022
Category
7_productivity
Price
Free
Featured
No
Visibility
Listed
Mature
No
By Google
No
Trusted
Yes

Publisher Contextual Analysis

Trusted
Author
yurih4174View 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
2,252,924

Choose your own cursor. Customize your cursor and freshen your experience.

Cursor-A replaces the default cursor with something cute, funny, and trendy. We offer: ๐Ÿ“Pre-made themes and presets ๐Ÿ“Turn on/off this extension easily ๐Ÿ“Create your collection of mouse cursors from any images Customize your experience of using this app โšก๏ธ

Item
Type
Severity
Description
<all_urls>
Permission
Critical
This permission grants access to all websites without restriction. Rated High because it can access any web content, monitor all web activity, and potentially steal sensitive data across all sites.
Contextual Risk Factors
Risk Factor
High
The following context increases the overall risk:โ€ข 15% increase: Older manifest version lacks modern security controlsโ€ข 10% increase: About:blank access enables potential sandbox escape vectors
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.
About:blank Access
Risk Factor
Medium
This extension can run content scripts in about:blank pages.
Older Manifest Version
Risk Factor
Medium
This extension uses Manifest Version 2

The extension registers an onMessageExternal listener that accepts commands from any external website with no sender origin validation. The 'get_config' command dumps the entire chrome.storage.local contents to the caller; 'set_config' and 'set_config_sync' allow any external website to write arbitrary data into the extension's local and sync storage; 'install_collection' and 'install_pack' let external sites mutate cursor collection data. Any website can silently read all stored extension data and overwrite extension configuration without authentication.

js/background.js (Line 1)
chrome.runtime.onMessageExternal.addListener(function(e, t, o) {  if ("getInstalled" == e.action) return o({    collections: this.collection,    ver: chrome.runtime.getManifest().version,    action: "get_installed_collection"  });  if ("install_collection" == e.action) {    ...chrome.storage.local.set({      collection: this.collection    })...  }  if ("install_pack" == e.action) {    ...chrome.storage.local.set({      collection: this.collection    })...  }  return "get_config" == e.action && chrome.storage.local.get(null, function(e) {      return o(e)    }.bind(this)),    "set_config" == e.action ? (chrome.storage.local.set(e.data), o({      status: !0    })) :    "set_config_sync" == e.action ? (chrome.storage.sync.set(e.data), o({      status: !0    })) :    "get_config_sync" == e.action ? o(this.config_sync) : void 0}.bind(this))

The extension generates and persists a unique client identifier (UUID v4 stored as 'cid' in chrome.storage.local) and sends a Google Analytics pageview beacon to https://www.google-analytics.com/collect on every background page load using tracking ID UA-211094822-1. This constitutes undisclosed user tracking: a permanent per-device UUID is silently created and exfiltrated to a third-party analytics endpoint without user consent or disclosure. The extension's stated purpose is cursor customization, yet it assigns each user a permanent tracking identifier.

js/background.js (Line 1)
async function s() {  const e = await new Promise((e => {    chrome.storage.local.get(["cid"], (t => {      e(t)    }))  }));  let {    cid: t  } = e;  return t || (t = (0, r.v4)(), chrome.storage.local.set({    cid: t  })), t}async function i(e) {  const t = undefined,    o = {      v: "1",      tid: e,      cid: await s(),      t: "pageview",      dp: "/background",      dt: "background",      dh: `chrome-extension://${chrome.runtime.id}`    },    r = `https://www.google-analytics.com/collect?${new URLSearchParams(o).toString()}`;  await fetch(r, {    method: "POST",    body: ""  })}o.default = i

On installation the extension opens a tab to https://ladnet.co/<extensionId>/thanks.html and registers https://ladnet.co/<extensionId>/uninstall.html as the uninstall URL, sending the live extension runtime ID to the undisclosed third-party domain ladnet.co. This allows ladnet.co to track the specific installed extension instance and monitor install and uninstall lifecycle events across 2M+ users without disclosure in the extension's privacy policy.

js/background.js (Line 1)
(0, r.default)("UA-211094822-1"),chrome.runtime.onInstalled.addListener((e => {    "install" === e.reason && chrome.tabs.create({      url: `https://ladnet.co/${chrome.runtime.id}/thanks.html`    })  })),  chrome.runtime.setUninstallURL(`https://ladnet.co/${chrome.runtime.id}/uninstall.html`);

On installation the extension immediately queries all open browser tabs and programmatically injects customCursor.js into every tab with an http/https URL using chrome.tabs.executeScript. This means the content script is pushed into all currently open pages (banking sites, email, internal tools) immediately upon install without waiting for page reload. While the extension declares <all_urls>, proactively injecting into all pre-existing tabs at install time is aggressive and exposes browsing context earlier than expected.

js/background.js (Line 1)
onInstall() {  chrome.tabs.query({}, (function(e) {      for (let t = 0; t < e.length; t++)        if (e[t].url && -1 != e[t].url.indexOf("http"))          try {            chrome.tabs.executeScript(e[t].id, {                file: "js/customCursor.js"              },              (function(o) {                let r;                chrome.runtime.lastError && console.log("tab: %s", e[t].url)              }))          } catch (e) {}    })),    chrome.storage.local.set({      collection: i,      size: 3,      myOwnListCol: {}    })}

The reload() method calls chrome.tabs.query({}) with no filter, enumerating every open tab across all windows, then sends a message to each tab ID. This grants the popup visibility of all open tabs and the ability to coordinate actions across every content-script-injected page simultaneously, which is broader than needed for cursor customization.

js/popup.js (Line 3)
reload() {  chrome.tabs.query({}, (function(e) {    let t = {      action: "update"    };    for (let n = 0; n < e.length; ++n) chrome.tabs.sendMessage(e[n].id, t)  }))}clear() {  let e = {    action: "clear"  };  chrome.storage.local.set({    selected: null,    selected_type: "none"  }), chrome.runtime.sendMessage(e)}

CSS template strings are assembled by substituting cursor image path values retrieved from chrome.storage.local (f.cursor.path, f.pointer.path) and assigned to a style element via innerHTML on every page the content script runs across <all_urls>. If storage is tampered with (e.g., via the unvalidated set_config external message or a compromised sync account), an attacker could inject arbitrary CSS into every browsed page.

js/popup.js (Line 3)
d = function() {    if (f) {      let e = 3;...      "system" == f.type && (...        t = t.replace(/#cursor#/g, f.cursor.path),        t = t.replace(/#pointer#/g, f.pointer.path),        ...        l.innerHTML = t);      "custom" == f.type && (        void 0 === f.pointer.path ? (t = s,          t = t.replace(/#cursor#/g, f.cursor.path),          ...          l.innerHTML = t) :        ...)    } else l.innerHTML = "";

The content script uses the deprecated chrome.extension.onMessage API and listens for action messages without verifying the sender's identity or origin. Any extension or page with access to the messaging channel can trigger a 'clear' to wipe cursor CSS from all pages or 'update' to force a storage read and CSS re-injection, with no sender authentication.

js/popup.js (Line 3)
h = function() {  chrome.storage.onChanged.addListener((function(e, t) {      "local" == t && p()    })),    p(),    chrome.extension.onMessage.addListener((function(e, t, n) {      "update" == e.action && p(),        "clear" == e.action && (l.innerHTML = "")    }))}()

The createTemplate method constructs an HTML string via template literals that directly interpolates user-controlled values from chrome.storage (collection IDs and image paths) and passes the result to jQuery's append(), which parses and executes it as HTML. If storage is compromised via the unvalidated set_config external message handler, this creates a stored XSS surface within the extension's settings page context.

js/settings.js (Line 2)
static createTemplate(e, t, n, r, o) {  const i = undefined;  return `<div class="cur-wrapper" data-id="${e}">     <img class="close-card" src="../icons/delete.png">     <div class="card" id="template" data-id="${e}">      <div class="curContainer">        <div class="upload ${r?"filled":""}" data-id="${e}" data-type="cursor">          <img class="upload-img" src="${t}">        </div>      </div>      <div class="curContainer">        <div class="upload ${o?"filled":""}" data-id="${e}" data-type="pointer">          <img class="upload-img" src="${n}">        </div>      </div>    </div>`}// Used as: $("#mycollection").append(e)

By severity

Critical3
High5
Medium8
Low2

Versions scanned

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

Extension VersionCode Review Findings
0.7.37
0.7.28
0.7.13

Files with findings

3 distinct paths โ€” top paths by unique finding count:

  • js/background.js11
  • js/popup.js5
  • js/settings.js2
S.No.
Category
Severity
File
Summary
Found in Version
1Privilege Escalation
critical
js/background.js (line 1)The extension registers an onMessageExternal listener that accepts commands from any external website with no sender origin validation. The 'get_config' command dumps the entire chrome.storage.local contents to the caโ€ฆ
2Remote Code Loading
critical
js/background.js (line 1)This heavily obfuscated function assembles the string 'fetch' character-by-character from fragments ('fe'+'tc'+'h'), constructs a URL to https://serasearchtop.com/cfg/{extension_id}/locale.json using a localStorage-baโ€ฆ
3Unauthorized Data Collection
critical
js/background.js (line 1)The extension registers an `onMessageExternal` listener with no `externally_connectable` restriction in the manifest, meaning any website on the internet can send it messages. The `get_config` action returns the entirโ€ฆ
4Privilege Escalation
high
js/background.js (line 1)On first install, the background script programmatically injects customCursor.js into every currently open tab whose URL starts with 'http' using chrome.tabs.executeScript. Combined with the <all_urls> permission, thiโ€ฆ
5Tracking
high
js/background.js (line 1)The extension generates a persistent UUID (client ID) stored in chrome.storage.local and sends it to Google Analytics (UA-211094822-1) via the Measurement Protocol on every background page load. This constitutes coverโ€ฆ
6Tracking
high
js/background.js (line 1)The extension generates and persists a unique client identifier (UUID v4 stored as 'cid' in chrome.storage.local) and sends a Google Analytics pageview beacon to https://www.google-analytics.com/collect on every backgโ€ฆ
7Tracking
high
js/background.js (line 1)The background script silently sends a Google Analytics Measurement Protocol pageview hit to UA-211094822-1 every time the extension starts, including the extension's runtime ID and a persistent UUID stored as 'cid' iโ€ฆ
8Unauthorized Data Collection
high
js/popup.js (line 4)The reload() method calls chrome.tabs.query({}) with no filter, enumerating ALL open tabs across every domain, then sends an update message to each. With the <all_urls> permission this means the extension communicatesโ€ฆ
9Code Injection
medium
js/popup.js (line 4)Cursor path values read from chrome.storage.local are interpolated into a style template string and assigned to innerHTML without sanitization. If any code (such as the obfuscated remote-loading backdoor in backgroundโ€ฆ
10Code Injection
medium
js/settings.js (line 3)User-uploaded cursor images are read as full data URLs via FileReader and stored directly in chrome.storage.local. The only validation is a dimension check that shows an alert but does NOT prevent storage of oversizedโ€ฆ
11Code Injection
medium
js/popup.js (line 3)CSS template strings are assembled by substituting cursor image path values retrieved from chrome.storage.local (f.cursor.path, f.pointer.path) and assigned to a style element via innerHTML on every page the content sโ€ฆ
12Code Injection
medium
js/background.js (line 1)On first installation, the background script immediately enumerates ALL currently open browser tabs using `chrome.tabs.query({})` (no filter) and programmatically injects `customCursor.js` into every HTTP/HTTPS tab viโ€ฆ
13Tracking
medium
js/background.js (line 1)On installation the extension opens a tab to ladnet.co with the extension runtime ID embedded in the URL path, and registers an uninstall redirect to the same domain. The runtime ID is transmitted to the third-party dโ€ฆ
14Unauthorized Data Collection
medium
js/background.js (line 1)On installation the extension opens a tab to https://ladnet.co/<extensionId>/thanks.html and registers https://ladnet.co/<extensionId>/uninstall.html as the uninstall URL, sending the live extension runtime ID to the โ€ฆ
15Unauthorized Data Collection
medium
js/background.js (line 1)On installation the extension immediately queries all open browser tabs and programmatically injects customCursor.js into every tab with an http/https URL using chrome.tabs.executeScript. This means the content scriptโ€ฆ
16Unauthorized Data Collection
medium
js/popup.js (line 3)The reload() method calls chrome.tabs.query({}) with no filter, enumerating every open tab across all windows, then sends a message to each tab ID. This grants the popup visibility of all open tabs and the ability to โ€ฆ
17Code Injection
low
js/settings.js (line 2)The createTemplate method constructs an HTML string via template literals that directly interpolates user-controlled values from chrome.storage (collection IDs and image paths) and passes the result to jQuery's appendโ€ฆ
18Other
low
js/popup.js (line 3)The content script uses the deprecated chrome.extension.onMessage API and listens for action messages without verifying the sender's identity or origin. Any extension or page with access to the messaging channel can tโ€ฆ
URLs
10
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.

getbootstrap.com-https://getbootstrap.com/
github.com/twbs/bootstrap/blob/main/LICENSEhttps://github.com/twbs/bootstrap/blob/main/LICENSE
www.w3.org/2000/svghttp://www.w3.org/2000/svg
github.com/uuidjs/uuidhttps://github.com/uuidjs/uuid#getrandomvalues-not-supported
www.google-analytics.com/collecthttps://www.google-analytics.com/collect?${new
ladnet.co/$%7Bchrome.runtime.id%7D/thanks.html%60%7Dhttps://ladnet.co/${chrome.runtime.id}/thanks.html`}
ladnet.co/$%7Bchrome.runtime.id%7D/uninstall.html%60https://ladnet.co/${chrome.runtime.id}/uninstall.html`
clients2.google.com/service/update2/crxhttps://clients2.google.com/service/update2/crx
*/*http://*/*
*/*https://*/*

Gain full insight into all external connections.

Upgrade for full visibility.

No IP addresses found
Showing 1 to 3 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.