Attackers turn NIKKE’s game launcher into malware

Attackers turn NIKKE’s game launcher into malware

Bitdefender researchers investigated a credential theft campaign that delivered a full-featured info stealer via the NIKKE game launcher.

Goddess of Victory: NIKKE is a free-to-play sci-fi RPG shooter developed by Shift Up and published by Level Infinite for PC, iOS and Android. According to the publisher's October 2026 announcement, the game has recorded more than 45 million downloads worldwide since launch.

Attackers remotely instructed the launcher for the popular free-to-play game to download and execute the payload on the players' machines. They used the server-pushed task channel (which is what tells the client what to download and run).

They didn't patch a binary, exploit a vulnerability or drop a malicious file into the game distribution. The payload was a Lua-based stealer (which we call k2f-agent) that arrived as obfuscated LuaJIT bytecode in the form of a perfectly ordinary log file.

Running inside the launcher's embedded browser engine, the k2f-agent can harvest saved passwords and cookies from Chrome, Edge, and Opera, including those protected by Chrome's App-Bound Encryption.

The malware also targets five crypto wallet browser extensions: MetaMask, Phantom, Coinbase Wallet, Keplr and TronLink.

It can also collect SSH keys, GPG keys, Git credentials, Kubernetes configs, environment variables, shell history, Windows Credential Manager entries, NuGet.Config and the PowerShell profile.

Stolen data is carried along with the launcher's normal outbound traffic. The download, collection, exfiltration, and cleanup all took less than 10 minutes and left very few malicious artifacts.

The domain hosting the payload was registered about five weeks before the attacks, and the hosting provider in Iceland took the server down quickly.

Key Takeaways

  • Attackers delivered a stealer through NIKKE’s legitimate launcher. They used its server-pushed task channel without patching a binary.
  • The payload hid in a log file and ran inside the signed launcher process. The Lua-based k2f-agent contains 46 modules for credential theft, file collection and remote commands.
  • Its targets include browser passwords, cryptocurrency wallets and developer secrets. The stealer supports Chrome’s App-Bound Encryption and targets MetaMask, Phantom, Coinbase Wallet, Keplr and TronLink.
  • Stolen data travels through the launcher’s existing telemetry connection. Download, collection, exfiltration, and cleanup are complete in under ten minutes, leaving few malicious traces on disk.
  • Bitdefender detected and blocked the attack on the protected systems we observed. On those systems, the Advanced Threat Defense feature terminated the launcher before it could exfiltrate personal information.
  • The malicious delivery server has been taken down. The operators’ identities and how they gained control of the launcher’s task channel remain unknown. We have no evidence that the game’s developer or publisher was involved in the attack.

An anomaly in our insights

We started looking into this following a spike in our detections involving the Goddess of Victory (NIKKE launcher). The binary's main process was reading browser credential stores, even though it was a signed, legitimate binary.

The detections started on 30th October and carried on through the weekend.

A Reddit post came up at the same time Bitdefender was flagging the game launcher itself, and the poster wasn't sure whether it was a false positive or an actual infection.

We confirmed that the launcher was stealing credentials.

Payload delivery through the launcher

The server-pushed task channel

The NIKKE launcher is built on a game platform framework. The client-side architecture has a persistent client-server task channel (internally referred to as a CGI task manager). On login, the launcher queries its backend for tasks.

An embedded downloader then takes the URLs from those tasks and downloads the files to disk. The backend provides the URLs at runtime, so the same launcher build can download from any URL passed through the channel.

On the day of the attack in question, the launcher logged in and requested tasks. It queued the following download 1.6 seconds after the response had come back:

CGIMgr::FireEvents.OnCGITaskRsp, task_id=1073741867, result=0, rsp_code=200
tiny_downloader::TinyDownloader::AddTask.add task, task_id=2147483648,
    url=https://analytics.insightjs[.]com/comm/assets/insight.bundle

Freshly registered infrastructure

During the attack analytics.insightjs[.]com resolved to 89.127.233.127, which is a server in Iceland. The domain records show that insightjs[.]com was registered on 27th September 2026, about five weeks before the attack.

The name appears to have been chosen to resemble the existing open-source analytics library 'insight.js' and give the impression of legitimacy; we have no indication that the library or its maintainers are involved.

Payload disguised as a log file

The downloader saved the 205,135-byte response to:

Launcher\log\tinyget\tinyget.20261103-030255-271.log

The file was in the launcher's log directory and followed the standard download/log naming convention. It was a fairly standard log file, except that it contained LuaJIT 2.1 bytecode (the \x1bLJ magic), which is just compiled Lua (stripped of all debug info).

We searched every shipped executable, DLL, config file and archive in a variety of encodings and couldn't find the delivery URL. It's likely in a server response at runtime because we couldn't find it in the install files themselves.

Execution through the JavaScript-to-native bridge

A CEF build of Chromium 94 gives us the launcher interface. The embedded browser engine (CEF) has a well-documented JS-to-native bridge whereby JS in the webview can call call_service(<name>, <json>) and the launcher's service dispatcher will then pass that call on to a registered native or Lua handler.

When the downloaded bundle loads, its entry module registers a new service, k2f_chan, on this bridge:

local comm = rawget(_G, "comm_center")
if type(comm) == "table" and type(comm["reg_service"]) == "function" then
    comm["reg_service"]("k2f_chan", handler)
end

This registration then establishes the attacker's command channel. From that point on, the execution chain remains entirely within the legitimate launcher process. That's why the behavioral telemetry attributed the credential theft to a signed, trusted executable:

C2 server ── CGI task response ──> launcher downloader ──> disguised .log (LuaJIT bytecode)
        ──> launcher's Lua VM loads bundle ──> k2f_chan service registered
        ──> remote operator issues JSON ops over the JS bridge
        ──> launcher process performs file/crypto/registry operations

The malicious logic isn't in the shipped files. Memory forensics found all k2f-related strings and code artifacts in the launcher process's unbacked heap memory, with none present in any modules on disk.

The payload: k2f-agent, a 46-module stealer in a log file

We recovered the bundle and decompiled the LuaJIT bytecode. The payload is using a standard Lua obfuscator with a 1790-entry encrypted string table and a table permutation prelude. There are two bespoke decoders, one for a custom alphabet base64 and one for base85.

We've built a full offline decoder to recover the full plaintext source, including the real module names. The payload also has the build tag K2F_LUA_BUILD = "722b99d8d0e9".

The source has 46 modules in total. These contain 18 operator-facing commands, 13 Windows backends, 7 dedicated collection stages and a data-driven dispatcher. The C2 exposes the following commands:

Command Function
browserscan Full browser credential sweep (detailed below)
wallet_files Crypto-wallet browser-extension vault extraction
keyscan Secret-store sweep: SSH, GPG, Git credentials, Kubernetes configs, environment variables, shell history, Windows Credential Manager and developer project files
file_chunk Generic chunked file exfiltration (2 MiB reads; resolves %APPDATA% and similar macros)
payload_cleanup Deletes the disguised bundle and all staged artifacts after the run
creds Windows Credential Manager harvesting (DPAPI)
chrome_scan / chrome_install / chrome_cleanup / chrome_uninstall Dedicated Chromium targeting stage
exec Spawns processes with piped I/O
download Pushes additional files to the host
ls / cat / cd Interactive filesystem access
screens Screenshot capture
sysinfo / host_facts / whoami Reconnaissance

Browser credential collection and decryption

The BrowserScan operation will search every Chrome, Edge and Opera profile directory it can find (the build also has Firefox/Gecko support). It will collect every Login Data, Login Data for Account, Cookies and Local State file.

The search will go into the recovery, cache and safety list subdirectories, which are subdirectories that legitimate browser processes won't go into. Each database is then placed into the temp directory under the following naming convention:

%TEMP%\k2f-bcreds-<unix-time>-<random>.db   (+ .db-wal / .db-shm / .db-journal)

The stealer queries the staged databases with the following Chrome password-store SQL:

SELECT origin_url, username_value, password_value FROM logins

For the classic v10 AES-256-GCM blobs, the decryption engine uses the DPAPI-unwrapped OS-Crypt key from Local State. It also supports Chrome's App-Bound Encryption (introduced in Chrome 127), which suggests maintenance will be required for the more recent browser builds.

The server decides whether or not to collect cookies from each victim. In the captured run, collect_cookies:false was used, which effectively disabled collection (the operator can, of course, change that setting remotely).

Crypto-wallet theft

The wallet_files operation identifies browser-extension vaults by extension ID and reads their LevelDB storage directly:

Browser extension ID Wallet
nkbihfbeogaeaoehlefnkodbefgpgknn MetaMask
bfnaelmomeimhlpmgjnjophhpkkoljpa Phantom (Solana)
aflkmfhebedbjioipglgcbcmnbpgliof Coinbase Wallet
bhhhlbepdkbapadjdnnojkbgioiodbic Keplr (Cosmos)
acmacodkjbdgmoleebolmdjonilkdbch TronLink

With a MetaMask .ldb vault and the browser's Local State master key an attacker can recover the seed phrase offline and drain the wallet.

Developer and system secrets

The captured run also included retrieval of %APPDATA%\NuGet\NuGet.Config, which contains package-feed credentials, and %USERPROFILE%\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1. These targets suggest interest in software developers and their supply-chain access, as well as game players.

The keyscan modules were present, but the operator didn’t invoke them in this run. They can collect SSH private keys, including PuTTY .ppk files, as well as GPG keyrings, Git credential stores, Kubernetes configs, environment variables and shell history.

Exfiltration through launcher traffic

The payload download and the stolen data take different network paths:

  • The payload came from the attacker's recently registered domain, hosted in Iceland.
  • The stolen data is sent via the launcher's existing TLS encrypted platform telemetry channel (alongside the normal heartbeat messages). It sits in the opaque extension fields of that channel so network monitoring sees nothing out of the ordinary - just some standard game telemetry.

The launcher binaries, embedded browser, service bridge, downloader and telemetry channel were not modified; the attackers abused them. The exfiltration traffic passed through the launcher’s regular telemetry infrastructure, which we have no reason to believe is controlled by the attackers. We believe the campaign is being run by the operators of the insightjs[.]com delivery domain.

Who they are, we don't know, nor do we know how they got access to the launcher's task channel. There's no game-specific logic in the malicious bundle. An app with the same server-pushed task channel and JS-to-native service bridge would be equally susceptible to abuse.

The activity is difficult to detect for several reasons:

  • The delivery URL isn't in the shipped game files at all. The bundle comes at runtime, as a log.
  • The stealer's code and strings remain in the heap memory of a signed, trusted process.
  • The reconstructed timeline puts the time from bundle download to completed collection at around 6 to 10 minutes.
  • After the run payload_cleanup deletes the bundle and the staged credential databases. We also saw attempts to delete the SQLite WAL files that had already been deleted - those failed.
  • Exfiltration makes use of existing legitimate connections and doesn't open up any new sockets.

How Bitdefender detected it

There are two stages at which the defender can detect and block this attack. You could block the delivery URL and thus prevent the stealer from downloading.

In this case, the domain was very recently registered and had no history whatsoever, so it hadn't raised any flags that would have led to it being blocked.

Bitdefender Advanced Threat Defense caught the second stage (a non-browser process accessing the browser credential stores) and terminated the game launcher on affected users' machines before any personal information could be exfiltrated.

The users were effectively locked out of the game, but the intervention stopped the data from being stolen.

Takedown and other reports

The Icelandic hosting provider has taken the malicious server down. With the delivery domain now unreachable, the observed attack chain can't download the bundle, register k2f_chan, or start credential collection. The launcher's normal functionality is unimpeded.

Also, we notified the developer and publisher on November 10th that we would publish this analysis, but they have yet to respond. 

Reddit users also observed this pattern and investigated it independently. We acknowledge their contributions:

https://gist.github.com/MotherSphere/d6c049a09ba8ac3085c51ee9df24a4e5

https://www.reddit.com/r/NIKKEGoddessofVictory/comments/1xmxz3t/check_your_logs_people_delete_the_pc_client_for/

Recommendations

If you played NIKKE (or used the affected launcher) during the attack window, treat the machine as compromised:

  • Rotate all passwords stored in Chrome, Edge and Opera. The stealer is designed to copy both the credential databases and the master keys required to decrypt them offline.
  • Treat browser extension wallets as at risk. Move assets from MetaMask, Phantom, Coinbase Wallet, Keplr and TronLink wallets into new seed phrases generated on a clean machine.
  • Rotate developer secrets: SSH keys, GPG keys, Git credentials, Kubernetes configs, NuGet feed credentials, anything in shell history or environment variables and Windows Credential Manager entries.
  • Enable phishing resistant MFA wherever you can. Stolen cookies and sessions can be used to gain access without a password.

Very few persistent disk artefacts are left after the campaign has run. The following are indicators that defenders can look for via behavioral and network monitoring:

  • A non-browser process (in particular a game launcher) opening ... \User Data...\Login Data, Login Data For Account, Local State or extension Local Extension Settings*.ldb files.
  • Files matching %TEMP%\k2f-bcreds-.db (including -wal/-shm/-journal siblings).
  • *.log files larger than ~50KB whose first few bytes are \x1bLJ\x01 (LuaJIT bytecode) rather than text.
  • Launcher or game processes connecting to domains outside the vendor’s known infrastructure, particularly recently registered domains.

Disclaimer

This article is published for information and public-interest security research purposes only. It reflects Bitdefender's technical analysis of data available to us at the time of writing, which may be incomplete and may change as more information becomes available. We will update the article if we learn of material new facts.

Nothing in this article states or suggests that Shift Up, Level Infinite, Tencent, the maintainers of insight.js, the hosting provider or any other company or person named here took part in, approved or knew about the malicious activity described. Our findings show that unknown third parties abused legitimate software and infrastructure.

References to products, services and trademarks are for identification only and belong to their owners; no affiliation or endorsement is implied.

Statements about how Bitdefender products performed refer only to the protected systems we observed during this incident and do not guarantee the same result in every environment. The recommendations and indicators of compromise are general guidance, not professional advice for any specific situation; readers should assess their own systems and seek qualified help where needed. To the extent permitted by law, Bitdefender is not liable for any action taken or not taken based on this article.

Third-party links are provided for reference; we do not control and are not responsible for their content. Community researchers are credited with their consent. If you believe any information here is inaccurate or concerns you personally, contact us at legal@bitdefender.com and we will review it promptly.

Indicators of compromise

Indicator type Value
Domain analytics.insightjs[.]com, insightjs[.]com
IP address 89.127.233.127
URL path /comm/assets/insight.bundle
Payload file path Launcher\log\tinyget\tinyget.<yyyymmdd>-<hhmmss>-<pid>.log — contains LuaJIT bytecode
SHA-256 CC0AD05BFE85940A6067B3A72C182D3953339129206634141926D5D0B35973EC
Collected credentials file path %TEMP%\k2f-bcreds-<unix>-<rand>.db — contains collected browser credentials
Payload build tag K2F_LUA_BUILD = "722b99d8d0e9"

tags


Author


Florin Cristian COCOLAS

Security Researcher at Bitdefender with a passion for reverse engineering. Always curious to see what new techniques attackers come up with next.

View all posts
Janos Gergo SZELES

I'm a senior software engineer at Bitdefender. Passionate about malware behavior analysis, I am continuously looking for new tricks employed by malicious actors.

View all posts

You might also like

Bookmarks


loader