BRITTLE COMPASS 1.2.5: an Electron stealer that rewrites Discord

The first BRITTLE COMPASS build. Asks for admin, steals browsers, wallets and files, and leaves a modified Discord client behind.

Assessment. A JavaScript stealer in an Electron “game” that asks for admin at launch, takes browser data, Discord accounts, wallets and documents, and rewrites the Discord client to keep capturing logins. High confidence in what the code is built to do; this build was analyzed statically and not run.

Nothing here says the build succeeded on any particular machine. If it ran, treat the browser’s saved passwords, cookies and cards, any wallets it targets, and the Discord account as exposed, and rebuild the Discord client from scratch. No remote-shell capability was identified in the analyzed sample; the response steps are sized to that.

Note Source summary. My own static analysis of the 1.2.5 installer and its extracted payload (reliability A, credibility 2; see How I rate things). It’s one of three builds served by the BRITTLE COMPASS lure. I didn’t run it, so behavior on a live host is inferred from recovered code.

Type
malware
Status
unknown
Confidence
high
First seen
2026-10-14
Related names
“@neverlose” (embed marker)
contents
  1. From the lure to a double-click
  2. Unpacking: a bytecode file that is mostly a string
  3. Before it steals: deciding whether you're real
  4. The steal
  5. Getting the data out
  6. Staying: rewriting the Discord client
  7. Detection and response
  8. Indicators
  9. ATT&CK mapping
  10. References

From the lure to a double-click #

The victim gets here through the fake game site described on the actor page: a Discord message, a trailer, a password, a download. What arrives is <game>-Setup-1.2.5.exe, named after the fake game, a 112 MB NSIS installer built with electron-builder. There is no game in it.

The first thing worth noticing happens before any malware runs. The Electron executable’s embedded manifest asks for requireAdministrator. The manifest is otherwise stock, so somebody changed that one line on purpose. The victim sees a Windows consent prompt from an unknown publisher, and a lot of people click Yes because games ask for weird things.

That one click is what makes the rest of this build work. Stealing Chrome’s newest cookie encryption needs a SYSTEM token, and asking for admin up front means the malware never has to bypass UAC.

What a defender can catch here: an Electron application that demands administrator rights on every launch is unusual on its own. The ELECTRON_App_Requiring_Administrator rule below looks for exactly that.

Unpacking: a bytecode file that is mostly a string #

The installed application’s app.asar holds a short chain:

main.js  ->  1a3ba0ea.js  ->  05c0aacf9088c832894b.jsc
             disables hardware acceleration, launches with --no-sandbox,
             loads the bytenode runtime, then loads the .jsc

A .jsc file is V8 bytecode produced by bytenode, which people use to ship JavaScript without shipping source. This one cheats: the 2.2 MB file is a small stub whose only job is to evaluate one enormous string constant, 1,103,046 characters of obfuscated JavaScript. The real payload never existed as bytecode at all. It was sitting in the constant pool the whole time, which made it carvable without a V8 decompiler.

Acronis documented the same Electron-plus-bytecode packaging across several fake-game stealer families in 2025 [1]. That’s a shared technique, not shared code: I haven’t matched this build’s code to any of those families, and this one also goes after Chrome’s App-Bound Encryption. The JavaScript itself is obfuscated with JS-Confuser: a string table decoded per call site with basE91 under 73 different shuffled alphabets, a constant array, control-flow flattening and a central dispatcher. Annoying, not exotic.

What a defender can catch here: a bytenode .jsc that is large and low in entropy is worth a look, because compiled bytecode is usually denser. It isn’t proof of an embedded-source stub. BYTENODE_JSC_Evaluating_Embedded_Source is a hunting rule for that shape, regardless of family.

Before it steals: deciding whether you’re real #

The payload checks for an internet connection by requesting https://google.com and quits silently if that fails. Then it decides whether it’s on a real person’s computer:

  • It runs if the machine has Steam, Riot Games, Brave or Opera data. Gamers have those; sandboxes usually don’t.
  • It quits on small machines (under 2 GB of RAM or one CPU) and on a handful of user profile paths that match known analysis-sandbox images.
  • It has a bypass: if C:\Users\AppOnFlySupport exists and the public IP, looked up through api.ipify.org, matches 88.86.117[.]130, it skips every check. That reads like the author’s own test machine, but nothing in the code treats that address as a destination, so it is an environment marker, not infrastructure.

The steal #

The payload runs one full collection immediately and repeats it every 90 minutes while the process stays alive, posting its progress to a Discord webhook as numbered steps. Those step labels are in the code verbatim:

step 1         anti-analysis, then the installed antivirus list via WMI SecurityCenter2
step 2         discord           tokens from all four Discord clients and from browser storage
step 3/1       masterkeys        Chromium key, including App-Bound Encryption
step 3/2       browsers          passwords, cookies, autofill, cards
step 4         wallets           browser extension and desktop wallets
step 5         injection         rewrite the Discord client
step 6         files             documents, keys and source code from user folders

Browsers. About 20 Chromium-family and 6 Gecko-family browsers. For Chrome’s App-Bound Encryption it enables SeDebugPrivilege, borrows the lsass.exe token to get SYSTEM, and unwraps the key with the publicly documented bypass constants. Firefox-family credentials go through nss3‘s own decryption. Saved cards, including stored verification values, are in scope.

Discord. Every token found is checked against Discord’s API and enriched: billing sources, Nitro status, badges, servers where the account has admin rights, and whether MFA is on. That enrichment is how the operator decides which accounts are worth selling or abusing.

Wallets. A dedicated collector covers 83 Chromium wallet extensions, 7 Firefox wallet extensions identified by hard-coded profile UUIDs, and 26 desktop wallet directories. A wallet hit is announced to a separate webhook with @everyone.

Files. It walks Desktop, Documents, Downloads, Pictures, Music and Videos four levels deep and takes documents, spreadsheets, .env files, SSH and TLS keys, VPN and RDP profiles, password databases, archives and source code up to 200 KB each, and images up to 5 MB. This is the build that takes the key material a responder worries about.

Screenshots. A full-screen capture every 60 seconds, to its own webhook, for as long as the process runs.

Getting the data out #

Small things go straight to Discord. The browser archive is posted unencrypted to the main webhook, and some username and password pairs are posted in clear text inside a Discord embed.

Wallet and file archives are handled more carefully. Each is encrypted with a fresh AES-256-GCM key, that key is wrapped with one of two embedded RSA-4096 public keys, and the result is uploaded to Gofile, falling back to Catbox, under a random .fix file name. The download link goes to the webhook. With only the uploaded archive in hand, you can’t open it: that takes the RSA private key or that archive’s own AES key.

What a defender can catch here: an unexpected process posting to discord.com/api/webhooks/ and uploading to gofile.io or catbox.moe is the network signature of this stage. Gofile and Catbox are shared services, so block the behavior, not the domains.

Staying: rewriting the Discord client #

I found no scheduled task, no Run key and no Startup entry in this build, so the stealer itself has no established way to start again. What persists is the change it makes to the Discord client. Because this is static analysis, that’s what the code writes, not an observed restart. It kills Discord, then overwrites discord_desktop_core\index.js in every Discord install with its own code plus the original one-line re-export, so Discord still starts normally:

%LOCALAPPDATA%\Discord*\app-*\modules\discord_desktop_core-*\discord_desktop_core\index.js
    <injected code> ... module.exports = require("./core.asar")

From then on, every time Discord starts, the injected code:

  • clears Discord’s session and forces the victim to log in again, so the credentials get captured fresh;
  • watches login, registration, two-factor setup and password or email changes through the Chrome DevTools protocol, and sends the password, token and TOTP secret to a dedicated webhook;
  • blocks QR-code login and the session-listing, logout and handoff endpoints, so the victim can’t see or kill the operator’s sessions.

That last part is why “change your Discord password” is not enough. Changed on the infected machine, the new password goes straight to the operator.

What a defender can catch here: the stock index.js I compared against is a single line under 100 bytes. A much larger one that still re-exports ./core.asar is a strong lead that it’s been modified. Check it against a clean copy of the same Discord version before concluding. DISCORD_DESKTOP_CORE_INDEXJS_TAMPERED is a broad hunting rule for this whole family of grabbers, and the cheapest estate-wide sweep.

Detection and response #

If this build may have run, do these now, in order:

  1. Take the machine off the network, and don’t sign in to anything on it until it’s cleaned.
  2. From a different, clean device, revoke sessions, then change passwords: email first, then Discord, Google and anything saved in the browser.
  3. On Discord, from that clean device, sign out every session, then remove and re-enroll two-factor so a new secret is issued. The injected client can capture TOTP setup secrets, so treat the existing one as potentially exposed.
  4. Move cryptocurrency to wallets created on a clean device.
  5. On the infected machine, uninstall Discord and delete its application data, remove the fake game and the leftover paths under Indicators, then reinstall Discord. Rebuilding the machine is safer; no remote-shell capability was identified in this sample, so a careful cleanup is a reasonable minimum.
  6. Rotate keys from user folders (SSH, VPN profiles, RDP credentials, password databases) and reissue payment cards that were saved in a browser.

To find other affected machines, compare the size of discord_desktop_core\index.js against the stock file everywhere someone may have run a “beta game”, and alert on Electron executables that require administrator rights and on large bytenode stubs.

YARA #

Each rule matched its target file. None has been tested against a broad benign corpus, and the last two are deliberately broad hunting rules, so tune before production use.

import "math"

rule BC_125_Bytenode_Stage2_JSC
{
    meta:
        description = "BRITTLE COMPASS 1.2.5 stage 2: bytenode V8 code cache carrying the JS-Confuser grabber source"
        sha256 = "af923f46107b6c072c7dfc97abd5b9fff4cf60ded3ce084b162e53af41e8adc2"
    strings:
        $t_arr  = "q7oR6F"  wide
        $t_tbl  = "QIVWvP"  wide
        $t_disp = "nqYHZHr" wide
        $t_anti = "S3Lozrk" wide
    condition:
        uint32(0) == 0xC0DE0674 and 3 of them
}

rule BYTENODE_JSC_Evaluating_Embedded_Source
{
    meta:
        description = "Any large bytenode .jsc that is only a stub evaluating an embedded source string"
    strings:
        $eval = "evalmachine" ascii
    condition:
        uint32(0) == 0xC0DE0674 and filesize > 200KB and $eval
        and math.entropy(0x100, filesize - 0x100) < 4.5
}

rule DISCORD_DESKTOP_CORE_INDEXJS_TAMPERED
{
    meta:
        description = "discord_desktop_core index.js that re-exports ./core.asar but is far larger than the stock one-line file"
    strings:
        $r1 = "require('./core.asar')" ascii
        $r2 = "require(\"./core.asar\")" ascii
    condition:
        filesize > 1KB and filesize < 20MB and any of them
}

rule ELECTRON_App_Requiring_Administrator
{
    meta:
        description = "Electron main binary whose manifest demands requireAdministrator"
    strings:
        $mani = "requestedExecutionLevel level=\"requireAdministrator\"" ascii
        $e1   = "Electron/" ascii
        $e2   = "Chrome/" ascii
    condition:
        uint16(0) == 0x5A4D and filesize > 5MB and all of them
}

Indicators #

Files
Type Indicator Context First seen (UTC)
SHA-256 6a1f7c820fcc93c156a05102b604837ca11c45aecb1e177d00ce85ada7c5ba07 Installer, <game>-Setup-1.2.5.exe, 112,299,202 bytes 2026-10-14
SHA-256 811e6a4977416f54c4686c06a3345dd4fe19592026c2e1d3d215dd005004c6df app.asar, 11,087,494 bytes 2026-10-14
SHA-256 af923f46107b6c072c7dfc97abd5b9fff4cf60ded3ce084b162e53af41e8adc2 05c0aacf9088c832894b.jsc, stage 2, 2,207,552 bytes 2026-10-14
SHA-256 4995d43cff3eba268b0b2a9389bb7965d4388a265bbbccac1725702f10be9573 Reconstructed modified Discord index.js, 255,631 bytes 2026-10-14
MD5 ffa51718804a600e5e7a136f7a724ebe Installer 2026-10-14
SHA-256 (SPKI) 41173a71d9f7f346c280a4ba086944518023c07f07d199bee50a73959d477e70 Embedded RSA-4096 public key that wraps archive keys 2026-10-14
SHA-256 (SPKI) f1622de6b7d8436ecd27933a4b570a260499a954687922eba1b6fb85b709ff7d Second embedded RSA-4096 public key 2026-10-14
Network. Webhook tokens are withheld; the IDs are enough for Discord to act on and for network matching
Type Indicator Context First seen (UTC)
Discord webhook ID 1553041811025563698 Status and browser-archive reporting 2026-10-14
Discord webhook ID 1553041959843663904 Screenshots every 60 seconds 2026-10-14
Discord webhook ID 1550267932406194276 Wallet-hit alerts, on canary.discord.com 2026-10-14
Discord webhook ID 1553041879140929577 Credentials captured by the Discord-client injection 2026-10-14
Discord server ID 1549436092535541861 Holds the webhooks; created 2026-09-15 per its snowflake 2026-10-14
URL hxxps://<server>.gofile[.]io/contents/uploadfile Encrypted archive upload. Shared service 2026-10-14
URL hxxps://catbox[.]moe/user/api.php Fallback upload. Shared service 2026-10-14
IPv4 88.86.117[.]130 Environment marker compared against the public IP. Not a destination 2026-10-14
Host
Type Indicator Context
Path %LOCALAPPDATA%\*-updater\installer.exe Full installer copy left by the electron-builder installer; survives a normal uninstall
Path %APPDATA%\<game>\ Application data, named after the fake game; survives a normal uninstall
Path C:\Users\AppOnFlySupport Environment check only; not created by the malware
File name <8 random characters>.fix Encrypted archive uploaded to Gofile or Catbox
String @neverlose Discord embed footer
GUID 9167a1b4-4045-5fc3-81fe-2cb56a321807 Installer GUID

ATT&CK mapping #

Tactic Technique Procedure
Execution User Execution: Malicious File (T1204.002) Victim runs a fake game installer
Execution Command and Scripting Interpreter: JavaScript (T1059.007) Payload runs as JavaScript inside Electron
Privilege Escalation Access Token Manipulation (T1134) Borrows the lsass.exe token for SYSTEM
Defense Evasion Obfuscated Files or Information (T1027) Bytenode stub, JS-Confuser, basE91 string table
Defense Evasion Virtualization/Sandbox Evasion: System Checks (T1497.001) RAM, CPU, profile and installed-software checks
Defense Evasion Masquerading (T1036) Stealer distributed as an indie game
Persistence Compromise Host Software Binary (T1554) Overwrites Discord’s index.js
Credential Access Credentials from Web Browsers (T1555.003) Chromium and Gecko credential stores
Credential Access Steal Web Session Cookie (T1539) Browser cookies, Discord tokens
Discovery Software Discovery: Security Software Discovery (T1518.001) WMI SecurityCenter2 antivirus list
Collection Screen Capture (T1113) Screenshot every 60 seconds
Collection Data from Local System (T1005) Documents, keys and wallets from user folders
Exfiltration Exfiltration Over Web Service: Exfiltration to Cloud Storage (T1567.002) Gofile and Catbox uploads
Exfiltration Exfiltration Over Web Service (T1567) Discord webhooks

References #

  1. Acronis Threat Research Unit, “Threat actors go gaming: Electron-based stealers in disguise”, July 2025. acronis.com (opens in a new tab) (B2: earlier fake-game stealers using the same Electron-plus-bytecode packaging; technique comparison only)

tags

  • infostealer
  • electron
  • bytenode
  • discord
  • cryptocurrency
  • fake-game-lure

found an error? send it in. corrections are dated and logged on the page.