Update 2026-06-21: v0.4.15 turned the deletion routine into a signed, server-pushed file-modification engine; v0.4.16 renamed the parts that still named my addon
Published: 2026-06-21
Author: Jesper (JesperLive / MrSataana), developer of GRIP - Enhanced Macro Sequencer (GRIP-EMS)
Subject software: GSE Companion v0.4.15 and v0.4.16 (desktop app), distributed from https://gse.tools/releases
Continues: the 2026-06-12 disclosure (README.md, v0.4.12) and the 2026-06-20 update (v0.4.14 base64).
Read this first
I am the author of GRIP-EMS, a competing addon. Don’t take my word for any of this. Every factual claim below is a line you can read in the shipped file, and the steps to reproduce are at the bottom. Two builds have shipped since my last update and this covers both. I also ran the current build live, and I am reporting what the server actually did, including the parts that do not support my side.
One-paragraph summary
In v0.4.14 the code that names my addon was hidden with base64 but still ran. In v0.4.15 GSE removed those names from the binary entirely and changed the design: the single-purpose routine that deleted sequences from my addon’s save file was replaced with a general, cryptographically signed, server-pushed file-modification engine, and the detection target was moved off the binary onto the server. v0.4.16, built twelve minutes after v0.4.15, renamed the two remaining server-facing fields to blander words and deleted the comments that explained them. The capability in the current build is remote, signed deletion or modification of any addon’s saved data while WoW is closed. A live instrumented run on 2026-06-21 found it dormant: the server was not sending the trigger.
v0.4.15 - the three changes
1. The four identifiers are gone. In v0.4.14 the strings GRIP-EMS.lua, GRIP_EMS_CHAR,
provenanceSource, and gse-legacy were present as base64. In v0.4.15 they are not in the binary in any
encoding I checked - plaintext, base64 (standard, url-safe, no-pad), hex, reversed, decimal char-codes,
and percent-encoding all return nothing, across the main process, the renderer, and the preload bundle.
The fixed “delete GRIP_EMS_CHAR sequences tagged gse-legacy” routine and the runAccountCleanup comment
are also gone.
2. Detection moved to the server. The access-policy fetch now returns a server-supplied field, and the
client does a read-only presence scan for whatever filename the server names, then sets the per-account
restrictedAccount flag. With no value sent (the current state), nothing scans. The competitor filename
is no longer hard-coded in the app; the server supplies the target at runtime.
3. The fixed purge became a signed remote engine. This is the main change. The app subscribes to a
server event stream (/events/subscribe); a directive on that stream is verified by an ed25519 signature
and then executed by a small interpreter that can list, read, delete-keys-from, and rewrite saved-variable
files. Verbatim chain (full code in evidence/companion_0.4.16_command_engine.js):
// signature gate - only a directive GSE signed will run
function go(e){ if(!e||typeof e.sig!="string"||!e.sig.startsWith("v2:")) return null;
... return Vs.sign.detached.verify(o,s,ho) ? n : null; } // tweetnacl verify vs embedded key ho
// handler - run only if signed, not expired, persona matches, WoW closed
async function Po(e){ const t=go(e); if(!t||t.exp&&Date.now()>t.exp) return;
... if (WoW running) { report "wow_running"; return; }
c = uo(t.plan,{wowPaths:n.wowPaths??[]}); // run the plan
xt(t.nonce,{ok:!0,...c}); } // POST result to /diagnostic/result/<nonce>
// interpreter ops
case "listFiles": ... case "read": ... case "deleteKeys": ... case "setKey": ... case "write": ...
The interpreter’s reads and writes are restricted to .lua files under the user’s configured WoW folders,
and a write is an atomic replace. tweetnacl was added as a dependency in v0.4.15 to verify these
directives. In plain terms: a directive GSE signs can delete entries from, or overwrite, any addon’s
saved-variables file on a targeted machine when WoW is closed, and report back what it changed. No prompt
is shown at execution.
v0.4.16 - rename and strip
Only one source file changed from v0.4.15. Comparing the whole installer payload: of 96 files, only
app.asar and the launcher GSE Companion.exe differ, and the exe delta is 64 bytes - a version-string
stamp plus the embedded asar-integrity hash, no code. Inside out/main/index.js, the entire semantic
change is three edits:
detectPatternrenamed tointegrityRef(the server detection field).directiverenamed totask(the signed-command field on the event stream).- four comments next to the enforcement state were deleted.
The rest of the diff is the minifier reassigning short variable names. The signature gate, the embedded
public key, the interpreter and all of its operations are byte-identical to v0.4.15. The two fields that
were renamed - detectPattern and directive - are the two most self-describing names a reader would
search for; the blander replacements (integrityRef, task) are what is in the binary now.
The embedded key and the gates (unchanged in both builds)
go() verifies a v2: ed25519 signature with tweetnacl against an embedded public key:
b531cb8b505ae9752b5b789f26085853b0ba5da5d7e7e244975f0545430d683a
It is the only 64-hex constant in the binary and did not change between v0.4.15 and v0.4.16. A plan runs
only with a valid GSE signature, before expiry, matching the signed-in persona, with WoW closed, scoped to
.lua under your WoW paths. This is GSE-authenticated, scoped modification - not arbitrary external code
execution. The concern is the capability itself and who holds the signing key.
Runtime check (2026-06-21) - what the server actually did
I ran v0.4.16 under an HTTPS intercept on my own machine, signed in, with WoW closed (the only state in which a plan executes), for about half an hour across two launches and an idle watch. What the server sent:
/settings/access-policyreturned{"enforce":false,"updatedAt":null,"integrity":"verified"}on every poll. No detection pattern was sent.- The app connected to the event stream seven times; no signed plan and no command directive arrived over it.
- Nothing under my addon’s saved-variables was read, modified, or deleted - the app only checked file timestamps as part of a general change-watcher that stats every addon’s save file.
So the engine is present and was not exercised in this window. The server returns a field named integrity
while the v0.4.16 client reads integrityRef, so that field is, in this build, inert in the client.
What I am not claiming
- I am not claiming any deletion or modification occurred. None did, in what I observed;
enforceis false and no plan was sent. The flag is server-controlled and I cannot see GSE’s intent for it. - That v0.4.16’s renames were meant to defeat the search terms in my earlier write-ups is my inference - from the twelve-minute gap after v0.4.15 and from the fact that the changed fields are exactly the self-describing ones. Both builds are public; read them and judge.
- The detection and account-flag paths are written to run on login and a timer. In this build the account-flag request is currently malformed and fails server-side; that is a bug, not a removal.
How to verify (v0.4.15 / v0.4.16)
- Download GSE Companion v0.4.15 or v0.4.16 from https://gse.tools/releases. (v0.4.16 is the current release as of 2026-06-21; v0.4.15 may no longer be on the page. For any build, verify its SHA-256 against the hashes below.)
- Extract:
npx @electron/asar extract "<install>\resources\app.asar" out, openout/out/main/index.js. - Confirm the four identifiers are absent in plaintext and base64 (e.g. search
GRIP-EMS,gse-legacy, and the base64R1JJUC1FTVMubHVhfrom the v0.4.14 build - all return nothing). - Find the engine: search the embedded key
b531cb8b505ae9752b5b789f26085853b0ba5da5d7e7e244975f0545430d683a, thesign.detached.verifycall, thecompanion:requestevent handler, and the interpretercaselabelslistFiles/read/deleteKeys/setKey/write. - v0.4.16 only: confirm
detectPatternreturns nothing andintegrityRefis present; confirm the event field istask, notdirective. - Live flag:
curl https://api.gse.tools/settings/access-policy.
File integrity (SHA-256)
v0.4.15 (acquired 2026-06-20):
- GSE Companion Setup 0.4.15.exe:
d516415c9b1ff83c8d1796b071581ef76763511576999018de16076649224a02(81,322,606 bytes) - app.asar (0.4.15):
2e734950eea97015bbf2e69f601da128f28e42de01735f1382033625add3b5e2 - out/main/index.js (0.4.15):
6b13343b4ab4218a37f68080f1bd1a0e0d37dc5c355b68c5dd21a408b806ffc4(128,949 bytes)
v0.4.16 (acquired 2026-06-20):
- GSE Companion Setup 0.4.16.exe:
264013e8d6508a2cb5b04ac92f22ed5498a8dd38804b91e342ca7fadd1981026(81,322,563 bytes) - app.asar (0.4.16):
84a72f8636c07f1821cba22ff85aae65c530442ae197bc6149922482c8131b70 - out/main/index.js (0.4.16):
5271373bd3de213973282172aa339002dc71c2c88fed39efb13249fbcb078cc2(128,766 bytes)
Native modules are unchanged from v0.4.14 (stock packages): cbor-extract 36c2d44b..., ps-list fastlist
x64 d1a71f9a..., x86 017411f3....
Auto-updater (still unsigned)
Unchanged from v0.4.14: the updater downloads an installer from https://api.qik.dev/file/<id> and runs it
(spawn(file, ["/S","--force-run"]) on Windows) with no signature or hash check, with auto-apply on by
default. The ed25519 verification added in v0.4.15 for the command engine was not applied to updates.