SlowMist: Udesk Malicious JS Steals Data and Alters Transfer Addresses

iconMetaEra
Share
AI summary iconSummary
SlowMist discovered a malicious JavaScript script within the Udesk system, linked to on-chain news regarding compromised platforms such as mgbx.com and bitxex.io. The script, loaded via udeskApi.2026-10-16.cached.js and deeps.js, steals session data and modifies deposit addresses. Attackers employ a remote loader to inject malicious code, posing a risk of fund theft. Inflation data and market volatility may exacerbate losses for affected users. The breach underscores critical security vulnerabilities across multiple exchanges.
How can a single script compromise both user data and transfer funds?

Article author and source: SlowMist Tech

Context

Recently, SlowMist security personnel detected a targeted attack involving poisoned scripts related to the Udesk customer service system during routine threat intelligence gathering. The team subsequently obtained two JavaScript samples, udeskApi.2026-10-16.cached.js and deeps.js, and conducted an analysis to trace how the malicious code infiltrated web pages via customer service scripts and to determine its impact on user data and business operations.

The investigation of the sample gradually revealed two types of risks: malicious scripts simultaneously harvest session data and sensitive user inputs from the webpage while modifying deposit addresses and copying content according to site-specific rules. The former could enable attackers to impersonate login sessions or take over accounts, while the latter could trick users into sending funds to substituted recipient addresses. Starting from the entry point where the customer service script is loaded, we reconstructed the implementation and triggering conditions of both behaviors by tracing the data retrieval, network transmission, and page modification logic.

MistEye response

MistEye is a proprietary Web3 threat intelligence and dynamic security monitoring system developed by SlowMist, integrating security monitoring and intelligence aggregation to provide users with real-time risk alerts and asset protection.

MistEye has immediately synchronized the risk information through intelligence alerts and customer notification channels.

Malicious loader and remote payload loading mechanism

After opening udeskApi.2026-10-16.cached.js, you can see code for features such as the customer service button, chat iframe, visitor tracking, and message communication. Continuing to examine the end of the file, after the main logic concludes, there is an independent function: it decodes two strings using _ud(), creates elements, and inserts them into the current document's head.

This section does not explicitly list the tag name or the remote URL. If only plaintext domain names are searched, the entry point may be easily missed. By examining the implementation of _ud(), we found that it retrieves two hexadecimal characters at a time and converts them into a character; after expanding the constants, the loading target becomes clear.

Decode 736372697074 as script, and another constant as https[:]//udeskqlobal[.]com/deeps.js. The domain contains "qlobal" starting with the letter 'q'—retain this spelling during searches. The loader sets the script as asynchronous and inserts it into the page; when execution reaches this point and browser policies and network conditions permit, the remote code can enter the current document.

The payload corresponding to this URL is deeps.js. The investigation focus has shifted from the customer service SDK to the payload itself. Third-party classic scripts execute in the context of the embedded document, and the data they can access depends on the actual page or iframe in which they run. The customer service chat window uses an iframe and does not automatically isolate scripts loaded on the host page.

Web data collection mechanism and scope of impact

deeps.js first reads window.location.hostname and generates configuration C according to the rules for three sites. To determine which pages will be crawled, this configuration alone is not sufficient: it is necessary to further trace the exit condition to determine whether it applies to the entire script or only to a specific module.

Following the control flow downward, we see that cookie and web storage reads, snapshot initiation, and form and authentication request hooks all appear before if (!C) return;. Below are the snapshot send statement and the final XHR hook, extracted in source order; comments indicate the omitted code in between, corresponding to the formatted view D:L100, D:L151–L166.

The location of the exit condition clarifies the scope of impact: even if the hostname does not match any of the three site rules, the script will still enter the data collection path and install hooks before exiting the address module. When investigating exposed pages, you cannot limit your search to just these three site configurations.

Upon launch, the payload reads cookies, localStorage, and sessionStorage accessible on the current webpage. These locations can store login sessions, user profiles, and business data; if they contain valid, reusable authentication tokens, an attacker who obtains them could impersonate the user’s session. The script also includes the top-level page URL and the current document’s origin, submitting this data alongside the source page.

The data collection process includes error tolerance for each item. When fetching the top-level URL from a source fails, the script replaces it with "x" and continues processing other fields; both types of web storage are serialized as JSON. Cookie scope is limited to what is readable via document.cookie, excluding HttpOnly cookies.

The script also retains entry points for data submitted later. When the user submits the form, it iterates through input, select, and textarea elements, copying non-empty content before proceeding with the original submission. Fields actually filled out on the page—such as username, password, and CAPTCHA—may be routed through additional data transmission paths, potentially leading to account login or takeover if leaked.

This path is implemented by wrapping HTMLFormElement.prototype.submit and listening for submit events in the capture phase. For pages that submit data directly via APIs, the script also wraps fetch and XHR: when a request includes a body and the URL contains keywords such as login|signin|auth|register|signup|password, the corresponding content is copied while preserving the original request call. In the fetch branch, the URL must be a string and the body must come from the request options; when objects such as FormData are directly JSON-serialized, the collected content may lack actual fields.

Data leakage mechanism and backup channel

The above collection endpoint ultimately calls the same _send() function. Tracing this function further reveals a fixed recipient at https[:]//udeskqlobal[.]com/c.php. The snapshot initiation uses the fields s, o, c, l, and ss to carry the page URL, current origin, readable cookies, and two types of web storage, respectively; subsequent form and authentication requests are sent upon their respective triggers.

The function extracts parameters after the URL question mark and inserts them into the asynchronous POST body, setting Content-Type: application/x-www-form-urlencoded. Below is the complete preserved send function (D:L45–L60):

The sending path also includes a fallback image request: if an XHR error occurs or a synchronous issue arises during transmission, the script creates an Image object and assigns the URL with parameters to its src property, attempting to resend the data via a GET request. The URL is truncated to the first 8,000 JavaScript characters, so longer content may be incomplete.

When understanding this path, it is important to distinguish between "request sending" and "response reading." The script does not read the response from c.php; a cross-origin POST that meets the criteria for a simple request can be sent first, with the browser then restricting response reading, so CORS errors can occur simultaneously with request sending. Investigation logs should examine both the POST body and image GET parameters, while outbound policies should separately verify connect-src and img-src. A regular form that triggers document navigation may also affect whether asynchronous requests can complete.

At this point, the destination of the webpage session data and subsequent submissions is clear. However, after the site exit check, the payload retains another set of operations: identifying address formats, modifying page text, and hijacking the copy path. These code segments further point toward the deposit functionality.

Deposit address replacement and clipboard hijacking mechanism

After the if (!C) return; statement, the script enters the address module. The first three hostname rules now serve a clear purpose: matching mgbx[.]com, bikingex[.], and bitxex[.]io to select the appropriate element selectors for addresses and copy buttons on different pages.

These regular expressions lack start and end anchors, resulting in a broader match range than exact domain comparison. Page rules also check the full location.href, and keywords such as "deposit," "recharge," or "assets" in query parameters or fragments are included in the evaluation. Once a page, element, or address format matches, the script scans every 200 milliseconds and replaces any identified deposit addresses with the configured value. If a user completes a valid transfer using the replaced address, the recipient destination will become that address.

Three site branches share six configuration values, labeled in the code as BTC, EVM, TRON, Solana, LTC, and DOGE. Address recognition is based solely on character shape and matching order, without verifying the user-selected network or address checksum, and may also misidentify standard business identifiers.

Continue checking the copied code, and you can see that the sample simultaneously manipulates both the page display and the clipboard content. As a result, even if users compare the page address with the copied result, they may still receive consistent manipulated values. The three paths are:

  • Wrap the Clipboard API. navigator.clipboard.writeText first calls R() to replace parameters, then passes them to the original method. This path is restricted only by the hostname configuration, does not recheck deposit page conditions, and does not rely on DOM scanning for matched elements.
  • Replace the copy button. The script clones the matched button, installs a new click listener, and replaces the original node. The new listener prevents the default action and event propagation, and attempts to copy the address stored in the shared variable _cur.
  • Intercept the copy event. When _cur is not empty and the page rules are satisfied, the listener on the document replaces the copied content with _cur, without checking whether the user-selected text is an address.

Among them, the clipboard API wrapper and the copy listener are adjacent in the source code (D:L260–L275), but they have different trigger conditions:

_cur stores the last actual address replaced. When multiple addresses are displayed on the same screen, the most recent replacement overwrites the previous record, and multiple buttons may copy the same value. If the page initially displays a configured address, scanning will not initialize _cur, and newly added button listeners will not write content; cloned HTML inline event attributes will still participate in event handling.

The analysis also revealed an implementation flaw affecting behavior judgment: the script attempts to read the own property descriptor of textContent from Element.prototype, whereas the standard property is defined on Node.prototype. Under the standard prototype chain, accessing .set subsequently throws an exception. After this branch fails, the catch block silently swallows the exception; further inspection of the surrounding code reveals that the polling has already been registered, and the subsequent copy hooks will still be installed according to their respective conditions. A single branch failure does not terminate the address hijacking module.

Summary

After tracing the loader at the end of the customer service script, we identified the sample’s attack objectives: harvesting data usable for session hijacking or account login, and replacing the recipient addresses in the deposit page and copy operations with configured values. The former is not restricted by the three site configurations, while the latter is enabled per site and specific copy path; investigation must cover various exposure scenarios.

Businesses that are still loading related scripts should cease distribution immediately, remediate exposed credentials, and verify deposit targets through trusted backend systems and transaction records.

Recommendation

  1. Secure and halt the distribution of compromised resources. If the production environment still loads the affected scripts, block access as soon as possible after saving the actual response, request chain, caching information, and collection timestamp; restore from a trusted, independently verified version, and review site hosting, CDN, build, and tag management configurations.
  2. Retrieve and load loading and exfiltration records. Perform a joined query for malicious domains, two paths, and file hashes; exfiltration records also check POST bodies and GET parameters. When analyzing compressed scripts, also search for hexadecimal URLs within loaders to avoid missing obfuscated entries by checking plaintext only.
  3. Terminate the compromised document and revoke exposed credentials. Fully close the associated page or WebView document to prevent reloading of old resources. Based on the actual scope of exposure, terminate sessions, rotate tokens and passwords from a clean environment; removing script tags will not revoke already installed hooks and timers.
  4. Independently verify the deposit address and transaction. For pages executing payloads, confirm the original deposit address, related transactions, and actual transfer destination through trusted channels, and assess the impact based on transaction records.
  5. Verify scripts and data export restrictions. Combine business settings to control script sources and integrity, separately validating policies such as connect-src and img-src, and restrict script loading and data exfiltration for udeskqlobal[.]com.

IOC

Domain name

udeskqlobal[.]com

URL

https://udeskqlobal.com/deeps.js

https://udeskqlobal.com/c.php

Wallet address

BTC: bc1qhzppfj69ywp22swj50jwcfxdamg3ym245srng9

EVM: 0x9B6EcD0023a28E1391c5124eCe578A9751A337b2

TRON: TH4L5YAhhxtC8qALbZKbPZZgausbGi25nF

Solana: AFmCUe3nNbjTaC585CcdA3vvC9iWVR8YunooFKpaQx2Z

LTC: ltc1qwz0zp39ywl34kahvn9lyk7j5x63wsy9tcxhm3w

DOGE: DAoy2w8uvFtZ92q87s9qKEoHbWgV7mVThj

Malicious file

filename: udeskApi.2026-10-16.cached.js

SHA256: 45b4e8f160d8d5177819f6c1dc67acc7abbdc65eeaffc909e668799dc778bcf6

filename: deeps.js

SHA256: 57c1441c4f5bb3260981a2df64f9ff35f117abde0d8667c8c66a047880074c59

About MistEye

MistEye is a proprietary Web3 threat intelligence and dynamic security monitoring platform developed by SlowMist, offering API-based detection of malicious activities and supply chain risk alerts within open-source package ecosystems.

All malicious packages and IOCs involved in this campaign have been integrated into the MistEye threat detection engine. Developers can use the API to automatically scan project dependencies, quickly determine if any known malicious packages are present, and receive remediation recommendations.

Disclaimer: The information on this page may have been obtained from third parties and does not necessarily reflect the views or opinions of KuCoin. This content is provided for general informational purposes only, without any representation or warranty of any kind, nor shall it be construed as financial or investment advice. KuCoin shall not be liable for any errors or omissions, or for any outcomes resulting from the use of this information. Investments in digital assets can be risky. Please carefully evaluate the risks of a product and your risk tolerance based on your own financial circumstances. For more information, please refer to our Terms of Use and Risk Disclosure.