Detecting a Magecart Attack: How to Find the Invisible Skimmer
Magecart is one of the most dangerous threats facing modern e-commerce. Unlike classic attacks that take down a site or steal a database, Magecart operates silently. It doesn’t steal from you – it steals directly from your customers at the moment they trust your brand the most: on the payment page.
Before You Begin: Assessing the Severity of the Situation
- Isolated case (single customer): If HOLEST DYNAMIC DOM GUARDIAN has reported a warning for only one customer, there is a high probability that the malicious code was injected on that customer’s own device (e.g. local malware, compromised browser). In this case your store is most likely fine – advise the customer to scan their own device.
- Multiple cases – immediate action required: If HOLEST DYNAMIC DOM GUARDIAN is reporting warnings for multiple customers, or the problem occurs when you personally attempt a transaction – this is an alarm that demands immediate response. Every minute of delay means your customers’ card data is actively being stolen.
- Warning – the threat may be hiding: In some cases, threats of this type have built-in evasion mechanisms: the malicious code automatically hides or deactivates when it detects that an administrator is accessing the site (based on session cookies, URL parameters, or specific request headers). It is therefore strongly recommended to test the site from a private/incognito window without being logged into the admin account.
The following describes how, in a real-world case, the exact script responsible for the malicious code was located.
Before the Investigation: Required Site Preparation
- Enable maintenance mode: While you investigate, new visitors must not be able to reach checkout and enter card details. Enable maintenance mode through your WP maintenance plugin – visitors will see a “Site is currently under maintenance” page, while you as administrator continue to see the site normally.
- Deactivate the HolestPay or other payment module: To freely inspect the checkout page without interference from the HOLEST DYNAMIC DOM GUARDIAN system, you must temporarily deactivate the HolestPay plugin in the WordPress admin panel (Plugins → Holest Pay → Deactivate). Deactivating the plugin automatically deactivates the D-DOM Guardian protection as well, allowing you to observe the malicious form and trace its source without interference.
Phase 0: Spotting the Anomaly
Most store owners learn about an attack only when their bank or customers report suspicious transactions. However, there are visual indicators you can spot yourself:
- Language mismatch: If your site is in your local language but the card input fields suddenly appear in English (e.g. “Card Number” instead of the local equivalent), that is a red flag.
- Delayed rendering: Skimmers often wait for all legitimate scripts to load before injecting their fake form. If you notice that the payment form changes or flickers a few seconds after page load – you are likely under attack.
Identifying and Analysing the Fake Form (Element Forensics)
The attack begins when you notice a card entry form on the checkout page that is not part of your original design. The most common sign is that the labels and fields are in English while the rest of the site is in a different language.

Image 1 – The attacker’s fake card form has appeared on the checkout page alongside the legitimate payment processor form.
Right-click directly on the suspicious field and choose Inspect. In the Elements panel, locate the characteristic attributes of that element: id, name, or placeholder. These are the attacker’s “signature” and will serve as the trigger for our trap.

Image 2 – Using Inspect we identify the characteristic strings (sq-pf-unq and card_number) whose appearance will trigger the breakpoint.
The malware constructed a complete fake form (imitating the Square payment system) containing fields for card number, expiry date, CVV, and a save-to-account option. Importantly, this HTML is not present statically in the page source – the malware builds it dynamically through JavaScript at page load time. We confirm this by searching the DOM (e.g. searching for the prefix sq-pf-unq):

Image 2-2 – Searching the page source for the key strings (sq-pf-unq, card_number) returns no results – the form is constructed dynamically by JavaScript.
Precisely because the form is dynamic, a standard code search is useless. We need to catch the JavaScript in the act of building that form.
Setting the Digital Trap (Trap Script)
Since the malicious code executes dynamically and briefly, we need to force the browser to automatically pause execution the moment the suspicious HTML appears in the DOM. We achieve this using a MutationObserver combined with native debugger statements.
Prepare a trap script like the one below so that it triggers a breakpoint (debugger) when it detects the creation of characteristic parts of the malicious form:
(function magecartGlobalSniffer() {
console.log("Sniffer active. Monitoring all DOM changes...");
// 1. MutationObserver - catches absolutely everything added to the HTML
const observer = new MutationObserver(function observerCallback(mutations) {
mutations.forEach(function mutationHandler(mutation) {
mutation.addedNodes.forEach(function nodeHandler(node) {
if (node.nodeType === 1) {
const htmlContent = node.outerHTML || "";
if (htmlContent.includes('sq-pf-unq') || htmlContent.includes('card_number')) {
console.warn("INJECTION DETECTED!");
console.log("Element:", node);
debugger; // Check the Call Stack here!
}
}
});
});
});
observer.observe(document.documentElement, {
childList: true,
subtree: true
});
// 2. Intercept document.write (common method used by older skimmers)
const originalWrite = document.write;
document.write = function interceptedWrite(content) {
if (content && (content.includes('sq-pf-unq') || content.includes('card_number'))) {
console.warn("document.write INJECTION DETECTED!");
debugger;
}
return originalWrite.apply(this, arguments);
};
// 3. Helper function for manual stack inspection in the console
window.getMalwareStack = function() {
try {
throw new Error("Manual Stack Trace");
} catch (e) {
return e.stack;
}
};
console.log("Trap is ready. If the form appears, the debugger will fire.");
})();
'sq-pf-unq' and 'card_number' with the identifiers you found in Step 1 – these are the triggers specific to your attack.
Before pasting the trap, open the Sources tab in DevTools and set a breakpoint as early as possible in the page load sequence. This forces the browser to pause before the malware has any chance to inject anything, giving you the opportunity to paste the trap via the console. Once the browser pauses at that breakpoint, switch to the Console tab, paste the trap script above, and run it. From that point on, the trap is active and waiting for the malware:

Image 4 – The trap has been injected through the console while the browser is paused. As soon as the malware attempts to build the fake form, the breakpoint will fire automatically.
Catching the Source (Call Stack Analysis)
Continue page loading. When the malware attempts to construct the fake form, our trap will catch it and the browser will automatically pause execution. The screen dims and DevTools opens the Sources tab.

Image 5 – The trap has worked: the breakpoint fired at the exact moment the malware tried to inject the fake form into the DOM.
The key is the Call Stack panel (right side of the Sources tab). It shows the chronological chain of function calls that led to the creation of the fake form. Walk it backwards – skip the first entry (that is our trap) and focus on the second or third entry.

Image 6 – Walking the Call Stack backwards, we locate the exact JavaScript file that triggered the fake form injection. In our case it was a script from the external domain cms-manager.net.
cms-manager.net) or has a random name such as ae83f2.js – you have found the attacker.
Finding the “Entry Point” – How the Malware Loads onto Your Site
Now that we know the URL of the malicious script, we need to find where and how it was injected into your site. Use View Page Source (Ctrl + U) and search (Ctrl + F) for the discovered domain or URL.
Magecart is typically loaded via a seemingly harmless script tag in the site’s header or footer. Our investigation found that the following external script URL had been injected into the HTML: https://cms-manager.net/script.js

Image 7 – In the page source we find the script tag loading the malicious script from an external domain. This is the “entry point” the attacker left behind on the server.
This line is not part of your original code – the attacker injected it directly into files on the server, most commonly through a compromised FTP/SSH account or a vulnerability in a CMS plugin.
What to Do After Detection?
grep -r "cms-manager.net" . or find . -name "*.php" | xargs grep "cms-manager" will almost certainly return no results – the infected PHP file exists on the server, but the string we are looking for does not appear in readable form. The malicious URL is hidden behind encoding such as base64, gzip compression, or multiple layers of obfuscation, making it undetectable by a plain text search.
How to Locate the Infected File on the Server
Since we know which script in the browser is causing the problem, we can use a process of elimination to identify which module or file on the server is injecting it:
- Disable modules one by one: Through the admin panel, gradually deactivate modules/plugins and after each one refresh the checkout page. When the malicious script stops loading – the last module you disabled is the culprit.
- Inspect that module’s files: Once we know which module is responsible, we examine its files. What we are looking for are PHP files that appear suspicious – containing massive blocks of encoded content: long strings of random-looking characters that make no sense at first glance. Typical patterns include
eval(base64_decode(...)),eval(gzinflate(...)),eval(str_rot13(...)), or multiple layers of nested decoding. Legitimate modules should never contain such constructs – if you find a PHP file with hundreds or thousands of characters of encoded string, it is almost certainly malicious code. - Trace the network request: In DevTools, open the Network tab, filter by type JS, and watch which file from your server initiates the request to
cms-manager.net. This directly reveals which file on your site is calling the malicious external script.
Once You Have Found the Infected File
- Change all passwords: FTP, SSH, WP-Admin, and the database – the attacker had to gain access somehow.
- Review other files: Check
wp-config.phpand.htaccessfor additional suspicious modifications – there is often more than one infected location. - Server logs: Review access logs to see who modified files and when, during the period the skimmer was active.
- Notify your payment processor: If the skimmer was active, you are obligated to notify your bank and payment processor to protect customers who may have been affected.
This guide was created for educational purposes based on a real-world forensic analysis of a Magecart variant.
Stay vigilant – the security of your customers is your top priority.









