Skip to the content.

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:

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:

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

How to verify (v0.4.15 / v0.4.16)

  1. 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.)
  2. Extract: npx @electron/asar extract "<install>\resources\app.asar" out, open out/out/main/index.js.
  3. Confirm the four identifiers are absent in plaintext and base64 (e.g. search GRIP-EMS, gse-legacy, and the base64 R1JJUC1FTVMubHVh from the v0.4.14 build - all return nothing).
  4. Find the engine: search the embedded key b531cb8b505ae9752b5b789f26085853b0ba5da5d7e7e244975f0545430d683a, the sign.detached.verify call, the companion:request event handler, and the interpreter case labels listFiles / read / deleteKeys / setKey / write.
  5. v0.4.16 only: confirm detectPattern returns nothing and integrityRef is present; confirm the event field is task, not directive.
  6. Live flag: curl https://api.gse.tools/settings/access-policy.

File integrity (SHA-256)

v0.4.15 (acquired 2026-06-20):

v0.4.16 (acquired 2026-06-20):

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.