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:
- 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.)
- Extract the app logic:
npx @electron/asar extract "<install>\resources\app.asar" out, then openout/out/main/index.js. - Search for the decoder and the four base64 literals:
R1JJUC1FTVMubHVh,R1JJUF9FTVNfQ0hBUg==,cHJvdmVuYW5jZVNvdXJjZQ==,Z3NlLWxlZ2FjeQ==. - Decode them (any platform): for example in Node,
Buffer.from("R1JJUC1FTVMubHVh","base64").toString()printsGRIP-EMS.lua. On Linux/macOS,echo R1JJUC1FTVMubHVh | base64 -d. - Read the surrounding functions (
Rs/Bs,Us,Ks,At,_o,zs) and confirm the flow: detectGRIP-EMS.lua-> PATCHrestrictedAccounttoapi.qik.dev-> readenforcefromapi.gse.tools/settings/access-policy-> if present and enforced and WoW closed, delete fromGRIP_EMS_CHAR.sequences. - Confirm the live flag:
curl https://api.gse.tools/settings/access-policy.
File integrity (SHA-256), v0.4.14, acquired 2026-06-20
- GSE Companion Setup 0.4.14.exe:
24b64bc72d9c56095c7c92b331842a205be6dd3f23830dddab4a850f9f58dbd0(81,296,884 bytes) - resources/app.asar (0.4.14):
217ff61e074d421ed418f12d47f7f342c09eba9d8c15c4a5bc59fc746ff7229e - out/main/index.js (0.4.14 app logic):
9c8c9588f7a749c81fb710de73e98899ca516f56cdb004fa82547315b5f0239d
What I am not claiming
- I am not claiming the deletion is currently switched on. The
enforceflag readsfalsetoday and is server-controlled; I cannot see GSE’s intent for it, only its current value. - The change from plaintext to base64 is a verifiable fact (compare the two builds). That the purpose of that change was to hide the code from the search steps I published is my inference. I think it is the obvious one, given the timing and that only my addon’s identifiers were encoded, but you can read both builds and judge for yourself.
- The detection and
restrictedAccountaccount-flagging run whenever a user is signed in, on a ten-minute timer. That is in the shipped code and runs today.
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.