top of page

MirrorMask: a tiny code change that silently skims checkout data

  • Benjamin Hosack
  • Aug 15
  • 4 min read

Updated: 2 days ago

At Turaco Labs, we have identified a live digital skimmer (e-skimmer) that hijacks Stripe Elements (and potentially other gateways) by proxying Stripe through a look-alike mirror system. A small and innocuous PHP code change quietly rewrites js.stripe.com to the attacker’s domain; from there, a transparent reverse-proxy spoofs headers and modifies responses while returning content that looks and behaves exactly like the real thing.


While most attacks which aim to replace the checkout payment flow with an attacker controlled input or data harvesting function are easily spotted due to their notable differences from the expected payment workflow, MirrorMask maintains the look and feel of the original payment flow perfectly, making it significantly less likely to be detected by site owners and administrators.


Why this matters

Stripe Elements is widely - and rightly - considered a secure way to collect payment card data. It isolates card fields in iframes served directly by Stripe and requires merchants to verify the domains that embed Elements. Our discovery shows how a threat actor can appear to satisfy those checks by relaying traffic through a controlled mirror server, keeping the checkout working and looking normal while quietly siphoning data in transit.


Important: We’ve seen no evidence of a weakness in Stripe’s platform. The compromise happens on the merchant site, where an attacker can rewrite resource URLs and then relay requests upstream.


As of mid August 2025, the malicious domain we investigated had been in use for nearly two months and, to our knowledge, has not yet been flagged by any major vendors.


What we’re calling it: MirrorMask

We’re referring to this technique as MirrorMask - the attacker presents a near-perfect reflection of Stripe’s public endpoints so that everything looks familiar to the browser and to the user.


Who is potentially affected

  • This attack primarily targets merchants using Stripe Elements

  • Potentially any checkout that loads third-party payment scripts where a host rewrite would change the origin of those assets


How MirrorMask works

  1. Small site change:  A simple string replacement swaps Stripe’s script and API domain to the attacker’s.

    MirrorMask changes
  2. Browser loads from the mirror: The checkout page now pulls /v3 and related assets from js.evilcorp.com instead of js.stripe.com.

  3. Attacker’s server mirrors Stripe: The attacker’s server, using nginx, relays requests to Stripe while:

    • Rewriting responses so remaining references to js.stripe.com point back to the mirror instead.

    • Requests forwarded to Stripe have (Host, Origin, Referer) headers rewritten to impersonate the legitimate merchant domain.

    • Selective injections add skimmer logic where needed - e.g., to exfiltrate card data or session identifiers.

  4. Everything still appears normal: Elements styling, configuration, and flow continue to function. A developer or astute administrator might notice the different hosts in network tools; most users won’t.

MirrorMask Flow

How it appears to bypass verified-domain checks

Stripe expects Elements to be embedded from known, verified domains. MirrorMask relays browser traffic so that requests arriving at Stripe look like they came from the legitimate site (thanks to header spoofing). Since the merchant site itself initiated the resource load (albeit to the mirror), everything else - the iframe structure, API paths, and runtime behavior - still matches expectations.


Again, it is important to note: This is not a bug in Stripe; it’s the consequence of local code tampering on the merchant’s site, plus a high-fidelity relay that keeps the rest of the contract intact.


Technical anatomy (high-level)

  • Reverse-proxy mirror The attacker hosts a domain that tracks Stripe’s public endpoints. Think of it as a programmable “man-in-the-middle” for legitimate assets and API calls.

  • Response rewriting Any references to Stripe’s canonical domains (e.g., js.stripe.com) are rewritten to the mirror. Additional scripts can be injected selectively (to reduce breakage and detection).

  • Request header spoofing Upstream calls to Stripe include forged Host, Origin, and Referer headers so they appear to originate from the victim site and its verified domain.

  • Minimal merchant compromise The site infection can be as subtle as a one-line str_replace in PHP template output, making code review easy to miss and change diffs look relatively harmless.


Defender note: We’re deliberately avoiding step-by-step configs that would help reproduce the attack. The above is enough to understand and mitigate without enabling abuse.


Signs you might be affected

  • Unexpected hosts for Stripe paths Network tab shows a domain other than js.stripe.com serving /v3/ or related assets. 

  • Harmless-looking string replacements Search for str_replace('js.stripe.com', …) or similar in templates, controllers, or output filters.


Practical mitigations

  1. Enforce a site-wide CSP (most effective) Enforce a strict allow list for scripts/frames and API calls.

  2. Verify build and template sources Confirm that js.stripe.com and api.stripe.com aren’t replaced during rendering or deployment.

  3. Tighten change control: Require approvals for production template changes; monitor for post-deployment drift.

  4. Audit admin access & secrets: If a line of PHP was changed, assume credentials or update channels may be compromised.


Note on SRI: Subresource Integrity is powerful but can be hard to use with third-party libraries that change frequently. Treat CSP as your primary line of defense here.


How ThreatView helps

Toward the end, a little product talk - because this is exactly what we built ThreatView to catch:

  • File System Integrity Monitoring (FIM): Flags even a single-line change like the str_replace shown above, with diffs and who/when attribution.

  • Checkout Monitoring: Continuously monitors your checkout and validates that sensitive flows only call approved domains (e.g., js.stripe.com, api.stripe.com). 

  • Deep External Malware Scanning: Performs daily external scans of your website looking for malicious code, even when hidden behind obfuscation.


If you’d like help deploying CSP or scanning your checkout for MirrorMask-style issues, ThreatView can get you there quickly.


Responsible stance

This article aims to inform defenders and merchants. It does not include step-by-step configurations that would facilitate abuse. We have no indication of a vulnerability in Stripe; the technique relies on a local content rewrite plus a high-fidelity relay.


Summary

  • MirrorMask is a high-fidelity mirror attack that replaces Stripe’s host with an attacker-controlled domain and spoofs headers to keep everything looking legitimate.

  • The checkout still works, which lowers suspicion.

  • A robust, site-wide CSP, combined with basic change-control hygiene, would have blocked it.

  • ThreatView detects and prevents this class of attack via file integrity monitoring, checkout monitoring, and deep malware scanning.


 
 
 
bottom of page