Security Considerations When Running Untrusted Handlers in Unity MCP: Architecture and Mitigations

Unity MCP executes dynamically discovered handlers via reflection on Unity's main thread without sandboxing, exposing projects to arbitrary code execution, denial-of-service attacks, and network-based threats when loading untrusted assemblies.

Unity MCP (Message Command Protocol) enables extensible command handling through the isuzu-shiranui/unitymcp repository's reflection-based discovery system. While this architecture provides powerful flexibility for editor automation, it simultaneously creates a substantial attack surface when executing handlers from unverified third-party assemblies.

How Unity MCP Discovers and Executes Handlers

Understanding the handler lifecycle is essential for evaluating security risks. The system discovers, instantiates, and executes handlers through several tightly coupled stages defined in the core server implementation.

Reflection-Based Discovery in McpHandlerDiscovery.cs

The discovery process begins in McpHandlerDiscovery.cs at lines 34-55, where the system scans every loaded assembly in the current AppDomain:

var assemblies = AppDomain.CurrentDomain.GetAssemblies();
var handlerTypes = assembly.GetTypes().Where(t => typeof(T).IsAssignableFrom(t) && !t.IsAbstract && !t.IsInterface);

This reflection-based approach identifies any non-abstract type implementing IMcpCommandHandler or IMcpResourceHandler, regardless of the assembly's origin or trust status. The code explicitly excludes only core Unity and System assemblies, leaving all third-party packages and dynamically loaded DLLs eligible for handler registration.

Handler Instantiation and Registration

Once discovered, handlers are instantiated via Activator.CreateInstance and registered with the server. In McpHandlerDiscovery.cs lines 61-66, the system creates instances without constructor arguments:

var instance = (T)Activator.CreateInstance(handlerType);
this.registerAction(instance);

The registration callback stores handlers in McpServer.cs (lines 85-115) within a dictionary keyed by command prefix:

this.commandHandlers[commandPrefix] = new HandlerRegistration(handler, enabled);

This registration persists the handler's enabled state in McpSettings, but performs no cryptographic verification or signature checking on the assembly source.

Synchronous Execution on the Main Thread

Command execution occurs in McpServer.cs lines 100-150 via the ExecuteCommand method, which queues actions to run exclusively on Unity's main thread:

ExecuteOnMainThread(() => {
    result = registration.Handler.Execute(action, parameters);
});

The system implements a 5-second timeout via waitHandle.WaitOne(5000), but the handler still executes synchronously on the main thread, blocking the Unity Editor UI during operation.

Critical Security Risks When Running Untrusted Handlers

The architectural design of Unity MCP creates several vulnerability classes when executing code from untrusted sources.

Arbitrary Code Execution via Assembly Loading

Because McpHandlerDiscovery.cs scans all loaded assemblies without whitelist validation, any malicious DLL placed in the project can implement IMcpCommandHandler and gain full access to the Unity Editor API. Attackers can leverage EditorApplication, AssetDatabase, File.IO, and network classes to execute destructive operations. The CodeExecutionCommandHandler.cs sample demonstrates this risk explicitly, showing how handlers can execute arbitrary C# code within the editor context.

Lack of Sandboxing and Isolation

Handlers execute within the same AppDomain and process as the Unity Editor, sharing memory space and security context. Unlike sandboxed plugin architectures that use separate processes or restricted AppDomains, Unity MCP provides no isolation boundary. A malfunctioning or malicious handler can directly corrupt scene files, delete assets from the AssetDatabase, or modify editor preferences stored in the registry.

Denial-of-Service via Main Thread Blocking

The synchronous execution model in ExecuteCommand creates a denial-of-service vulnerability. Because handlers run on the main Unity thread via ExecuteOnMainThread, a long-running computation or infinite loop within a handler will freeze the Unity Editor UI. While the 5-second timeout (waitHandle.WaitOne(5000)) eventually triggers, the main thread remains blocked during execution, potentially causing editor instability or data loss from unsaved changes.

Unauthorized Network Access via UDP Discovery

The UDP discovery mechanism in McpServer.cs lines 331-376 accepts broadcast packets from any network source without authentication:

switch (messageType) {
    case "mcp_server_announce":
        this.TryConnect();
        break;
}

This allows malicious hosts to announce fake MCP servers, potentially causing the Unity client to connect to attacker-controlled endpoints. Once connected, the client may expose project information including the client ID, Unity version, and hashed project paths, or receive crafted JSON commands designed to exploit handler vulnerabilities.

Input Validation Vulnerabilities

The command parsing logic in ExecuteCommand (lines 128-139) splits command strings on the . character with minimal validation:

var parts = command.Split('.');
if (parts.Length < 2) {
    return ErrorResult("Invalid command format");
}

Malformed commands or excessively long strings may trigger exception handling paths that reveal internal state information. While the system catches exceptions to prevent crashes, error messages may leak sensitive configuration details to potential attackers.

Sensitive Data Exposure via Logging

When McpSettings.detailedLogs is enabled, the system logs complete JSON command payloads and responses to the Unity console. If commands contain authentication tokens, file paths, or proprietary parameters, these details persist in log files. An attacker with read access to Unity editor logs or the console window could extract these sensitive values from the detailed debug output.

Mitigation Strategies for Secure Handler Execution

Implementing defensive measures requires modifying the discovery, execution, and networking layers of the Unity MCP architecture.

Implementing Assembly Whitelists

Restrict handler discovery to explicitly trusted assemblies by modifying McpHandlerDiscovery.cs:

// In DiscoverAndRegister()
var whitelist = new[] { "UnityMCP", "MyTrustedPackage", "VerifiedVendor" };
if (!whitelist.Any(prefix => assembly.FullName.StartsWith(prefix)))
{
    continue; // Skip unknown assemblies
}

This prevents third-party packages from registering handlers without explicit inclusion in the whitelist.

Enforcing Execution Timeouts

Wrap handler execution in a cancellable task to prevent main thread blocking:

private JObject RunHandlerSafely(IMcpCommandHandler handler, string action, JObject parameters)
{
    var cts = new CancellationTokenSource(TimeSpan.FromSeconds(2));
    var task = Task.Run(() => handler.Execute(action, parameters), cts.Token);
    try { return task.Result; }
    catch (OperationCanceledException) { 
        return ErrorResult("Handler execution timeout"); 
    }
}

This pattern limits execution time and prevents infinite loops from hanging the Unity Editor.

Securing UDP Discovery

Add authentication token validation to the ReceiveCallback method in McpServer.cs:

// In ReceiveCallback
var token = serverInfo["authToken"]?.ToString();
if (token != ExpectedAuthToken) { 
    return; // Ignore unauthenticated announcements
}
this.TryConnect();

Only servers presenting the pre-shared secret can trigger automatic connections.

Sanitizing Debug Output

Prevent sensitive data leakage by filtering detailed logs:

private bool DetailedLogs => McpSettings.instance.detailedLogs && !IsSensitiveCommand(prefix);

private bool IsSensitiveCommand(string prefix)
{
    var sensitivePrefixes = new[] { "auth", "credentials", "private" };
    return sensitivePrefixes.Any(p => prefix.Contains(p));
}

This ensures commands containing authentication or credential data never appear in console logs.

Explicit Handler Disabling

Maintain a disable list in McpSettings to block specific handlers:

public HashSet<string> disabledPrefixes = new HashSet<string> { "UntrustedVendor", "SuspiciousPackage" };

Check this collection during registration to prevent known problematic handlers from activating, even if present in loaded assemblies.

Summary

  • Unity MCP loads handlers via reflection from all assemblies in the AppDomain without signature verification, as implemented in McpHandlerDiscovery.cs.
  • Handlers execute synchronously on the main thread with full Unity API access, creating risks of UI freezing and arbitrary code execution.
  • No sandboxing exists between handlers and the Unity Editor, allowing direct access to project assets and editor state.
  • UDP discovery accepts unauthenticated broadcasts, enabling potential man-in-the-middle or spoofing attacks.
  • Mitigation requires implementing assembly whitelists, execution timeouts, UDP authentication, and sensitive data filtering to secure the MCP environment.

Frequently Asked Questions

How does Unity MCP discover handlers without authentication?

Unity MCP uses reflection in McpHandlerDiscovery.cs (lines 34-55) to scan AppDomain.CurrentDomain.GetAssemblies() for types implementing IMcpCommandHandler. The system instantiates eligible types via Activator.CreateInstance without verifying assembly signatures or publisher identities, allowing any loaded DLL to register handlers automatically.

Can a malicious handler delete project assets or crash the Unity Editor?

Yes. Because handlers execute in the same AppDomain as the Unity Editor with full API access, malicious code can invoke AssetDatabase.DeleteAsset(), modify scene files, or enter infinite loops that block the main thread. The synchronous execution model in McpServer.ExecuteCommand provides no isolation from the editor process.

What timeout exists for handler execution?

The ExecuteCommand method in McpServer.cs implements a 5-second timeout using waitHandle.WaitOne(5000). However, this only affects the waiting mechanism; the handler itself runs synchronously on the main thread via ExecuteOnMainThread, meaning long-running operations will freeze the Unity UI until completion or timeout.

How can I prevent specific packages from registering MCP handlers?

Implement an assembly whitelist in McpHandlerDiscovery.DiscoverAndRegister() that checks assembly.FullName against trusted prefixes before instantiating handlers. Alternatively, maintain a disabledPrefixes HashSet in McpSettings and check it during the registration callback to block specific vendor prefixes from activating.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →