Charity Hacked: Web Skimmer Infected Caritas Spain Websites for Over a Year

By Pedro Fortuna 20 min read

With David Alves and Pedro Marrucho

This research documents Jscrambler’s investigation into a stealthy web-skimming campaign that infiltrated multiple Caritas Spain websites for Caritas Internationalis, a confederation of over 160 Catholic relief, development, and social service organizations operating in more than 200 countries and territories.
All targeted Caritas Spain websites were running WooCommerce, the popular e-commerce plugin for WordPress. The attack chain had two distinct stages, designed to remain undetected while intercepting sensitive payment data.

This campaign reinforces a broader trend: web skimming infections are increasingly driven by modular kits. These toolkits let attackers mix and match delivery mechanisms, support multiple communication channels within their infrastructure, and deploy flexible combinations of loader and skimmer scripts. Jscrambler confirmed that the threat actors’ automated validation and use of stolen cards occur soon after they capture them.

What makes this case especially concerning is the victim: Caritas, a non-profit dedicated to helping vulnerable communities. Still, attackers kept their skimming operation running across seventeen Caritas España sites for over a year until it was shut down recently.

How the Attack Works

The skimming campaign, like many, was executed in two stages. Stage one served as the loader, laying the groundwork for the attack. Stage two contained the skimmer logic, injected a fake payment form, and exfiltrated sensitive data.

Stage 1: Entry point and loader

The initial infection vector remains unknown. It could have been an exploited vulnerability, a misconfigured server, a compromised plugin, or credentials theft.  In this type of infection, threat actors usually ensure they can retain access even if the initial vulnerability or misconfiguration is patched or fixed in the meantime.

We observed that the Stage 1 loader was injected as a one-liner at the bottom of the minified WooCommerce JavaScript file cart-fragments.min.js, which runs on the homepage.

https://www.caritas.es/main-files/plugins/woocommerce/assets/js/frontend/cart-fragments.min.js?ver=6.1.2

Here’s what that one-liner looks like:

Entry-point-and-loaderListing 1 – Sample stage 1 loader

This one-liner (lightly obfuscated) executes the following logic:

  1. Clears a key (XsuHCYmfbgVSRFVx7SHRnU7DfapjFpaf) from localStorage (this entry is associated with a potential web socket connection);
  2. Checks for another key (QIQWJJnh1Ckclw0jFr5KPME2M3kYHTyq) to avoid multiple skimming attacks on the same device;
  3. Dynamically constructs a URL using String.fromCharCode — in this case, https://categorywishlist.com;
  4. Sends a POST request to that endpoint;
  5. If the response is successful, the loader:
    • gets a JSON response that, among other things, includes a property called response.data containing the following subproperties:
  • “script”: the URL from where the stage2 script must be loaded,
  • “handler”: the URL to where skimmed data will be exfiltrated by the Fetch method,
  • “Socket”: an alternative exfil channel using Web Sockets

sample-jscon-returnedListing 2 – Sample JSON returned by the categorywishlist.com endpoint

The arrays above are strings using the same obfuscation technique as before. Using String.fromCharCode, you get:

json-after-decoding-string-elementsListing 3 – JSON after decoding string elements

  • Then “socket” and “handler” are saved, respectively, into Local Storage items “XsuHCYmfbgVSRFVx7SHRnU7DfapjFpaf” and “XsuHCYmfbgVSRFVx7SHRnU7DfapjFpaf_handler”

6. Loads a stage 2 script from https://newsasssets.com/caritas.js by appending it to the head section of the DOM.

The script catches errors to avoid triggering alerts that could lead to earlier discovery of the attack.

Stage 2: Fake payment form and exfiltration

donor-form-caritas-spainImage 1 – Donor form

Once loaded, the second-stage script monitors for the selection of the Tarjeta (payment card) payment option. When detected, it injects a fake Continuar (Proceed) submit button and hides the real one.

payment-card-option-selected-on-the-donor-formImage 2 – Payment Card option selected on the donor’s form

fake-button-inject-function

Image  3 – Fake button inject function (deobfuscated for improved readability)

Once the user submits the initial form, it overlays it with a fake payment form on the same domain (caritas.es) that visually resembles the legitimate payment gateway (Redsys on behalf of Santander).   The skimmed data — cardholder name, number, expiry, and CVV — is collected and exfiltrated via a covert Image.src request to https://hotjarws.com/b.php, base64 encoded.

user-submits-the-initial-form

Collected data:

  • Cardholder data:
    • User Agent
    • Email
    • First Name
    • Last Name
    • Address
    • City And Postcode
    • Cardholder name
    • Phone
    • DNI
    • Payment card number
    • Expiry date
    • CVV
  • Collected from:
    • website

fake-payment-form-running-caritas-spainImage 3 – Fake payment form running at Caritas.es

exfiltrated-dataImage 4 – Exfiltrated data

exfiltrated-data-example

After the user submits the fake payment form, the overlay is removed, and a loading spinner is shown for a few seconds. Then, the donor form is shown again. At this point, provided that the user does not deselect the target (card), if the user clicks Continuar (submit), they are redirected to the legitimate PSP site to proceed with the donation.

legitimate-payment-form

Image 5 – Legitimate payment form on sis.redsys.es

While the visual representation is convincing, the differences become obvious after the user is taken to the second payment form.  By comparing Images 3 and 5, they are easily spotted.  The question is whether these differences are enough to prompt users to report them to Caritas and, if so, how Caritas processes those reports.

Infected Websites

The team checked all Caritas-related websites, and we found the same skimming campaign affecting the following 17 websites:

  • caritas.es
  • caritasespanola.org
  • caritasdtr.org
  • caritasoa.org
  • caritastortosa.org
  • caritas-sc.org
  • caritasmalaga.es
  • caritasmallorca.org
  • caritasmeba.es
  • caritasplasencia.org
  • caritasvalencia.org
  • caritas-zaragoza.org
  • caritasbi.org
  • caritasbisbatvic.cat
  • caritasjaen.es
  • caritasregiondemurcia.org
  • diocesanaterrassa.caritas.es

Most websites were hosted under the same IP address, indicating centralized management or a shared infrastructure. A few exceptions exist (3), but most were under the same IP and likely managed through a common backend administration panel.

infected-websites-infrastructure-graph

Image 6 – Infected websites infrastructure graph

Research Timelines

This campaign was first detected on March 16th, 2025. Soon after, researchers found all seventeen infected Caritas websites in Spain, along with all involved domains and IP addresses. Then, between April 1st and 3rd, 2025, the stage 1 categorywishlist.com and the C2 domain newassets.com went offline, but the websites were still infected with Stage 1. On April 3rd at 1 am, the C2 domain came back with a new IP:

research-timelines

At this point, Jscrambler started reaching out to victims. The team contacted Caritas on April 4th. Shortly after, all Caritas-infected websites went down for maintenance.

websites-under-maintenanceImage 7 – Websites under maintenance

When they returned online, few things had changed. All websites were still infected, but the point of infection was now on a different WooCommerce script:

woocommerce-script

The Jscrambler Research Team couldn’t confirm whether Caritas cleaned the previous script or whether the threat actors simply moved the infection point elsewhere, perhaps as an evasion tactic. Evidence suggests that the threat actors have persistent access to the WooCommerce installation.

Besides that change, the skimmer stack remained the same, except that a skimmer-related domain changed. Instead of using categorywishlist.com for the Stage 1 JSON request, it was now using assetssafepay.com. All other skimmer-related domains remained unchanged.

Jscrambler reached out to Caritas again, and by April 11th, 2025, we confirmed the infection had been removed.

Other Targets and Skimming Insights

The same campaign targeted several websites beyond Caritas. The Jscrambler Research Team discovered that this threat actor was leveraging an unusually high number of domains (61), most of which were hosted under the same IP address recently assigned to their C2 server (see Image 7).

When an attacker uses such a large volume of domains, taking them down individually is often ineffective. Taking down the IP address — for example, by reporting it to the hosting provider — is typically a more impactful countermeasure, especially when many sites are hosted on the same infrastructure.

Other-targets-skimming-insights

Image 8 – Domains used by the Threat Actor

Across other victim websites, we observed variations of the same attack. These differences appeared in both the loader scripts (Stage 1) and the main skimmer logic (Stage 2):

  • Stage 1 loaders: varied in location and method. Some were injected into different plugins or scripts, including those loaded via a legitimate Google Tag Manager (GTM) or through scripts pretending to be GTM. The loader code itself also showed multiple variations.
  • Stage 2 scripts: clearly generated by a tool, all very similar, usually obfuscated. In some cases, we saw a comment header typically associated with Google Closure Compiler: Copyright The Closure Library Authors. SPDX-License-Identifier: Apache-2.0. While the team cannot confirm whether Closure Compiler was actually used, the attacker may have inserted this comment deliberately to make the script appear more legitimate. If Closure Compiler was used at some point, its traces may have been overwritten by subsequent layers of obfuscation. Closure Compiler is intended for minification, not obfuscation; however, defenders doing a quick analysis may miss the distinction.

Interestingly, some victims seemed to know something was wrong but lacked the means or knowledge to address it properly. On one merchant’s site, there was an attempt to block the skimmer by injecting a script designed to prevent the stage 2 payload from loading from paysafeprocess.com.

merchant-attempt-fix-the-problemImage 9 – A merchant’s attempt to fix the problem

How Fast is Stolen Data Used?

The Jscrambler Research Team wanted to understand how quickly stolen payment data from this campaign was being used. To do so, a canary payment card was deployed from Thinkst — a specially generated card number intended for use as a decoy and not for legitimate transactions. If this card is used or even tested for authorization, it triggers an alert, confirming that it has been compromised. Think of it as a payment card honeypot.

Using a canary card service, a card was created and submitted through the fake form on caritas.es. Within just 10 minutes, an alert was received.

incident-info-canary-payment-card-triggered-alert

Image 10 – Canary Payment Card triggered alert

Given how quickly the card was tested, the threat actor’s infrastructure is likely automated to validate stolen cards soon after capturing them.

Highly Persistent Infection

As stated above, the Jscrambler Research Team first detected this infection in mid-March 2025. However, by examining historical snapshots from Archive.org and other web-crawling services, the initial infection was traced back to February 22nd, 2024.

highly-persistent-infection

first-sign-of-infection

Image 11 – First sign of infection on February 22nd, 2024

Over time, we observed that different scripts were infected, multiple skimming techniques were deployed, and there were periods of dormancy. These signs strongly suggest that the threat actors had persistent access to the WooCommerce environments, allowing them to reintroduce or modify the skimming code at will, shift infection points, and rotate infrastructure domains as needed.

As of April 11th, 2025, Jscrambler confirmed that the skimmer was no longer active. However, from our external vantage point, we cannot determine whether the attacker still retains any level of access to the affected systems.

How to Protect Against Web Skimming

To reduce the risk of web skimming, organizations that accept online payments should implement robust security solutions. Merchants accepting payment card payments are already contractually obligated to comply with security standards such as PCI DSS.

Specifically, the following requirements apply:

  • Requirement 6.4.3: Merchants must ensure that all payment page scripts are authorized and have a method to assure their integrity. This means cataloging which scripts are expected to run on the payment page, validating their sources, and implementing integrity checks.
  • Requirement 11.6.1: Merchants must implement a change- and tamper-detection mechanism to alert on unauthorized modifications to HTTP headers and the contents of payment pages as received by the consumer browser. This requires the ability to detect if a skimmer or rogue script is injected post-deployment.

Implementing script behavior-based monitoring solutions, such as Jscrambler Webpage Integrity, can detect unauthorized script injections and enforce PCI DSS requirements 6.4.3 and 11.6.1.

Because small merchants often lack the expertise or resources to fully implement PCI DSS’s stringent requirements, these automated solutions provide an essential layer of protection. An incident response plan is equally important and should include how to communicate with users and restore trust after an incident.

Web skimming prevention requires a combination of technical controls, process rigor, and continuous visibility into what is executing on your users’ browsers during checkout.

Conclusion

Losing payment card numbers to threat actors is always a serious matter, regardless of the context. In a typical online shopping scenario, the impact is significant. However, when someone visits a website solely to make a donation to a charitable cause and their cardholder data is stolen in the process, it feels especially disheartening.

This incident serves as a powerful reminder that web skimming is a threat that transcends organization size, mission, or industry. Threat actors don’t discriminate — if a website processes cardholder data, it’s a viable target.

Skimming operations are increasingly relying on automation. From searching and infecting victims, to validating and using the stolen data. There is a market for skimming kits, which invites new threat actors to set up their skimming operations. This attack also demonstrates that these attacks can persist for extended periods, making web skimming a highly profitable activity for threat actors.

If your organization processes online payments, ensuring the integrity of what users see in their browsers is critical. To learn how Webpage Integrity can help you detect and stop web skimming attacks before they cause harm, get in touch with us — we’re here to help.

Indicators of Compromise (IOCs):
GTM IDs

GTM
GTM-KJJ3BFKC

Indicators of Compromise (IOCs):
Malicious Domains

C2 IP ASN ASN-NAME ASN-COUNTRY
paysafeprocess[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
analysiscache[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
analysisdoubleclick[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
assets-token[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
assetshotjar[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
assetssafepay[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
bundlereferrer[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
analysistoken[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
notificationfeedback[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
cachereferrer[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
campaigntransaction[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
categorywishlist[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
cdn-secure[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
cdnmozilla[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
cdnnewassets[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
explorerstripe[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
gravatargo[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
platformwebsite[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
heure-planification[.]com 185[.]208[.]158[.]121 42624 SWISSNETWORK02, SC Seychelles
hipaye[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
hotjarmultisafe[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
interfaceuser-friendly[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
locationchrome[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
ratingrecommendation[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
recommendationtrend[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
inventoryvoucher[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
timestampcdn[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
referrerlocation[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
refundpurchase[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
safepaymultisafe[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
securedata-ns[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
securi-analitycs[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
staticreview[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
stockbarcode[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
jguery-web[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
web-jguery[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
stripehotjar[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
tag-secure[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
user-friendlyexperience[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
webjguery[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
webjquery[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
wishlistnotification[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
ads-advertise[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
multisafebundle[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
paysafeprocess[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
analysis-ns[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
hotjarws[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
mozillastatus[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
firefoxcaptcha[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
experienceresponsive[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
newsassets[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
checkoutcache[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
cdnweb2analytics[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
cdnsafepay[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
bundle-referrer[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
cloudsolutio[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
cachecaptcha[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
assets-tokens[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
advertcheckout[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
token-analysis[.]com 86[.]54[.]42[.]111 42624 SWISSNETWORK02, SC Seychelles
approvalreceipt[.]com – – – –
stripepayway[.]com – – – –