Drost Edge — $100 promotional credit.Start now
Drost
All research
Drost ResearchOctober 26, 2026·Migel Tissera·12 min read

Msty Studio RCE: How an Imported Prompt Pack Became Native Code Execution

A two-stage Electron chain from imported prompt data to a native process running as the desktop user

Disclosure status: Msty received the complete technical report and supporting evidence. More than 30 days have passed since disclosure. Drost followed up but received no technical response, CVE assignment, or remediation confirmation. Public release notes and Drost’s later static review indicate that the demonstrated imported-title sink has since been changed.

On September 12, 2026, I started a zero-day hunt with Drost in our security research environment. The objective was to find a zero-day against Msty Studio 2.9.9 on a Mac.

Drost worked for about an hour and came back with several issues across Msty’s desktop application. After reviewing the findings, I asked Drost to try and chain them, escalate and get RCE. Within 15 minutes, Drost had identified a two-stage chain: a prompt title entered the product as data, became JavaScript when the user searched Msty’s prompt library, crossed the Electron renderer boundary and caused the main process to launch a native program with the desktop user’s permissions. The following hours were then spent proving the chain end-to-end, and a harmless marker file confirmed the final boundary crossing.

This was not zero-click. The attack required the user to import a crafted prompt-library file and later use the prompt-library search. But the user did not need to search for the malicious title — any query that caused the imported record to appear in the results rendered its attacker-controlled title as HTML and triggered the chain.

The same execution primitive could plausibly support substantially greater post-exploitation impact, including payload retrieval and execution, access to user-readable data, and user-level persistence.

TL;DR

  • Product tested: Msty Studio 2.9.9

  • Platform tested: macOS arm64

  • Attacker control: A title inside an imported prompt-library JSON file

  • User interaction: Import the file, then perform a search that returns the imported record

  • Entry point: Stored HTML injection in the prompt selector

  • Boundary crossed: Electron renderer to privileged main process

  • Demonstrated impact: An attacker-selected native process ran as the desktop user

  • Severity: Critical product-security impact

  • Additional primitive: Renderer-controlled directory enumeration and transfer of a known readable file

  • CVE status: No public CVE identified as of October 26, 2026

How Drost found the chain

This exploit did not appear in one jump.

Drost began by unpacking the Electron applications, identifying their versions and mapping the native capabilities exposed through the renderer. It found the dangerous half of the chain early: a generic IPC bridge that let renderer JavaScript choose privileged operations and supply their arguments.

That was serious in itself, but it was not yet a remote vulnerability. Renderer JavaScript already needed to be compromised for the latter half to be effective. The missing question then was how attacker-controlled content could reach that renderer.

To get there, Drost explored other possibilities first. It tested the local AI sidecar and its cross-origin behavior. The tempting remote-web path was blocked, so it downgraded that branch instead of forcing a finding. It then returned to the renderer and enumerated the places where Msty assigned strings to innerHTML. One sink was inside the prompt selector. The component highlighted matching search terms by inserting a trusted <mark> element, but it did not escape the original prompt title before treating the combined result as HTML.

Drost then followed that title backwards and found ordinary import paths into the prompt library. It followed renderer control forwards and reached the IPC bridge it had already mapped. That completed the chain.

This is the part that matters to me. The native capability was found first. The exploit only became real when the agent found a credible route from untrusted shared content into that capability—and abandoned a different route when the evidence did not support it.

The complete chain

Msty Studio 2.9.9 complete attack chain

Open the full-size attack chain

This was one exploit chain made from two separate failures:

  1. Imported prompt content became executable renderer content.

  2. Renderer content was allowed to authorize privileged desktop operations.

Honestly, either issue deserved a fix on its own. But together, they turned a prompt pack into a native code execution primitive.

The bug hid inside a state change

The prompt title did not execute when it was imported. Msty accepted it, stored it and displayed it as text in the ordinary library view. The dangerous transition happened only afterwards, when the user searched the library.

Search interfaces often add markup around matching text, and Msty’s highlighter did that by inserting a trusted <mark> element into the title string. However, it did not encode the original title first.

In the minified Msty Studio 2.9.9 renderer bundle, the decisive behavior was:

js
function Ie(r,M){
  // regex construction omitted
  return r.replace(h,'<mark class="text-black">$1</mark>')
}

// Prompt search result
innerHTML:W(l.extras?.title)

The application wanted to add one trusted HTML element. In doing so, it reinterpreted the entire untrusted title as HTML.

That distinction is important. The same title could look inert after import and during ordinary browsing, then become active only when a matching search result appeared.

text
normal library view  -> title treated as text
search result        -> title transformed and treated as HTML

This kind of state-dependent transition is easy to miss, because the import code looked like data handling, and the normal view looked safe. The security property changed only after search highlighting entered the path.

Stage one: imported data becomes renderer code

The tested path began with a prompt-library JSON file containing a crafted title. Msty’s importer parsed the file, validated the record structure, and stored the title. That validation established that the object looked like a prompt, but it did not make the title safe for an HTML context.

The search index later copied the stored title into the search result. When a query returned that record, the prompt selector passed the highlighted result to innerHTML. At that point, Chromium parsed an attacker-controlled element inside the Electron renderer.

The bug was therefore more specific than “HTML was allowed in a title.” It required a change in how the same stored value was interpreted. Reviewing only ingestion—or only the ordinary library view—would miss it.

Stage two: renderer code becomes a native process

This was a security oversight, as renderer execution should have been contained by Msty when they built their software.

Electron applications normally split responsibilities between a renderer, which displays the interface, and a main process, which holds desktop capabilities. A compromised renderer should not automatically gain permission to start programs, read arbitrary files or choose network destinations.

Msty exposed a generic method called sendAndReceive through its preload layer:

js
sendAndReceive(...args) {
  const [channel, ...omit] = args;
  return electron.ipcRenderer.invoke(channel, ...omit);
}

The renderer chose both the IPC channel and its arguments.

One main-process handler forwarded those arguments directly to Msty’s tools service:

js
ipcMain.handle("tools:listTools", (_, args) =>
  toolsService.listTools(args)
);

For a local MCP configuration, the tools service constructed an stdio transport from renderer-supplied values:

js
clientTransport = new StdioClientTransport({
  command: fullCommand,
  args: serverConfig.args,
  env: { ...env, ...serverConfig.env },
  cwd: os.homedir()
});

await client.connect(clientTransport);

The packaged MCP SDK then did exactly what an stdio transport is designed to do: it started the configured process.

The MCP SDK was not the vulnerability. The broken boundary was in the application. Renderer-controlled data selected a privileged operation and supplied the executable configuration without a separate authorization decision in the main process.

Demonstrating the chain

The recorded test used Msty Studio 2.9.9 on macOS arm64.

Debugger automation invoked Msty’s own prompt-file import store action and then drove the real prompt-selector interface. The operating-system file-picker click was not separately exercised, and the application bundle was not modified.

The preserved run recorded:

Check Result
Main application reached Pass
Prompt file accepted through the application import action Pass
Crafted title stored unchanged Pass
Search entered; imported record returned in the results Pass
Injected image element present in the selector DOM Pass
Native-process marker created Pass

Why this is RCE

The final primitive let renderer content select a native executable and its arguments. The recorded test used that ability only to create a harmless marker, but the same primitive could plausibly support substantially greater post-exploitation impact, including payload retrieval and execution, access to user-readable data, and user-level persistence.

The word “remote” can be confusing here. This was not a network request that immediately returned a shell. The attacker’s delivery object was a prompt-library file, and exploitation required the recipient to import it and later perform a search that returned the imported record.

But in desktop software, that is still a real code-execution boundary. A document-like object supplied by another party caused an attacker-selected native process to run on the recipient’s machine.

The renderer could also reach files

The process path was not the only privileged capability behind the bridge.

Msty Studio 2.9.9 also registered handlers that accepted renderer-selected filesystem paths and destinations. One listed the contents of a supplied directory. Another accepted a local file path and base URL, opened the file and streamed it in an HTTP request.

In a separate controlled renderer test, Drost selected the known /etc/hosts file and a local listener. The listener received 493 bytes, separately from an earlier six-byte warmup request. This demonstrated a file-transfer primitive.

Patch status

Msty’s public changelog says Msty Studio 2.9.10, published on September 13, added “security fixes for imported content across the interface.” Msty Studio 3.0.0 Beta 12 carries a corresponding imported-content security note. Both releases were published before we contacted Msty, so we cannot attribute those changes to our report.

After Msty acknowledged the initial contact but did not provide a technical response to the report or follow-up, on October 26 we downloaded the current official Apple Silicon installer. The package reports Msty Studio 2.9.12. Static inspection—without launching the application—showed that the search highlighter now HTML-escapes the stored title before restoring only its own trusted <mark> tags. That closes the precise title-to-HTML transition used by the recorded 2.9.9 chain.

However, the 2.9.12 package still exposes the generic preload sendAndReceive method, forwards renderer-selected tools:listTools arguments to the tools service and constructs an MCP stdio transport from the supplied command, arguments and environment. The architectural V-2 boundary therefore remains present in the current package, although we did not attempt runtime exploitation.

How this should be fixed

Both boundaries need independent fixes.

Keep imported content as text

Search highlighting should be built from text nodes and trusted elements.

In the current Msty Studio 2.9.12 package, the search highlighter HTML-escapes the complete original title before restoring only its own trusted <mark> tags. That is the right fix for the demonstrated sink. The same text-preservation rule should apply to every other imported-content renderer.

Input validation can reject unexpected markup as defense in depth. It should not be the only protection. Stored content can reach several renderers, and every renderer must preserve it as data.

Regression tests should cover imported titles containing markup-like text, the ordinary library view, matching searches, content previews and the transition between those states.

Restore the Electron privilege boundary

The preload layer should expose narrow operations instead of a generic channel-forwarding primitive.

The main process should validate the IPC sender, derive executable configurations from trusted application state, require explicit approval before starting a new local process, bind file operations to approved paths and restrict transfer destinations to configured services.

A channel allowlist alone is not enough if an allowed handler still accepts renderer-supplied executable paths, arguments, filesystem paths or destinations.

The renderer must be treated as potentially compromised. A future rendering flaw or dependency vulnerability should not immediately become native execution.

What AI desktop applications should learn

AI desktop applications are rapidly accumulating operating-system authority.

They manage model files, local tools, MCP servers, API credentials, project directories, imported prompts, community content and cloud connectors. Each capability makes sense by itself. The danger appears when content and capability meet inside the same trust boundary.

Community content is supply-chain input

Prompt packs may look like documents, but applications must treat them as untrusted external input. Importing a prompt should never imply a decision to trust code.

The renderer is not an authorization boundary

Renderer compromise is a normal Electron threat to design for. The main process must independently approve privileged operations.

MCP increases the consequence of renderer flaws

MCP stdio deliberately starts local processes. That capability needs a strong boundary around it. If arbitrary renderer content can manufacture an MCP configuration, a display bug becomes a host-execution bug.

UI state transitions deserve security review

The title was safe in one view and dangerous in another. Search, highlighting, preview, markdown rendering, editing, exporting and sharing can all change how the same stored value is interpreted.

Security review has to follow data through those transitions. Reviewing ingestion alone is not enough.

Disclosure timeline

Date Event
September 12–13, 2026 Good-faith security research on a licensed local copy of Msty Studio 2.9.9
September 15, 2026 Drost sent Msty the confidential technical report and sanitized evidence package
October 23, 2026 Drost requested confirmation of remediation and affected-version boundaries; Msty did not provide a technical response
October 26, 2026 Static review of the official 2.9.12 Apple Silicon package verified that the demonstrated title-rendering stage had changed; the original trigger was not rerun
Pending Vendor confirmation, first fixed release and CVE status

Closing

The interesting part of this finding was not one exotic primitive, but the composition.

  1. A prompt title entered the application as ordinary data.

  2. Search turned that data into HTML.

  3. The renderer crossed a generic IPC boundary.

  4. The main process constructed an MCP stdio transport.

  5. The SDK started the selected process.

Every step looked locally reasonable. Together, they gave an imported prompt pack native execution on the user’s machine.

More than anything, this is why AI desktop applications need hard trust boundaries now. These products are becoming interfaces to the operating system. The content they ingest cannot, and should not, be allowed to inherit that authority.

Research and disclosure: Migel Tissera / Drost
Affected release verified: Msty Studio 2.9.9, macOS arm64
Current release inspected: Msty Studio 2.9.12, macOS arm64; demonstrated imported-title sink fixed by static source review
First fixed release: Not established; 2.9.10 is the earliest public candidate
CVE status: No public CVE identified as of October 26, 2026

DrostAI securityvulnerability researchMstyElectronMCPRCE