Skip to main content
Glama

mcp-testbed: Detecting Malicious MCP Server Behavior

CI Python Detections License

AI agents such as Claude Desktop, Cursor and VS Code load MCP (Model Context Protocol) servers as local child processes running with the user's full privileges. A malicious or compromised server, for example a typosquatted package or a poisoned update, can run commands and read secrets, and to most endpoint tooling it looks like an ordinary python.exe or node.exe.

This project builds a harmless test server that reproduces those behaviors, then answers two questions:

  1. What does default Windows / Wazuh / Sysmon logging actually see?

  2. What logging changes and detections are needed to catch it?

Safety by design. Commands come from a fixed allowlist of read-only built-ins (whoami, hostname, ipconfig, tasklist); no input reaches a shell. File reads are limited to fake decoy files the project creates, guarded by a marker file and a path check. There is no network code.

Threat model

flowchart LR
    U[User] --> C[AI client<br/>Claude Desktop / Cursor]
    C -->|stdio| S[MCP server<br/>python.exe / node.exe]
    S -->|T1059| SH[cmd.exe / powershell.exe]
    S -->|T1552| F[~/.aws/credentials<br/>~/.ssh/id_rsa<br/>.env]
    SH -.-> SYS[Sysmon Event 1 ✔]
    F -.-> GAP[Sysmon: no read event ✘<br/>needs SACL → 4663]

Related MCP server: Vulnerable MCP Server

Simulated behaviors

Tool

Imitates

ATT&CK

Telemetry needed

system_diagnostics

Server spawning a shell

T1059.003

Sysmon Event 1

encoded_powershell_check

Obfuscated PowerShell

T1059.001, T1027

Sysmon Event 1, PowerShell 4104

load_project_config

Reading cloud keys, SSH keys, .env, git creds

T1552.001, T1552.004

Security 4663 (SACL)

Detections

Detection

Format

Logic

MCP interpreter spawns shell

Sigma / Wazuh 100700

parent python/node/uv with MCP in cmdline → child shell

Interpreter spawns encoded PowerShell

Sigma / Wazuh 100701

parent interpreter → powershell -enc

Decoy credential read

Sigma / Wazuh 100702

4663 on decoy path

AI client launches interpreter

Sigma / Wazuh 100703

Claude/Cursor/Windsurf → python/node/uv (correlation context)

Sysmon config additions

XML

ensures interpreter children and credential-path writes are logged

Design decisions

  • Decoys, not real secrets. Decoys sit at paths that mimic real ones (...\mcp-testbed-decoys\.aws\credentials), so path-based detections built here carry over to real ~/.aws with no changes to the matching logic.

  • Why SACLs. Sysmon has no file-read event; Event 11 fires only on create/overwrite. The only native Windows signal for a read is object-access auditing (4663) on files with an audit ACE.

  • Parent command line as context. A Sysmon event shows the parent but not the grandparent, so the AI client itself isn't in the event. The parent command line contains the server path, which is the most reliable single-event signal; deeper lineage needs a ProcessGuid pivot.

  • Real client in the loop. client/trigger.py uses the official MCP SDK over stdio, which reproduces the true process tree instead of a direct script call.

Detection validation

Sigma and Wazuh rules are unit-tested against the same labeled synthetic events. The first run found an -ec evasion, 3 false positives from Defender and the Windows Search indexer, and no way to tell which processes are MCP servers. All are fixed (one fix caused a regression, which the tests caught), taking detection from 8/12 with 3 false positives to 11/12 with 0. The remaining miss is documented: it needs process-lineage correlation, not a single-event rule. Details: docs/detection-validation.md.

Detection validation

Safety tests

The safety guarantees above are enforced by tests, not just described: unlisted commands rejected, reads blocked until decoys exist, path escapes refused, setup never touches real credential folders, no network imports.

python -m unittest discover tests -v

Safety tests

Run it

Windows 11 lab VM with Sysmon and a Wazuh agent (see detection-range):

git clone https://github.com/TexasSlammer/mcp-testbed; cd mcp-testbed
py -m venv .venv; .\.venv\Scripts\Activate.ps1
pip install -r requirements.txt
python server\setup_decoys.py        # create fake credential files
.\scripts\Set-DecoyAudit.ps1         # (admin) enable 4663 on decoys
python client\trigger.py             # run all behaviors, log UTC windows to runs.csv

Executed already? Committed evidence from a real Linux run lives in runs/ (8/8 behaviors, real outputs, process lineage). The Windows run over Wazuh is the last measurement this project needs - docs/evidence-plan.md step M2.

Test it under a real AI client too (claude_desktop_config.json):

{ "mcpServers": { "testbed-utils": {
    "command": "C:\\path\\to\\mcp-testbed\\.venv\\Scripts\\python.exe",
    "args": ["C:\\path\\to\\mcp-testbed\\server\\testbed_server.py"] } } }

Findings

Execution evidence is committed under runs/: the testbed was executed for real (8/8 behaviors through a real MCP stdio session, real process lineage, real decoy reads). Windows default-logging behavior and its verification checklist are in FINDINGS.md. Rule-logic results are in docs/detection-validation.md.

Behavior

Default logging (documented)

After changes

Shell child process

4688 off by default; Sysmon channel not collected by the agent → invisible

Sysmon Event 1 → rule 100700

Encoded PowerShell

needs script block logging for the decoded script

4104 → rule 100701

Credential file read

Sysmon cannot log reads - no event

SACL + 4663 → rule 100702

Process lineage to AI client

single event shows parent only

ParentProcessGuid pivot + rule 100703 context

Author

Mark Lambert, M.S. Information Security & Privacy candidate, The University of Texas at Austin GitHub · LinkedIn

MIT License

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      C
      maintenance
      A deception-based threat detection server that impersonates enterprise MCP integrations to log and forward attacker interactions to SIEM systems. It provides convincing fake responses across 38 tools while capturing forensic details of all MCP tool calls.
      MIT