Steganography in a Magecart Attack

May 5th, 2022 | By Jscrambler | 4 min read

A Magecart attack uses steganography to hide malicious code in something that is not secret to steal credentials and credit card data.

One month ago, we came across a report about another Magecart infection. Even though this infection was first detected in a known consumer electronics retailer, the same skimmer was
also being used on over a dozen other websites.

One of the most peculiar aspects of this attack was the fact that it was fetching a remote file called fonts.css,” from which it would retrieve JavaScript code to be executed as the next stage of the attack.

How can a .css file contain JavaScript code?

Well, it did not contain JavaScript code.

The .css file contained a few lines of valid CSS code, but there were also non-visible characters such as spaces, tabs, and newlines.

A clear pattern in this sequence of characters does not exist, so this was very suspicious and strongly hinted that steganography was being used.

Invisible characters selected in fonts.css

What is steganography, and how does it work?

“Hiding in plain sight” is the most common description of steganography. It consists of hiding a secret message in something that is not secret, and this practice goes back, at least, to ancient Greece.

One of the most famous examples from this era is that they would shave a messenger’s head, tattoo a secret message into his scalp, and then send the messenger to his destination after his hair had grown back.

In comparison, the malicious script we are analyzing conceals the malicious JavaScript code behind spaces, tabs, and newlines, which are visible to everyone but need a “haircut” process to reveal the hidden message.

This process consists of three steps:

  1. Split the payload into chunks by using space characters as separators.

  2. Replace tabs with the character 1.

  3. Replace newlines with the character 0.

Converting fonts.css contents to a binary string

The result is a binary string that represents obfuscated JavaScript code ready to be executed in the next stage of the attack.

Example of the transformation process

What was responsible for this processing or fetching the .css file?

It turns out the victim’s website was hosting and running a compromised version of jQuery, but we do not know for sure how it got there.

The victim may have simply downloaded an infected version of jQuery from an untrusted source or have some other kind of vulnerability in the application or their servers that would allow an attacker to modify an existing script. However, these are only a few possibilities among many others.

This compromised script was simply a legitimate minified version of jQuery but with an additional malicious function appended to the bottom of the script, as commonly seen on other Magecart attacks, like the one that targeted British Airways.

This function was responsible for fetching the .css file, processing the hidden payload, and finally executing the generated JavaScript code.

Compromised jQuery event sequence

Does this mean that a suspicious URL was visible in the code?

This is where the attackers used another simple but effective trick. Using a combination of a decoy URL that resembles a typical Facebook CDN endpoint, and an array of numbers representing specific indexes, the attackers can pick characters from the decoy URL to construct the real malicious URL.

Converting the decoy URL to the malicious URL

How was the sensitive information accessed?

In the next stage, the attackers add an event listener for the “onblur” event to the “window” object, which will trigger whenever the window loses focus.

When this happens, another function will add “onchange” event listeners to all elements of type “textarea”, “select” and “input”.

Every time there is a change in the value of these elements, both the identifier and the value of the element will be temporarily saved in a “localStorage” item.

Saving collected data into a localStorage item

What about the exfiltration process?

The attackers chose to create two additional event listeners on the “window” object. These listeners, triggered by “DOMContentLoaded” and “beforeunload” events, would exfiltrate the data every time the page had finished loading its content or the user decided to leave.

At this point, the script would grab the saved data from “localStorage” and perform a sequence of transformations. It encodes data as “base64”, reverses it, and converts it into a string of tabs and newlines according to its binary representation. The binary data is then used to create a new Blob object that is appended to a “FormData” object.

Finally, the script executes a “POST” request using “fetch” and sends the “FormData” object containing all the stolen information to a URL controlled by the attackers. When this is completed, the attackers remove the “localStorage” item they have been using to store the information, cleaning up any traces of their operation.

What do we learn from this?

Tracking digital skimmers is getting harder by the day.

There are countless threat actors and variations of skimmers as attackers continue to look for new, improved, and automated ways of deception.

If you own an e-commerce website, make sure to keep your software updated, try to leverage the best security practices available, and, if it suits your needs, try to adopt a solution for client-side in-depth protection.


The leader in client-side Web security. With Jscrambler, JavaScript applications become self-defensive and capable of detecting and blocking client-side attacks like Magecart.

View All Articles

Must read next


12 Checklist Items for Defeating Magecart Attacks

These 12 verifications will help you procure a product that effectively tackles Magecart attacks and keeps the user experience intact on your website.

October 7, 2020 | By Pedro Fortuna | 4 min read

Web Security

7 Biggest Magecart Attacks To Date, Lessons Learned

Businesses are still losing the war on Magecart. In this article, we revisit the most relevant attacks and uncover key security and business insights.

September 12, 2019 | By Jscrambler | 6 min read

Section Divider

Subscribe to Our Newsletter