Skip to the content.

Update 2026-06-20: GSE Companion v0.4.14 obfuscates the competitor-targeting code after disclosure

Published: 2026-06-20 Author: Jesper (JesperLive / MrSataana), developer of GRIP - Enhanced Macro Sequencer (GRIP-EMS) Subject software: GSE Companion v0.4.14 (desktop app), distributed from https://gse.tools/releases Continues: the 2026-06-12 disclosure in this repository (README.md), which documented v0.4.12.


Read this first

I am the author of GRIP-EMS, a competing addon. Do not take my word for any of this. Every factual claim below is a line you can read in the shipped file yourself, and the steps to reproduce are at the bottom. The one new fact in this update is simple and checkable: the code I documented on 2026-06-12 is still in the app, doing the same thing, but in v0.4.14 the parts that name my addon were changed from plain text to base64 so they no longer turn up in a search.

One-paragraph summary

On 2026-06-12 I documented an “access-policy” subsystem in GSE Companion v0.4.12 that detects my addon’s save file (GRIP-EMS.lua), reports its presence to GSE’s backend and flags the user’s account (restrictedAccount), and carries a server-gated routine that deletes sequences out of my addon’s save file. That disclosure listed the exact function names to search for. In v0.4.14, released after that disclosure, the subsystem is unchanged in behavior, but the four identifiers that name my addon are now base64-encoded and decoded at runtime, and the descriptive function names are gone. A search of v0.4.14 for the terms in my published reproduction steps now returns nothing. The behavior was not removed; it was hidden.

What changed, and only what changed

Before (v0.4.12 and v0.4.13): plaintext

In the v0.4.12 application logic (saved extract evidence/app_asar_grip_region.js in this repository, app.asar 209aded…b0f), the identifiers are plain text:

line 635:  GRIP-EMS.lua
line 805:  GRIP_EMS_CHAR
line 813:  provenanceSource
line 814:  gse-legacy

and the functions are named in plain English: detectGripEmsAcrossClients, syncRestrictedAccountFlag, fetchAccessPolicy, runAccountCleanup, purgeGripCharSequences, runAccessPolicyCheck, plus the constants GRIP_SV_FILENAME and ACCESS_POLICY_REFRESH_MS. My 2026-06-12 README re-verified v0.4.13 and found this region byte-identical to v0.4.12.

After (v0.4.14): base64

In v0.4.14 (app.asar 217ff61…29e, out/main/index.js 9c8c95…39d) those four identifiers do not appear in plain text anywhere in the file. They exist only as base64 string literals on one line, decoded at runtime by a small helper (line 551):

const kt = (e) => Buffer.from(e, "base64").toString("utf8"),
  Rt = kt("R1JJUC1FTVMubHVh"),            // -> "GRIP-EMS.lua"
  Ms = kt("R1JJUF9FTVNfQ0hBUg=="),        // -> "GRIP_EMS_CHAR"
  Vs = kt("cHJvdmVuYW5jZVNvdXJjZQ=="),    // -> "provenanceSource"
  Ns = kt("Z3NlLWxlZ2FjeQ==");            // -> "gse-legacy"

These four are the only base64-encoded string literals in the application code. (The app does use base64 the ordinary way too: at line 309 it base64-decodes the import strings a user pastes. That is decoding user input, not a hidden constant.) Every other string in the 3,240-line file, including its own filenames, the API URLs and the GSE table names, is plain text. The only strings that were encoded are the ones that name my addon and my addon’s save-file schema.

The descriptive function names were also stripped (the build is minified). They left one tell: a code comment at line 2543 still reads // tally from runAccountCleanup(), which ties the now- renamed function back to the runAccountCleanup named in v0.4.12.

Same code, renamed

The logic is identical to what I documented on 2026-06-12. The mapping:

v0.4.12 (plaintext name)        v0.4.14 (minified)
detectGripEmsAcrossClients  ->  Bs / Rs        (scan WoW folders for GRIP-EMS.lua)
syncRestrictedAccountFlag   ->  Us             (PATCH restrictedAccount to api.qik.dev)
fetchAccessPolicy           ->  Ks             (GET api.gse.tools/settings/access-policy)
runAccessPolicyCheck        ->  At             (orchestrator: login + auth:me + 10-min timer)
runAccountCleanup           ->  _o             (loop over every GRIP-EMS.lua found)
purgeGripCharSequences      ->  zs             (delete sequences from GRIP-EMS.lua)
GRIP_SV_FILENAME            ->  Rt (base64)
ACCESS_POLICY_REFRESH_MS    ->  $o  (= 10 * 60 * 1000)

The verbatim v0.4.14 code for all of this is in evidence/app_asar_grip_region_0.4.14.js in this repository. The deletion gate is unchanged (line 2563):

if (ie.restricted && ie.enforce)   // GRIP-EMS present AND server flag on -> purge

and the deletion itself (zs, line 703) still reads parsed.GRIP_EMS_CHAR.sequences and removes every sequence whose provenanceSource === "gse-legacy" or whose name matches one of the user’s GSE sequences, then rewrites the file atomically.

Current live state (captured 2026-06-20)

A direct request to the server flag the deletion is gated on:

GET https://api.gse.tools/settings/access-policy  ->  {"enforce":false,"updatedAt":null}

So the deletion is not switched on right now. As before, this flag is server-controlled and can be changed by GSE at any time; the detection and the restrictedAccount account-flagging run regardless of it, on login and every ten minutes.

How to verify v0.4.14 yourself

The search terms in my 2026-06-12 steps no longer work on this build by design. Use these instead:

  1. Download GSE Companion v0.4.14 from https://gse.tools/releases. (As of 2026-06-21 the current release is v0.4.16; the releases page may no longer carry v0.4.14. If so, verify the SHA-256 of a copy you have against the hashes below instead.)
  2. Extract the app logic: npx @electron/asar extract "<install>\resources\app.asar" out, then open out/out/main/index.js.
  3. Search for the decoder and the four base64 literals: R1JJUC1FTVMubHVh, R1JJUF9FTVNfQ0hBUg==, cHJvdmVuYW5jZVNvdXJjZQ==, Z3NlLWxlZ2FjeQ==.
  4. Decode them (any platform): for example in Node, Buffer.from("R1JJUC1FTVMubHVh","base64").toString() prints GRIP-EMS.lua. On Linux/macOS, echo R1JJUC1FTVMubHVh | base64 -d.
  5. Read the surrounding functions (Rs/Bs, Us, Ks, At, _o, zs) and confirm the flow: detect GRIP-EMS.lua -> PATCH restrictedAccount to api.qik.dev -> read enforce from api.gse.tools/settings/access-policy -> if present and enforced and WoW closed, delete from GRIP_EMS_CHAR.sequences.
  6. Confirm the live flag: curl https://api.gse.tools/settings/access-policy.

File integrity (SHA-256), v0.4.14, acquired 2026-06-20

What I am not claiming

Additional observation (separate from the above): unsigned auto-update

While reading v0.4.14 I also noted that the app’s auto-updater downloads an installer from https://api.qik.dev/file/<id> and runs it silently (spawn(file, ["/S","--force-run"]) on Windows) with no signature or hash check, and autoApplyUpdates defaults to on. This is a general software-security weakness, not part of the competitor-targeting above: anyone able to compromise or impersonate that endpoint could push an executable that runs on users’ machines. I note it here only for completeness.