Security Alert: Confirmed Malware
Amazing Custom Cursor
ID: cnmlhlejmndckempfickgoelmkjfpece
Extension Info & Metadata
Publisher Contextual Analysis
- Author
- Julie JuradoView Profile
- MX records exist
- Yes
- Domain exists
- Yes
- Is disposable
- No
- Is role-based
- No
- Mailbox exists
- Yes
Amazing Custom Cursor - change mouse cursor style from 100+ presets
Amazing Custom Cursor allows you to change cursor style to themed preset cursors or upload custom cursor. * Features * - Change cursor on any page to one of our 100+ presets 👉 - Several preset categories 🌞 - Upload a custom cursor ⚙️ * How to use * - Install the extension - Click on toolbar button - Select “Upload cursor” to add your own custom cursor Please note that due to security limitations cursor could not be changed on internal browser pages or in Chrome Webstore.
The `onMessageExternal` listener has zero origin validation — any website can send messages to this extension by knowing (or enumerating) its ID. The `install_collection` and `install_pack` handlers blindly accept and persist arbitrary cursor data structures from external senders into `chrome.storage.local`, enabling any web page to inject attacker-controlled objects into the extension's storage. This is a classic MV2 cross-extension/web-to-extension abuse vector.
chrome.runtime.onMessageExternal.addListener(function(request, sender, sendResponse) { if (request.action == "getInstalled") { return sendResponse({ collections: this.collection, ver: chrome.runtime.getManifest().version, action: 'get_installed_collection' }); } if (request.action == "install_collection") { let data = {}, res = { status: true, version: chrome.runtime.getManifest().version, action: 'install_collection' } sendResponse(res); data = request; chrome.storage.local.get(null, function(items) { this.collection = items.collection; let slug = data['slug']; delete data['slug']; delete data.collection['slug']; this.collection[slug] = data.collection[slug]; chrome.storage.local.set({ collection: this.collection }); return sendResponse(res); }.bind(this)); }The `get_config` action dumps the entire `chrome.storage.local` contents to any requesting external origin with no authentication or origin check. The `set_config` and `set_config_sync` actions allow any website to write arbitrary key-value pairs into both the extension's local and sync storage. An attacker-controlled page can overwrite the `selected` cursor object with a crafted `cursor.path` value (e.g. a data URI payload), which `customCursor.js` will then inject into every page's CSS via `sheet.innerHTML`.
if (request.action == 'get_config') { chrome.storage.local.get(null, function(items) { return sendResponse(items); }.bind(this));}if (request.action == 'set_config') { chrome.storage.local.set(request.data); return sendResponse({ status: true });}if (request.action == 'set_config_sync') { chrome.storage.sync.set(request.data); return sendResponse({ status: true });}if (request.action == 'get_config_sync') { return sendResponse(this.config_sync);}The `authSync` method runs every 10 seconds indefinitely and continuously overwrites `chrome.storage.sync` with the full set of cursor pack IDs and the user's size preference. Chrome Sync storage is tied to the user's Google account and synced to Google's servers, meaning this creates a persistent, recurring upload of user behavioral data (which cursor packs are installed) to cloud infrastructure. The 10-second polling cadence is aggressive and disproportionate to any legitimate cursor-syncing need.
authSync() { chrome.storage.local.set({ collection: listOfCollection }); chrome.storage.local.get(['collection', 'selected', 'size'], function(data) { var packMap = new Map(); var packs = []; chrome.storage.sync.set({ 'size': data.size }); for (let i in data.collection) { let collection = data.collection[i]; for (let y in collection.items) { packs.push(collection.items[y].id); packMap.set(collection.items[y].id, true) } } chrome.storage.sync.get('packs', function(items) { chrome.storage.sync.set({ 'packs': packs }); }); }); setTimeout(this.authSync.bind(this), 1000 * 10);}By severity
Versions scanned
Showing 2 of 2 scanned versions with more than one unique finding. Counts are unique findings that include each version.
| Extension Version | Code Review Findings |
|---|---|
| 1.2.1 | 2 |
| 1.2 | 3 |
Files with findings
1 distinct path — top paths by unique finding count:
- background.js5
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.
Code Diff
Compare extension code between any two versions.
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.