Skip to the content.

Update 2026-07-09 (v0.4.20 to v0.4.22): the diagnostic upload now reads arbitrary addon files, and your error logs get attached

Three more Companion builds shipped since the last update: 0.4.20, 0.4.21, and 0.4.22. The detection, account-flag, and ed25519-signed file-modification engine documented for 0.4.15/0.4.16 are unchanged at every marker. Two of these builds widened what the app can read off your disk and send to GSE’s server. I also ran the current build under a decrypted capture; the new paths did not fire in that window, and I say so plainly below. As always: I am a competitor, so verify it yourself. Every claim is a line you can read in the shipped file.

Build hashes are in hashes.txt. The installed 0.4.22 app.asar I read is byte-identical to the installer extract, so this is the code that runs.

What changed in each build

The signed engine, stated plainly

The ed25519-signed, server-pushed engine can read, delete entries from, change entries in, and rewrite any .lua file under your WTF\ folder. That is any addon’s SavedVariables, not only GSE’s. It runs only if the message carries a valid GSE signature, matches your account, has not expired, and WoW is closed. It is not gated by the enforce flag. That flag only retired the older fixed deletion routine and greys out buttons in the app; a validly signed plan runs whether enforce is true or false. It cannot write or delete addon source files, because its scope is .lua files under WTF\ only.

What I ran, and what I did not find

I installed 0.4.22, signed in, with GRIP-EMS present on disk and WoW closed, and watched it for about 30 minutes under a decrypted TLS capture, including two manual syncs I triggered myself. In that window the app did only GSE content sync. No companion:request directive arrived. Nothing read or wrote a file outside GSE’s own data. No diagnostic upload fired. The enforce flag read false the whole time, both for my signed-in account and anonymously. No .svmnt.tmp file (the signature the rewrite routine leaves) ever appeared, and my GRIP-EMS.lua was byte-for-byte unchanged from before.

So the capabilities are in the shipped code, and I did not catch them being used against me in that window. Both halves are true and I am stating both. A 30-minute capture is a window, not a proof of a negative; the signed engine is armed whenever GSE chooses to send a signed plan.

Two more limits, for honesty: the event-stream body itself was not rendered by the proxy (it does not buffer streamed responses), so I am inferring “no directive” from the absence of the file writes and uploads a directive would cause, not from reading the stream. And the four GRIP-EMS identifiers are absent from all three builds in every encoding I tried (18 encodings plus split-string checks), so the detection target is supplied by the server, not written in the client.

Verify it yourself

  1. Download the build from gse.tools/releases and open %LOCALAPPDATA%\Programs\gse-companion\resources\app.asar (extract with npx @electron/asar extract app.asar out, or read it with a text editor).
  2. In out/main/index.js, read these four things:
    • the capture engine: search capture-denied; the roots function returns Interface/AddOns and WTF; the reader caps files at 4 * 1024 * 1024 and reads them as text with no type check.
    • the trigger: search companion:request; the branch with no task and no idx passes kinds and paths to the unsigned upload.
    • the signed engine scope: search for the writer that writes a .svmnt.tmp file and renames it over the target, and the scope check that requires the path to end in .lua and sit under WTF.
    • the error-log gather: search the regex /^!?Bug(Grabber|Sack)\.lua$/ and the errorLog: entries it produces.
  3. Check the live flag: curl https://api.gse.tools/settings/access-policy.

Files in this update

Scope

This documents behaviour in distributed software, from quoted code and a runtime capture. It is not a claim about anyone’s character, and it does not cover community moderation or account bans. Read the file and reach your own conclusion.