Torrent trackers have long been abused for distributing malicious software, disguised as popular films, games, and other content. Our previous research has shown that cybercriminals repeatedly turn to torrents as an initial infection vector, using trojanized cracks and installers to reach a large number of users. Installation guides for pirated software routinely instruct users to disable their antivirus, conditioning them to ignore the potential threats they are inviting onto their computers.
During our analysis of malware that leverages blockchain networks for its C2 infrastructure, we discovered a previously unknown modular, multi-stage framework that we dubbed MovieReaper. This report details the new crimeware campaign that began with the mass infection of users via compromised torrent tracker file storage. We have identified several hundred victims, including both individual users and organizations in multiple countries, such as Russia, TΓΌrkiye, Japan, Kenya, Uganda, and Colombia, as well as in several European countries like Spain, the Netherlands, Belgium, and Germany. We analyze the techniques for evading detection by security and sandbox solutions, and examine the capabilities of the modular framework.
Kaspersky products detect this threat as HEUR:Trojan.Win64.Agent.gen.
Technical details
Background
In midβAugust 2026, during our threatβhunting efforts, we identified a largeβscale infection campaign involving previously unknown malware disguised as popular movies. The campaign affected both individuals and organizations across multiple countries. Our initial analysis revealed a common denominator: all of the victims had used torrent trackers. This finding prompted us to investigate the campaign further and analyze its distribution mechanism, overall scope, and unknown malware implants.
Initial infection and spread
Compromised torrent trackers are the primary vector used to distribute malware. During our investigation, we identified multiple user reports describing suspicious files being downloaded instead of the intended content.
For example, a user of a popular movie torrent tracker reported the following case on Reddit:
Further analysis of the attack revealed that instead of compromising torrent trackers, the threat actor modified a widely used public repository of torrent files, itorrents[.]org. As a result, the trackers that relied on the repository began inadvertently distributing malicious torrent files to their users. This approach is particularly dangerous because it lets the threat actor reach users of multiple trackers without having to compromise each platform individually.
As of the publication date of this report, the archive remains compromised. When a user attempts to download a torrent via a magnet link, the legitimate torrent archive returns a different torrent file. This malicious torrent leads to the download of the malware loader, used to deploy a framework that we dubbed MovieReaper.
The loader initiates the infection chain shown in the diagram below. Each stage of the chain is described in detail in the following sections.
Malware implants
The infection chain consists of several steps, where only the initial one is dropped on the disk before it is executed to avoid detection. The malware itself is not heavily obfuscated, apart from strings being encrypted with a custom stream cipher. Most of the countermeasures were aimed at avoiding detection by AV sandboxes.
Step 1: Loader
The most popular initial executable was distributed through torrent trackers under many different names (for example, the odyssey (2026) [1080p] [webrip] [5.1].exe), but the file hash (MD5: A0B13781EDD7CFDAB13D79AFFF3C83C1) was identical across all downloads. We have seen multiple different loaders, where the executable file disguises itself with a long filename and an icon of some well-known application. Most of the filenames are rather long, presumably to hide the EXE extension at the end.
After the user manually starts the application, it establishes a global mutex to ensure that only one loader is executed at a time. We have seen several mutex variations in our samples, containing a randomly generated string (in the example Global\fnulSktzSqvVLXHU). This executable then performs a series of operations in order to avoid detection by AV sandbox solutions.
While performing those operations, the malware avoids making LoadLibrary and GetProcAddress calls to acquire the addresses of required functions. Instead, it searches for loaded libraries by traversing the double-linked list taken from the Ldr field of the PEB and then performs manual parsing of the loaded DLL to calculate the function address.
After all initial checks have passed, the binary prepares to establish a network connection to a C2 web server to download the shellcode, map it to the RWX memory and execute. While doing so, the loader decodes the domain name https://deadhub[.]org and if connection to it has failed, it uses the IP address http://193.23.118[.]155 as a fallback and connects to it using plain HTTP. The malware chooses a random group of strings and uses them as a path in the HTTP request to download the parts of the shellcode.
While mapping the address space and executing the shellcode, the loader registers a vectored exception handler and rewrites the handler address in memory in order to perform a debug break. This, will not crash the program, but instead redirect controlflow to the function that actually makes a raw NtProtectVirtualMemory syscall (via a previously located β0x0F 0x05β syscall instruction inside ntdll). Then it calls the undocumented ntdll function EtwpCreateEtwThread, which is a popular alternative toΒ CreateThread for code executionm, and executes the shellcode.
Step 2: Shellcode
The second stage of this malware performs an HTTPS request to the Solana blockchain at the endpoint /getAccountInfo endpoint for the account 6pnDGAiHgyPdmckM5Qt1YbanGzrX43WLEU159nRaNLDm. The data in field of the response contains the base64βencoded address of a second C2, which is encrypted with a static XOR key located within the shellcode itself. To store data in this account, attackers used a simple Solana program (address: CSiY8bQLBYPdfPWkwipBzH6sijTVQVVsA279JQdvwHtL).
Utilizing the Solana blockchain as a storage layer for next-stage C2 endpoints substantially complicates infrastructure takedown efforts by defenders.
The second stage payload communicates with its C2 server strictly through HTTPS via a TLS-pinned certificate using the nanopb protobuf library as a container for transferred data. The main logic of the stage 2 implant contains several initial commands, where the most important is the one that parses the COFF file, loads it into memory, and executes the module_init function from it. This provides a convenient interface for extension of the command list, which brings us to the next stage of the payload.
Step 3: UAC Bypass and persistence
Notably, the recovered modules were compiled with symbols, which accelerated reverse engineering.
After receiving the next stage from the second C2 server, the newly loaded module performs several tasks right in the module_init function.
Stage 3 performs UAC Bypass and achieves persistence using public techniques, masquerades the original binary as C:\ProgramData\Microsoft\Windows\Telemetry\msedge.exe, and restarts itself.
The respawned process starts with the initial loader, but with a special command-line argument, which allows it to skip most of the anti-sandboxing checks and proceed straight to downloading the next payload. The executable proceeds with the same steps as before, but this time, instead of downloading the persistence and UAC bypass module, a new one is downloaded from the second C2 server. This is because the malware uses the beacon to send a flag to the remote server, indicating whether the implant is running from the Telemetry folder, which allows the C2 to distinguish between first-run and respawned instances.
Step 4: The final implant
The final module (βfile managerβ) exposes 21 commands that give the operator filesystem access on the victim host. This allows remote the operator to download, upload, and read files on the system; list and enumerate directories; manipulate files with create, copy, rename, move, delete, chmod, and symlink commands; and use preview and thumbnail commands to exfiltrate previews of images and files before actually extracting them.
We suspect that other modules may be loaded on demand if requested by the operator.
Infrastructure
During this malware campaign, attackers are using various commercial hosting providers for their C2 infrastructure (see the IoC section for details). Furthermore, as noted above, the campaign leverages the legitimate Solana blockchain via the RPC endpoint api.mainnet.solana.com to deliver the address of the secondβstage C2 server to the malware. This approach provides the attackers with decentralized storage for C2 addresses, adding an additional layer of resilience and making it more difficult for defenders to disrupt the campaign by simply blocking the IP addresses of the C2 servers.
Victims
The observed campaign targeted both individuals and organizations across Europe, Asia, Africa, and Latin America, with infection attempts identified in Russia, Spain, Germany, Finland, TΓΌrkiye, Japan, Nepal, Kenya, Tanzania, Ghana, Uganda, Colombia, the Netherlands, Belgium, and other countries. The targeted organizations span a wide range of sectors, including enterprise, government, IT, consulting, retail, transportation, and agriculture.
Conclusions
Our research uncovered activity by the same actor dating back to October 2025. Although the campaign has evolved over time, with the malware authors expanding their arsenal and making the loader harder to detect, the pattern remains the same. This includes encoded strings, parts of shellcode downloaded through plain HTTP, and several techniques used to avoid sandboxes and virtual machines. We will continue monitoring this actorβs activity to catch new potential threats.
The first stage offers the clearest opportunity to disrupt this campaign: it relies on a single specific domain name and a single IP address to serve the shellcode, so taking down this server would prevent subsequent infection stages. This includes the second-stage payload, which uses the Solana blockchain network for a C2 and is therefore more resistant to conventional infrastructure takedowns.
However, this frameworkβs self-containment, modularity and in-memory execution has potential for reuse in later campaigns with minimal rework.
ImpervaΒ ThreatΒ ResearchΒ identifiedΒ a series ofΒ remoteΒ denialβofβserviceΒ vulnerabilities inΒ GraphQL Java,Β one of the mostΒ widelyΒ usedΒ librariesΒ forΒ GraphQLΒ in the Java ecosystem.Β
In this blog,Β weβllΒ deep dive into theseΒ vulnerabilities,Β analyzeΒ theirΒ impact,Β andΒ provide recommendations to protect your environment. If your endpoints are protected byΒ ImpervaΒ Web Application Firewall, your systems are already protected against these threats.Β Β
IntroductionΒ
GraphQLΒ Java isΒ the engine beneath Spring forΒ GraphQL, NetflixΒ DGS,Β andΒ Atlassianβs own products. With over one million downloads per month and ten years of production use, it isΒ aΒ naturalΒ choiceΒ for any teamΒ buildingΒ aΒ GraphQLΒ API on the JVM.Β
Over the last few years, multiple typesΒ ofΒ DoSΒ attacksΒ have beenΒ identifiedΒ acrossΒ GraphQLΒ implementations.Β These vulnerabilitiesΒ can lead to eitherΒ denial of serviceΒ or, inΒ cloud-billed environments, excessive cost consumption.Β In response, the industry converged on a set of protective controls, likeΒ depth limiting, query complexity budgets, and field count caps.Β Apollo addedΒ query cost analysisΒ and depth limiting,Β GitHubΒ meters its public GraphQL APIΒ by computed node cost,Β andΒ GraphQL JavaΒ alsoΒ introducedΒ additionalΒ controls.Β
However, these enhancements can leave blind spots earlier in theΒ pipeline, beforeΒ the server has even understood the request.Β
TheΒ DoS attackΒ we foundΒ liveΒ in the first half of the pipeline, where the query is parsed andΒ validated,Β andΒ thereforeΒ independent from the schema, the resolvers, and any backend logic.Β Β
They were reported underΒ GHSA-7p4r-9rcc-8vhv (still as draft)Β and fixed in versions 24.4, 25.1, and 26.1. Several products embedding the library were affected, including Adobe Experience Manager (AEM), Atlassian Confluence, andΒ HAPI FHIRΒ server, a widely used open-source implementation of the HL7 FHIR healthcare interoperability standard.Β
Request ProcessingΒ
Fig. 1: GraphQL Processing High Level PipelineΒ
GraphQLΒ was built around a simpleΒ idea:Β βGraphQLΒ queries mirror their response.β In other words, the client describes exactly the data it needs, while the serverΒ determinesΒ how to retrieve and resolve that data. The query is then sent to aΒ GraphQLΒ endpoint, where it goes through a series of processing steps before the response is returned:Β
HTTP Request:Β The server receives theΒ GraphQLΒ query.Β
Lexing:Β The query is broken down into tokens.Β
Parsing:Β The tokens are turned into anΒ Abstract Syntax Tree (AST)Β representingΒ the query structure.Β
Validation:Β The query is checked against theΒ GraphQLΒ schema and its rules.Β
Execution:Β GraphQLΒ invokes theΒ appropriateΒ resolversΒ to retrieve the requested data.Β
JSON Response:Β The results are assembled and returned to the client.Β
The distinction between these stages matters.Β A request can be rejected before execution because its syntax is invalid or because it does not match the schema.Β Only after passing these checks doesΒ GraphQLΒ reach the resolvers, where the application and its underlying data sources are accessed.Β
For security research, this pipeline provides a useful way to understand the attack surface.Β Each stage processes attacker-controlled input inΒ a different way, making it important to understand not only whatΒ GraphQLΒ does, but also when and where it does it.Β
Parsing and Validation: A Closer LookΒ
Before a server decides what data to return, it must first decide whether the request makes sense.Β Parsing breaks the raw query text into an Abstract Syntax Tree. This involves:Β
Resolving string literals:Β block strings go through a dedicatedΒ normalizationΒ routine that strips leading and trailing blank lines.Β
Constructing AST nodes for every valueΒ encountered:Β numeric literals are converted toΒ BigIntegerΒ orΒ BigDecimalΒ atΒ this point.Β
Validation walks the AST and checks it against the schema. This involves:Β
Field and type checks:Β do the requested fields exist?Β DoΒ the argumentΒ typesΒ match?Β
Fragment validation:Β named fragments must not form cycles, directly or transitivelyΒ
Validation is whereΒ fragment cycle detection takes place. Named fragments areΒ GraphQLβsΒ reuse mechanism. Instead of repeating the same selection set in multiple places, a client defines it once and references it with a spread:Β
Fig. 2: Named Fragments in GraphQLΒ
FragmentsΒ can themselvesΒ spread other fragments. The specΒ allowsΒ arbitraryΒ nesting,Β butΒ it forbids cycles: if A spreads B and B spreads A, resolving either one requires resolving the other first. The executionΒ engine wouldΒ recurse indefinitely. The same applies to indirect cycles across any number of fragments.Β
ThisΒ check happens during validation, after parsing has produced the AST and before execution starts. At thisΒ pointΒ theΒ server has a complete map of every named fragment in the document and everyΒ spreadΒ reference between them.Β Β
Cycle detectionΒ is pretty straightforward: for each fragment, follow its spread references transitively and check whether any path leads back to the starting node.Β If it does, the document is rejected with a validation errorΒ andΒ executionΒ never starts.Β
ValidateNoFragmentCyclesΒ is called once perΒ FragmentDefinitionΒ in the document.Β Each call starts with a freshΒ HashMap.Β
For each fragment, it callsΒ buildTransitiveSpreads, a depth-first traversal that follows every spread reference outward, building up the set of fragments reachable from the starting node.Β Β
The traversal tracks its current path in anΒ ArrayList, and at each step callsΒ ArrayList.containsΒ to check whether the next node has already been visited.Β Β
Worst Case ScenarioΒ
We considered a document withΒ theΒ followingΒ chain ofΒ dΒ fragments:Β
Fig. 3: Malicious Payload StructureΒ
For each fragment,Β ValidateNoFragmentCyclesΒ starts a new traversal with a fresh HashMap. Since the traversal follows the entire chain, and ArrayList.contains iterates over the path of fragments visited so far, the cost of a single validation is O(dΒ²).Β Β
Fig. 4: Processing of the First FragmentΒ
Since this happens for all fragments, the overall complexity is O(dΒ³), where d is the number of fragments in the document. Within the default 15,000-token limit, a single payload canΒ containΒ up toΒ aroundΒ 1,800Β fragments (~50 KB), which is sufficient to saturate a CPU core for severalΒ minutes atΒ everyΒ request.Β
Why existingΒ GraphQLΒ protections may not helpΒ
TraditionalΒ GraphQLΒ protections such as depth limits and field-count limitsΒ operateΒ during validation. However, this attack specifically targets theΒ validationΒ stepΒ itself.Β Therefore, it hitsΒ beforeΒ theΒ protections can prevent the attack.Β
Following the reception of our report,Β graphql-java released a patchΒ thatΒ introducesΒ memoization.Β Once a fragment has been explored, it is marked as done and never re-traversedΒ again. TheΒ sameΒ malicious payload is processed in a few millisecondsΒ instead.Β
This finding was the most impactful, but itΒ wasnβtΒ the only one.Β
Additional Remote DoS VulnerabilitiesΒ
WeΒ identifiedΒ the sameΒ underlying idea asΒ one of theΒ attack vectorsΒ previouslyΒ identifiedΒ in React Server Components (BigIntΒ values,Β CVE-2026-23864), and another vector involvingΒ block string normalization routine,Β more impactful.Β Both fixed inΒ 24.4, 25.1 and 26.1.Β
HAPIΒ FHIR Use CaseΒ
HAPI FHIR is a Java server designed to store and serve medical data (patients, prescriptions, lab results) using the FHIR healthcare standard. Like many modern APIs, it exposes aΒ GraphQLΒ endpoint that clients can use to query this data.Β Β
Internally, HAPI handlesΒ GraphQLΒ requests with its own parser, written specifically for FHIR, which knows how to resolve medical resources.Β But when a client asks for introspection (a standardΒ GraphQLΒ feature that returns the full list of available queries and types)Β HAPIΒ delegates directly toΒ graphql-java.Β Β
However,Β itβsΒ possible to bypass HAPIβs custom FHIR resolver and route a non-introspection query straight toΒ graphql-java.Β
This delegation is triggered by a simpleΒ string check:Β it relies on the presence of the stringΒ `__schema`Β in the body.Β Β
Therefore, simplyΒ startingΒ theΒ requestΒ withΒ the followingΒ pattern (see FigΒ 5.)Β wasΒ enough.Β
TestedΒ onΒ a freshΒ c7i.2xlarge instance, with the latestΒ HAPI serverΒ withΒ graphqlΒ enabled,Β a singleΒ requestΒ tookΒ 150 secondsΒ ofΒ validation.Β AΒ singleΒ waveΒ ofΒ multipleΒ smallΒ requests could lock the server entirelyΒ forΒ several minutes and pin all 8 CPU cores at 100% forΒ more thanΒ an hour.Β
In this application, this attack vector couldΒ representΒ an alternative avenue for a threat actor lacking authorization to exfiltrate patient dataΒ (as HAPIβs authorization model governsΒ GraphQLΒ endpoint access and data read permissionsΒ independently), andΒ stillΒ willing toΒ cause impact.Β
The attack surface is further widened by HAPIβs default CORS configurationΒ (allows any origin,Β Access-Control-Allow-Origin: *). In environments where noΒ additionalΒ network controls are in place, this means the attack could be triggered from aΒ browser: aΒ healthcare workerΒ opening a malicious link while connected to the internal network is sufficient to take down the FHIR server for everyone.Β
Who isΒ Affected?Β
An application is potentially exposed when:Β
It uses an affected version ofΒ GraphQLΒ Java;Β Β
It accepts attacker-controlledΒ GraphQLΒ documents;Β Β
TheΒ GraphQLΒ endpoint is remotely reachable;Β Β
No upstream control blocks the malicious request.Β Β
RemediationΒ
The fixes areΒ availableΒ inΒ GraphQLΒ Java versionsΒ 24.4, 25.1, and 26.1Β via PRs #4440, #4441.Β
For environments where an immediate upgrade is not possible:Β
Restrict access to affectedΒ GraphQLΒ endpointsΒ to authenticated or otherwise trusted clients where the applicationΒ permitsΒ it.Β
Apply rate limiting and concurrency limitsΒ to restrict the number ofΒ GraphQLΒ requests that can be processed simultaneously.Β
Monitor CPUΒ utilizationΒ andΒ GraphQLΒ request latencyΒ for unusual increases that mayΒ indicateΒ resource-exhaustion attempts.Β
If your endpoints are protected byΒ Imperva Web Application Firewall, your systems are already protected against these threats.Β
ConclusionΒ
As AI acceleratesΒ vulnerabilityΒ discovery and exploitation, threat actors can increasingly scan a target environment in real time,Β identifyΒ weaknesses across its technology stack, and rapidly turn those findings into attacks. This reduces the time organizationsΒ mustΒ detect and remediate newly exposed vulnerabilities, making proactive and continuously enforced security controls increasingly important.Β
AffectedΒ organizationsΒ shouldΒ upgrade to a fixed release as soon as possible. Until patches can be applied,Β additionalΒ controls at the application and network layers can help reduce exposure and limit the impact of potential attacks.Β
Imperva customers are protected against exploitation of these vulnerabilities. Imperva Threat Research will continue toΒ monitorΒ this threat and work to ensure that customersΒ remainΒ protected against emerging attack techniques targetingΒ GraphQLΒ and other widely deployed technologies.Β
TimelineΒ
August 11 βΒ We reported the security issue toΒ GraphQLΒ Java.Β
August 19 β Report Acknowledged.Β
August 23 β Fix releasedΒ in versionsΒ 24.4, 25.1 and 26.1.Β
AI-assisted development has crossed a threshold. The question is noΒ longer whether your IDE communicates with anΒ AI,Β itβsΒ how deeplyΒ that AI is now wired into your local environment. The Model Context Protocol (MCP) isΒ one of theΒ plumbing behind this shift: a JSON-RPC-based protocol that lets AI assistants invoke tools running on your machine.Β From settingΒ a breakpoint,Β toΒ runningΒ tests,Β orΒ launching aΒ debuggerβ¦Β allΒ from a chat window.Β
DebugMCPΒ is one of the extensionsΒ leadingΒ that charge. Published by Microsoft onΒ GitHub, it exposes a local MCP server that gives any compatible AI agentΒ (GitHub Copilot, Cline, Cursor, Codex, Windsurf, and others)Β direct control over the VS Code debugger. The value proposition is compelling: instead of pasting stack traces into a chat window and waiting for a suggestion, an AI agent can set breakpoints, step through code, inspect variables, and evaluate expressions autonomously.Β Β
WeΒ identifiedΒ and reportedΒ a criticalΒ security issueΒ in version 1.1.4.Β AΒ remote attacker who trickedΒ a developer into visiting a malicious webpageΒ couldΒ achieveΒ arbitrary code executionΒ on that developerβs machine, in the background, without any further user interaction (drive by).Β Β
Following our report, the maintainersΒ patchedΒ DebugMCPΒ viaΒ commit 86776b2m.Β TheΒ fix was silentlyΒ shipped (no version bump, no advisory) and is included in version 1.2.0 and later. We are publishing this report followingΒ theΒ 90-day disclosure period.Β
We recommendΒ updatingΒ toΒ the latest available version.Β
ScopeΒ
The exploitability of this weaknessΒ wasΒ amplifiedΒ by the context in which the software evolves.Β Β
Indeed,Β weβreΒ talking about an opensource MCP serverΒ hosted onΒ GitHub,Β thatΒ canΒ be used as a standalone server.Β ButΒ thisΒ MCP server isΒ alsoΒ exposed as anΒ extension inΒ VSCodeΒ Marketplace,Β installableΒ with a singleΒ clickΒ bothΒ in local endpoints,Β andΒ inΒ shared serversΒ via systems likeΒ GithubΒ CodeSpaces,Β OpenVSCodeΒ Server,Β etc.Β
FromΒ this singleΒ installationΒ click,Β theΒ serverΒ is automatically startedΒ andΒ listeningΒ on port 3001Β withoutΒ authentication,Β opening the door to RCE.Β
First,Β weβllΒ explore how this issue could beΒ exploited from aΒ surroundingΒ compromised device, andΒ weβllΒ thenΒ demonstrateΒ howΒ DNSΒ rebinding could be exploitedΒ to trigger RCEΒ viaΒ simplyΒ havingΒ a victim browseΒ to a malicious site.Β
At the end of 2025,Β probablyΒ followingΒ aΒ series ofΒ vulnerabilitiesΒ identifiedΒ in multiple MCPΒ servers,Β AnthropicΒ added anΒ additionalΒ layer ofΒ security to prevent thisΒ riskΒ (CVE-2025-66414)Β that addsΒ a default securityΒ layerΒ in most MCP server cases.Β Β
VersionΒ 1.24.0Β ofΒ modelcontextprotocolΒ introducesΒ createMcpExpressApp, a preconfigured express serverΒ instanceΒ thatΒ automaticallyΒ registersΒ validateHostHeaderΒ andΒ validateOriginHeader. Together,Β these functions preventΒ the riskΒ ofΒ DNS rebinding.Β Β
However,Β the library still relies on maintainers to useΒ headerΒ validationΒ middlewareΒ functionsΒ in case of custom express configuration.Β AndΒ in the case ofΒ DebugMCP, this is lacking.Β
That was theΒ firstΒ nodeΒ ofΒ ourΒ attackΒ chain.Β
Combined with the lack of hostΒ and originΒ definition andΒ validation,Β the customΒ express serverΒ definedΒ (identical toΒ CVE-2025-53967), exposed the MCPΒ toolsΒ far beyondΒ theΒ intendedΒ reach.Β Β
But independently from the broad network exposure, an LLM could be tricked via indirect prompt injection to access a file outside VSCode workspace trust, and the fix produced by the maintainers doesnβt answer this question.
Uncontrolled FileΒ PathΒ
To further explore the attack chain,Β letβsΒ review the tools exposed.Β
The README lists the available tools, including:Β
start_debugging:Β launches a debugging session for a given file pathΒ
get_debugger_state:Β returns the current state of an active debugging sessionΒ
get_variables:Β inspect local variables in the current stack frameΒ
evaluate_expression:Β evaluate an arbitrary expression in the debugger contextΒ
continue_execution:Β resume execution
FromΒ reading the tool definitions,Β start_debuggingΒ jumpedΒ outΒ immediatelyΒ since it acceptedΒ aΒ fileFullPathΒ argument and instructs VS Code to launch a debugger session for that file.Β ThatβsΒ aΒ file execution primitive.Β
But to obtain an efficient RCE chain, a few more steps were required.Β
The UNC Path PrimitiveΒ
At first glance, becauseΒ the vulnerability requires knowing the full path of an executable on the victimβs machine, itΒ seemsΒ difficult to weaponize reliably in the wild.Β
However, on Windows, the Universal Naming Convention (UNC) path format allows programs to reference files on network shares using paths of the form:Β
\\SERVER\SHARE\path\to\fileΒ
This feature enabled us toΒ makeΒ DebugMCPΒ pass the path to VS Codeβs debugging infrastructure, which passed it to the Python launcher, which reached out to the attackerβs SMB share and loaded the file. The fileΒ executedΒ under the victimβs user context.Β
Fig. 1: SMB endpoint to fetch payloadΒ
The proof-of-concept payload was intentionally benign:Β
import os os.system(βcalc.exeβ)Β
After a few seconds, Calculator opened. The attackerβs code was running on the victimβs machineΒ via a single HTTP request.Β
At this pointΒ weΒ had a working localΒ exploit,Β ifΒ weΒ couldΒ send one HTTP request to port 3001 with an attacker-controlled UNCΒ pathΒ andΒ getΒ code execution.Β Β
The remaining question was how to deliver that request from a remote attackerβs position to a victimβs localhost,Β across the same-origin policy that is supposed to make this impossible.Β
Stateless MCP sessionΒ
One part of the answer lies in the MCP itself.Β You can find aΒ detailed introduction to theΒ protocolΒ here.Β
What matters hereΒ is one implementation detail that significantly reducedΒ the attack complexity.Β
MCP over HTTP is built on JSON-RPC 2.0. The protocol specification describes a lifecycle: a client must send anΒ initializeΒ request, receive the serverβs capability response, then send anΒ initializedΒ notificationΒ (onlyΒ after this handshake can tool calls be made). This sequence implies a minimum of twoΒ round-tripsΒ before any tool is invoked, and it gives a server the opportunity toΒ establishΒ authenticatedΒ session state.Β
The MCP TypeScript SDKβsΒ StreamableHTTPServerTransportΒ enforces this lifecycle through aΒ validateSessionΒ function called on every non-initializeΒ request. The enforcement is conditional:Β
Fig. 2: Stateless MCP modeΒ
WhenΒ sessionIdGeneratorΒ is undefined,Β validateSessionΒ returnsΒ immediatelyΒ withoutΒ checking anything. The entire initialization lifecycle is bypassed. InΒ DebugMCPΒ v1.1.4, the transport was explicitly configured inΒ statelessΒ mode.Β Β
The consequence for the attack chain is direct: a singleΒ no-corsΒ HTTP requestΒ wasΒ sufficientΒ to trigger the attack.Β
Browser Local Network ProtectionsΒ
However, there was aΒ last ingredientΒ weΒ needed toΒ incorporateΒ toΒ obtainΒ a frictionless exploit.Β
Indeed,Β LocalΒ Network AccessβsΒ aim is to protect users from cross-site request forgery (CSRF) attacks targeting routers and other devices onΒ private networks, and to reduce the ability of sites to use these requests to fingerprint the userβs local network.Β
Combined withΒ theΒ same-origin policyΒ (thatΒ preventsΒ a piece ofΒ JavaScriptΒ from oneΒ domainΒ andΒ makeΒ corsΒ requests toΒ a different oneΒ and get the response),Β inΒ modern browsers, there is a good chance a warning popup would be displayed and halt the execution of the malicious contentΒ if a threat actor tries to scan the local network.Β Β
But DNS rebinding is a technique thatΒ canΒ potentiallyΒ circumventΒ this boundary by exploiting the way browsers cache DNS records.Β AndΒ as we explained earlier,Β DebugMCPΒ doesnβtΒ include MCP default mitigation added by Anthropic against this risk.Β
Here is the attackΒ flow:Β
Fig. 3: Attack FlowΒ
The sequence unfolds inΒ sixΒ steps:Β
Step 1:Β Victim visits the page.Β The attackerβs domainΒ resolves toΒ the attackerβs public IP (Phase 1 DNS). The browser loads theΒ initialΒ page content.Β Β
Step 2:Β DNS Rebinding.Β The domain was registered withΒ a very shortΒ TTL:Β 1 to 2 seconds.Β Firefox enforces an internal minimum cacheΒ duration of ~60 seconds regardless of the declared TTL, so the page polls in a JavaScript loop until the entryΒ expires and Firefox re-resolves the name: at which point the attackerβs DNS server returns 127.0.0.1.Β
Step 3: Local Network Access.Β The attackerβs JavaScript,Β issues aΒ fetchΒ toΒ http://evil.attacker.com:3001/mcp?transport=streamable_http. The browser considers this request same-origin and sends it. The DNS entry now points toΒ 127.0.0.1, so the request arrives at the victimβs localΒ DebugMCPΒ server.Β
Step 4:Β DebugMCPΒ Execution.Β The request reaches the MicrosoftΒ DebugMCPΒ server running locally on the victimβs machine.Β DebugMCPΒ processes the request and triggers its Python launcher, whichΒ is responsible forΒ starting the debugging workflow.Β
Step 5: Malicious Payload Download.Β The Python launcher connects to a publicly accessible SMB share controlled by the attacker and downloads the malicious Python script onto the victimβs machine.Β
Step 6: Code Execution.Β The launcher passes the downloaded script to theΒ start_debugging()Β function.Β DebugMCPΒ then executes the attacker-controlled payload,Β ultimately givingΒ the attacker code execution on the victimβs machine.Β
DemonstrationΒ
Although the exploit triggers error messages in the VS Code console, the payload is still successfully executed. We usedΒ Firefox version 150.0.3,Β theΒ latestΒ at the time of our research.Β
Note: After the research, Firefox enforced a Local Network Access Protections (version 153). This prevents the a request originating from a domain associated with a public IP to reach more private address networks. This recent feature, currently existing in Chrome and Firefox, isnβt yet generalized to all browsers.Β Β
ImpactΒ
The target is a developer. That means the compromised machine holds live credentials, source code, and trusted access to internal infrastructure.Β
In practice:Β AWS keys, SSH keys,Β GitHub tokens in VS Codeβs secret storage, active cloud CLI sessions, VPN tunnels open to the internal network, and push access to production branchesΒ would beΒ likely available:Β aΒ payload that runs as the developer inherits all of it silently.Β
The delivery requires no interaction beyond visiting aΒ page,Β itβsΒ a drive-byΒ attack.Β
RecommendationsΒ
DevelopersΒ using this tool shouldΒ update toΒ the latestΒ availableΒ version. The fix ships after 1.1.4 (version 1.2.0 and later).Β Β
In addition,Β itβsΒ recommended toΒ regularlyΒ auditΒ which servers areΒ listeningΒ on loopback.Β
Use authentication in your MCP servers andΒ enforce governance to control which MCP server is running in your network and be able to remove it if necessary.Β
Regarding MCP development more specifically:Β
UseΒ middleware thatΒ enforceΒ validation (likeΒ createMcpExpressAppΒ Since SDK v1.23.0).Β
Validate file path inputs.Β Reject UNC paths and remote schemes before passing any path to an execution primitive.Β
Disclosure TimelineΒ
May 19: IssueΒ reported to MicrosoftΒ Β
May 24: Fix shipped inΒ commitΒ 86776b2, released as version 1.2.0Β
September 25: Public disclosure (this blogpost)Β
ConclusionΒ
AI-assisted development is quietly rewriting theΒ developerΒ machineβsΒ threat model. To give an agent useful capabilities, extensions expose local servers, wire in execution primitives, and grant broad access to the filesystem and the debugger.Β Β
Each of these is a reasonable engineering decision on its own. Together, they turn the workstation into a dense collection of automation endpoints, and those same endpoints, built to be driven by a trusted agent, are equallyΒ drivableΒ by an attacker who reaches them. The productivity story and the attack surface story are the same story.Β
Developer environments are where source code, signing keys, pipeline credentials, and cloud sessions converge; compromising one is often a shorter path to production than attacking production directly.Β Β
This vulnerability was not sophisticated.Β The techniques here are notΒ new;Β whatβsΒ new is the rate at which capable, unvetted local servers are being deployed onto high-value machines,Β andΒ the growing ability ofΒ AIΒ agentsΒ toΒ discover andΒ chainΒ weaknesses autonomously.Β
A new kind of AI model returns decisions instead of text. We spent a day trying to change its mind. It cost about 50 cents. In this article Jev is a new kind of AI model that returns typed decisions instead of text, built for software to call rather than for people to read. We put it inside a realistic application and tried to change its verdict from the outside. βevery configuration we tested was broken: risk downgraded to low and investment advised, on a document that flags every warning sign βabout 50 cents per successful break, with our strongest [β¦]
In this article Nineteen Check Point AI Security R&D teams spent two days on one prompt: build the demo customers would ask to see twice. Three of the results tell a single story about securing AI agents, and none of it starts with an attacker. βan autonomous agent took dangerous actions with no attacker involved, it simply hit a wall and improvised βa single poisoned file in a code repository turned a popular coding agent into a data exfiltration channel βquestioning an off-track agent prevented as many attacks as blocking it, and completed more legitimate work βthe lesson for anyone [β¦]
Torrent trackers have long been abused for distributing malicious software, disguised as popular films, games, and other content. Our previous research has shown that cybercriminals repeatedly turn to torrents as an initial infection vector, using trojanized cracks and installers to reach a large number of users. Installation guides for pirated software routinely instruct users to disable their antivirus, conditioning them to ignore the potential threats they are inviting onto their computers.
During our analysis of malware that leverages blockchain networks for its C2 infrastructure, we discovered a previously unknown modular, multi-stage framework that we dubbed MovieReaper. This report details the new crimeware campaign that began with the mass infection of users via compromised torrent tracker file storage. We have identified several hundred victims, including both individual users and organizations in multiple countries, such as Russia, TΓΌrkiye, Japan, Kenya, Uganda, and Colombia, as well as in several European countries like Spain, the Netherlands, Belgium, and Germany. We analyze the techniques for evading detection by security and sandbox solutions, and examine the capabilities of the modular framework.
Kaspersky products detect this threat as HEUR:Trojan.Win64.Agent.gen.
Technical details
Background
In midβAugust 2026, during our threatβhunting efforts, we identified a largeβscale infection campaign involving previously unknown malware disguised as popular movies. The campaign affected both individuals and organizations across multiple countries. Our initial analysis revealed a common denominator: all of the victims had used torrent trackers. This finding prompted us to investigate the campaign further and analyze its distribution mechanism, overall scope, and unknown malware implants.
Initial infection and spread
Compromised torrent trackers are the primary vector used to distribute malware. During our investigation, we identified multiple user reports describing suspicious files being downloaded instead of the intended content.
For example, a user of a popular movie torrent tracker reported the following case on Reddit:
Further analysis of the attack revealed that instead of compromising torrent trackers, the threat actor modified a widely used public repository of torrent files, itorrents[.]org. As a result, the trackers that relied on the repository began inadvertently distributing malicious torrent files to their users. This approach is particularly dangerous because it lets the threat actor reach users of multiple trackers without having to compromise each platform individually.
As of the publication date of this report, the archive remains compromised. When a user attempts to download a torrent via a magnet link, the legitimate torrent archive returns a different torrent file. This malicious torrent leads to the download of the malware loader, used to deploy a framework that we dubbed MovieReaper.
The loader initiates the infection chain shown in the diagram below. Each stage of the chain is described in detail in the following sections.
Malware implants
The infection chain consists of several steps, where only the initial one is dropped on the disk before it is executed to avoid detection. The malware itself is not heavily obfuscated, apart from strings being encrypted with a custom stream cipher. Most of the countermeasures were aimed at avoiding detection by AV sandboxes.
Step 1: Loader
The most popular initial executable was distributed through torrent trackers under many different names (for example, the odyssey (2026) [1080p] [webrip] [5.1].exe), but the file hash (MD5: A0B13781EDD7CFDAB13D79AFFF3C83C1) was identical across all downloads. We have seen multiple different loaders, where the executable file disguises itself with a long filename and an icon of some well-known application. Most of the filenames are rather long, presumably to hide the EXE extension at the end.
After the user manually starts the application, it establishes a global mutex to ensure that only one loader is executed at a time. We have seen several mutex variations in our samples, containing a randomly generated string (in the example Global\fnulSktzSqvVLXHU). This executable then performs a series of operations in order to avoid detection by AV sandbox solutions.
While performing those operations, the malware avoids making LoadLibrary and GetProcAddress calls to acquire the addresses of required functions. Instead, it searches for loaded libraries by traversing the double-linked list taken from the Ldr field of the PEB and then performs manual parsing of the loaded DLL to calculate the function address.
After all initial checks have passed, the binary prepares to establish a network connection to a C2 web server to download the shellcode, map it to the RWX memory and execute. While doing so, the loader decodes the domain name https://deadhub[.]org and if connection to it has failed, it uses the IP address http://193.23.118[.]155 as a fallback and connects to it using plain HTTP. The malware chooses a random group of strings and uses them as a path in the HTTP request to download the parts of the shellcode.
While mapping the address space and executing the shellcode, the loader registers a vectored exception handler and rewrites the handler address in memory in order to perform a debug break. This, will not crash the program, but instead redirect controlflow to the function that actually makes a raw NtProtectVirtualMemory syscall (via a previously located β0x0F 0x05β syscall instruction inside ntdll). Then it calls the undocumented ntdll function EtwpCreateEtwThread, which is a popular alternative toΒ CreateThread for code executionm, and executes the shellcode.
Step 2: Shellcode
The second stage of this malware performs an HTTPS request to the Solana blockchain at the endpoint /getAccountInfo endpoint for the account 6pnDGAiHgyPdmckM5Qt1YbanGzrX43WLEU159nRaNLDm. The data in field of the response contains the base64βencoded address of a second C2, which is encrypted with a static XOR key located within the shellcode itself. To store data in this account, attackers used a simple Solana program (address: CSiY8bQLBYPdfPWkwipBzH6sijTVQVVsA279JQdvwHtL).
Utilizing the Solana blockchain as a storage layer for next-stage C2 endpoints substantially complicates infrastructure takedown efforts by defenders.
The second stage payload communicates with its C2 server strictly through HTTPS via a TLS-pinned certificate using the nanopb protobuf library as a container for transferred data. The main logic of the stage 2 implant contains several initial commands, where the most important is the one that parses the COFF file, loads it into memory, and executes the module_init function from it. This provides a convenient interface for extension of the command list, which brings us to the next stage of the payload.
Step 3: UAC Bypass and persistence
Notably, the recovered modules were compiled with symbols, which accelerated reverse engineering.
After receiving the next stage from the second C2 server, the newly loaded module performs several tasks right in the module_init function.
Stage 3 performs UAC Bypass and achieves persistence using public techniques, masquerades the original binary as C:\ProgramData\Microsoft\Windows\Telemetry\msedge.exe, and restarts itself.
The respawned process starts with the initial loader, but with a special command-line argument, which allows it to skip most of the anti-sandboxing checks and proceed straight to downloading the next payload. The executable proceeds with the same steps as before, but this time, instead of downloading the persistence and UAC bypass module, a new one is downloaded from the second C2 server. This is because the malware uses the beacon to send a flag to the remote server, indicating whether the implant is running from the Telemetry folder, which allows the C2 to distinguish between first-run and respawned instances.
Step 4: The final implant
The final module (βfile managerβ) exposes 21 commands that give the operator filesystem access on the victim host. This allows remote the operator to download, upload, and read files on the system; list and enumerate directories; manipulate files with create, copy, rename, move, delete, chmod, and symlink commands; and use preview and thumbnail commands to exfiltrate previews of images and files before actually extracting them.
We suspect that other modules may be loaded on demand if requested by the operator.
Infrastructure
During this malware campaign, attackers are using various commercial hosting providers for their C2 infrastructure (see the IoC section for details). Furthermore, as noted above, the campaign leverages the legitimate Solana blockchain via the RPC endpoint api.mainnet.solana.com to deliver the address of the secondβstage C2 server to the malware. This approach provides the attackers with decentralized storage for C2 addresses, adding an additional layer of resilience and making it more difficult for defenders to disrupt the campaign by simply blocking the IP addresses of the C2 servers.
Victims
The observed campaign targeted both individuals and organizations across Europe, Asia, Africa, and Latin America, with infection attempts identified in Russia, Spain, Germany, Finland, TΓΌrkiye, Japan, Nepal, Kenya, Tanzania, Ghana, Uganda, Colombia, the Netherlands, Belgium, and other countries. The targeted organizations span a wide range of sectors, including enterprise, government, IT, consulting, retail, transportation, and agriculture.
Conclusions
Our research uncovered activity by the same actor dating back to October 2025. Although the campaign has evolved over time, with the malware authors expanding their arsenal and making the loader harder to detect, the pattern remains the same. This includes encoded strings, parts of shellcode downloaded through plain HTTP, and several techniques used to avoid sandboxes and virtual machines. We will continue monitoring this actorβs activity to catch new potential threats.
The first stage offers the clearest opportunity to disrupt this campaign: it relies on a single specific domain name and a single IP address to serve the shellcode, so taking down this server would prevent subsequent infection stages. This includes the second-stage payload, which uses the Solana blockchain network for a C2 and is therefore more resistant to conventional infrastructure takedowns.
However, this frameworkβs self-containment, modularity and in-memory execution has potential for reuse in later campaigns with minimal rework.
We designed a behavioral clustering model to map cloud identity roles from audit logs, enabling continuous threat detection using standard SQL queries.