Red Harness
An evidence-bound static reverse-engineering harness for binaries you own or are authorized to test.
It is an MCP server (rh mcp, stdio) with 18 tools: static analysis through an IDA or Ghidra engine
(functions, strings, xrefs, decompile, disassemble, raw byte and raw string reading), controlled execution in Windows Sandbox when the
scope manifest allows it, a sandboxed compute tool for the model's own Python, and fix verification. Every claim a
model records has to cite evidence ids, quotes and addresses; a claim verifier checks them against the
evidence ledger and rejects or downgrades claims it cannot support. Behavior claims are proven only by a controlled run,
not by a value appearing in code. Whatever was not examined is reported as unknown, never as "clean".
Design notes are in docs/design/, the tool surface is in docs/usage-mcp.md and docs/tool-design.md, and the
privacy rules for tracked files are in docs/privacy-guard.md. Third-party attributions: NOTICE; optional third-party components and their licences: THIRD_PARTY_NOTICES.md.
How is this different
Tool-wrapper MCP servers give an agent reverse-engineering tools and pass the tool output through; nothing checks what the agent then says about the binary. Red Harness adds that check:
- Every claim is verified against recorded evidence. A claim cites evidence ids, quotes and addresses. A deterministic
verifier (no model) re-checks each one against the evidence ledger and rejects or downgrades what the evidence does not
support. Every status and reason it can give is listed in
docs/verifier-messages.md. - Behavior is proven only by a run. "This input is accepted" is never read off the code: it needs a controlled run of the target, and static evidence alone leaves such a claim unverified.
- Targets run in Windows Sandbox. Native execution of the target happens only there (network off, output records authenticated), and only when the scope manifest allows it.
- Unexamined is unknown. What was not looked at is reported as an unknown with its coverage, never as "clean".
Quickstart in 5 minutes
Install the red-harness-core package (the command it installs is rh; Python 3.12 on Windows):
pipx install red-harness-core
rh deps list # is Ghidra found? if not: rh deps show ghidra; it needs a JDK 21
rh quickstart C:\Windows\System32\notepad.exe
From a checkout instead: pipx install . (or build a wheel with python -m build --wheel and install the file from dist).
No model and no API key needed. rh quickstart checks the prerequisites, writes a scope manifest for the file (use a file you
own or are authorized to analyse), opens it with Ghidra (else IDA), runs a small static pass through the same code path as the
MCP tools, records two example claims that quote real evidence, builds the report and prints where it is, a short summary and
how to connect Claude Code or another MCP client. The first open runs the engine's analysis once (133 s for notepad.exe with
Ghidra 12.1.3 in our run); a repeat run is served from the cache (1 s).
Demo
Real output of rh quickstart C:\Windows\System32\notepad.exe --engine ghidra (Ghidra 12.1.3, Windows 10; the data folder
path is shown as <DATA_ROOT>):
Static pass with ghidra (the first open analyses the whole binary once; a cached result is reused later)
target_open x86 64-bit, 498 functions, 557 strings, protection NO_KNOWN_INDICATORS (140s)
functions_list 498 functions, evidence ev_04e98a81e9b3894d
imports 301 symbols from 28 DLLs, evidence ev_7e00c8229285bd85
strings 100 of 557 returned, evidence ev_c01e6dbb5a5ea895
claim_add SUPPORTED: The target imports GDI32.dll!CreateDCW at 0x140026800.
claim_add SUPPORTED: The target contains the string Unknown exception at 0x1400273d0.
Summary
target notepad.exe, entry 0x140023bd0, sha256 da5807bb0997cc6b...
pe profile PE32+ x64 windows_gui 7 sections aslr=yes dep=yes cfg=yes
claims 2 recorded, 2 verified by the claim verifier
report 2 findings, 0 hypotheses, 0 unsupported claims in findings (must be 0)
coverage NO_RECORDED_GAPS; not 'clean': functions listed 200/498, strings 100/557, nothing decompiled
Report: <DATA_ROOT>\jobs\job_da5807bb0997cc6b\report\report-8d4209bf00e1cef1.md
Total time: 142s
The generated report is in docs/examples/notepad-quickstart-report.md; each claim
cites evidence ids and quotes, and the coverage section lists what was not examined. docs/examples/README.md
explains each section.
Use from your agent
One command registers the MCP server (the absolute path of the installed rh, with the engine it found) in the AI coding
clients on this machine and installs the Red Harness skill, so your agent knows the evidence workflow:
rh setup --dry-run # shows what would change, with diffs; writes nothing
rh setup # applies it; restart the client afterwards
rh setup --client claude-code # only one client: claude-code, codex, cursor, gemini, claude-desktop
rh setup --print # only prints the configuration snippets, touches nothing
rh setup --uninstall # removes only the red-harness entry and the skill file it installed
Claude Code and Codex CLI are configured through their own claude mcp add / codex mcp add; Cursor
(~/.cursor/mcp.json), Gemini CLI (~/.gemini/settings.json) and Claude Desktop (claude_desktop_config.json, classic or
Microsoft Store install) through their JSON files, merged. The skill goes to ~/.claude/skills/red-harness/ (Claude Code) and
~/.agents/skills/red-harness/ (Codex CLI, Gemini CLI); --no-skill skips it. Every file is copied to
<name>.rh-backup-<timestamp> before it changes, existing servers and settings are kept, and a second run changes nothing.
A red-harness entry that does not run rh mcp, or a skill file you edited, is reported and left alone (--force
overrides that).
Then ask your agent, for example: "reverse engineer C:\path\to\tool.exe; I own it". Use only binaries you own or are
authorized to test.
Editions
This repository is the Core edition (Apache-2.0). Pro is a separate commercial edition. The MCP tool surface (18 tools) is the same in both; Pro adds capabilities behind the same tools and a few extra commands.
| Core (this repo, Apache-2.0) | Pro (commercial) | |
|---|---|---|
Static MCP tools (functions, strings, xrefs, decompile, disassemble, read_bytes, file_strings, imports) |
yes | yes |
| Evidence ledger, claim verifier, report | yes | yes |
| Ghidra and IDA engines | yes | yes |
run_controlled and compute in Windows Sandbox |
yes | yes |
| Protection diagnosis (including vendor attribution) | yes | yes |
Check inventory (candidate protection / licensing checks in target_open) |
yes | yes |
Dynamic observation (run_controlled(observe=...): API trace, executable-memory digests) |
no | yes |
Job bundle export and import (rh export, rh import) |
no | yes |
Vendor audit pack (driver facts in target_open, driver/service/bundle/workspace triage scripts) |
no | yes |
Evaluation and benchmark suite (rh eval, rh bench) |
no | yes |
| Kernel / Phase 2 lab | no | yes |
| Studio UI | no | planned |
In the Core build the Pro-only entry points answer in a fixed way: run_controlled with observe returns
DYNAMIC_BACKEND_UNAVAILABLE ("premium feature not included in this build"), the Pro CLI commands print a premium notice and
exit with status 2, and the driver facts in target_open are {"available": false, "note": "premium feature not included in this build"}.
To ask about Pro: open a thread in GitHub Discussions.
Requirements
- Windows 10 or 11, 64-bit (developed and tested on Windows 10 Pro). The server, the engines and every static tool run on any edition.
- Python 3.12 (
py -3.12). The only runtime dependency is themcpSDK, pinned and installed by pip. - One analysis engine: Ghidra (free) or IDA Pro (see "Engines"). No MCP tool works without an engine, because
target_openopens the target through it. - Windows Sandbox, only for the two tools that execute the target natively or run model code (
run_controlledandcompute). Windows Sandbox is part of Windows 10/11 Pro, Enterprise and Education (not Home); it needs hardware virtualization enabled in the firmware and the optional Windows feature "Windows Sandbox" switched on (restart required). Without it those two tools returnSANDBOX_UNAVAILABLEand everything else keeps working. The sandbox gets 2048 MB of memory by default (RH_SANDBOX_MEMORY_MB, 512 to 16384).emulatealso executes target code, but in a CPU emulator inside a restricted host process, not in Windows Sandbox; it is off by default.computealso needs a pinned embeddable CPython, installed once:rh compute-runtimeprints the download address and the expected SHA-256, thenrh compute-runtime install python-3.12.10-embed-amd64.zip.
- Memory: the Ghidra engine runs a JVM with a 4 GB heap (6 GB job limit); the IDA engine is limited to 6 GB as well.
Optional components
Red Harness bundles no third-party engine or library. The optional pieces are obtained by you, from their own
publishers, under their own licences, and none of them is covered by Red Harness's Apache-2.0 licence:
Unicorn (emulate), Capstone, Ghidra, IDA Pro/Home, the CPython embeddable package for compute, and Windows Sandbox.
See THIRD_PARTY_NOTICES.md (what each is for, how to get it, its licence and upstream link) and licenses/README.md.
rh deps list shows each component, whether it is present, its licence and its upstream link. rh deps install emulate
(or capstone) prints the licence notice, asks for confirmation (--yes skips the question) and then runs
pip install for the pinned version; it installs nothing else. Ghidra and IDA are never installed by rh: rh deps show ghidra
prints where to get them and which environment variable points Red Harness at them.
Engines
Every MCP tool needs an analysis engine; choose one with rh mcp --engine ghidra or rh mcp --engine ida. Without the flag
the server starts the IDA engine. A requested engine that is not usable stops the server with the reason on stderr and in the
error answer to the client's initialize request; there is no silent fallback to the other engine.
Ghidra (free).
- Ghidra 12.1.3 (the version this project is tested with): download the zip from https://github.com/NationalSecurityAgency/ghidra/releases and extract it anywhere.
- A JDK 21 (for example Eclipse Temurin 21), with
javaonPATHorJAVA_HOMEset. Check withjava -versionin a new terminal. - Tell the server where Ghidra is: set
RH_GHIDRA_DIR(orGHIDRA_INSTALL_DIR) to the extracted folder, the one that containssupport\analyzeHeadless.bat. Without either variable the server looks forghidra_*on your Desktop, forghidra*in your user folder and in%ProgramFiles%, and forC:\ghidra*(newest name first). - Start the server with
rh mcp --engine ghidra. The first open of a target runs Ghidra's full analysis once (minutes for a large binary; about two and a half minutes for a 200 KB system program on a desktop PC); the result is cached under the data root and later opens and queries reuse it.
IDA. IDA 9.x with a licence that includes idalib (IDA's headless library): the Pro editions. IDA Home and Classroom are listed by Hex-Rays as shipping idalib since 9.4; not yet tested by us. The Python package idapro that
talks to it is deliberately not a dependency of this project (its publisher on PyPI is unverified); install it from the wheel in
your IDA installation into the same environment as red-harness-core:
.venv\Scripts\pip install "<IDA>\idalib\python\idapro-0.0.9-py3-none-any.whl"
(With a pipx install: pipx inject red-harness-core "<IDA>\idalib\python\idapro-0.0.9-py3-none-any.whl".)
<IDA> is for example C:\Program Files\IDA Professional 9.4. Use the exact file name you find in that folder (dir "<IDA>\idalib\python");
pip does not accept a * wildcard there. Do not run py-activate-idalib.py. The IDA folder is found automatically under
%ProgramFiles%\IDA Professional* or from RH_IDA_DIR / IDADIR. The engine runs IDA in a separate Python process; if that
Python is not the one with idapro, set RH_IDA_PYTHON to it. Without idapro, target_open fails with TOOL_MISSING and
a message that says exactly this.
What works without any engine: none of the 18 MCP tools. The standalone scripts in scripts/ need no engine and execute
nothing (see "Standalone static CLIs"), and so does rh compute-runtime.
Quickstart
This walk-through uses Ghidra and runs the same calls a model makes, from a small Python client that ships with the project.
Use a program you built or are authorized to analyze; below it is C:\path\to\target.exe.
py -3.12 -m venv .venv
.venv\Scripts\pip install -e .
set RH_GHIDRA_DIR=C:\path\to\ghidra_12.1.3_PUBLIC
(set is for cmd.exe; in PowerShell use $env:RH_GHIDRA_DIR = "C:\path\to\ghidra_12.1.3_PUBLIC". Skip it if Ghidra sits in one
of the folders listed under "Engines".)
- SHA-256 of the target, lowercase (the manifest rejects upper case):
powershell -NoProfile -Command "(Get-FileHash 'C:\path\to\target.exe' -Algorithm SHA256).Hash.ToLower()" - Write the scope manifest
scope.jsonnext to it. The hash binds the manifest to this exact file;basisisownerorauthorized-test;allowed_operationslists what the session may do (staticis the minimum;run_controlledandcomputemust be added explicitly); an optional"expires": "2027-12-31"limits its lifetime.{ "schema": "rh.scope/1", "target_sha256": "<the lowercase hash from step 1>", "authorization": { "declared_by": "Your Name / Your Company", "basis": "owner", "statement": "This binary belongs to us; static analysis is authorized." }, "allowed_operations": ["static"] }
- Run the client (first open: Ghidra analyses the target once):
It starts.venv\Scripts\python scripts\quickstart_client.py C:\path\to\target.exe scope.json --engine ghidrarh mcp --engine ghidra, lists the tools and makes five calls:target_open(target_path, manifest_path),strings(limit=20, detail="full"),claim_add(kind="observation", text, evidence_ids, atoms)quoting the first string it got back,coverage()andreport_build(). It ends with the path of the Markdown report, under<data root>\jobs\<job id>\report\. A model client makes exactly these calls with the arguments named above; theclaim_addatoms are{"type":"quote","evidence_id":"ev_...","text":"<string>"}and{"type":"address","evidence_id":"ev_...","value":"0x..."}.
Connect an MCP client
Use absolute paths. The server needs the engine settings in its environment.
Claude Code: copy .mcp.json.example to .mcp.json in your project folder, replace the placeholder paths, start Claude Code and
approve the red-harness server with /mcp.
{
"mcpServers": {
"red-harness": {
"type": "stdio",
"command": "C:\\path\\to\\red-harness\\.venv\\Scripts\\rh.exe",
"args": ["mcp", "--engine", "ghidra"],
"env": {"RH_GHIDRA_DIR": "C:\\path\\to\\ghidra_12.1.3_PUBLIC", "RH_DATA_ROOT": "C:\\path\\to\\RedHarnessData"}
}
}
}
OpenAI Codex CLI (~/.codex/config.toml):
[mcp_servers.red-harness]
command = 'C:\path\to\red-harness\.venv\Scripts\rh.exe'
args = ["mcp", "--engine", "ghidra"]
env = { RH_GHIDRA_DIR = 'C:\path\to\ghidra_12.1.3_PUBLIC', RH_DATA_ROOT = 'C:\path\to\RedHarnessData' }
Any other stdio MCP client: run the command C:\path\to\red-harness\.venv\Scripts\rh.exe with the arguments mcp --engine ghidra
and the environment variables above. The protocol runs over the process's stdin and stdout (one JSON-RPC message per line), so
nothing else may write to stdout. scripts/quickstart_client.py is a complete example client built on the official mcp SDK.
The server side was verified with that SDK client; the client entries above follow those clients' documented formats.
If a client only says "connection closed", start the same command in a terminal: the reason is printed on stderr.
Development and tests
Install with the test extra and run the default suite (no engine and no Windows Sandbox needed):
py -3.12 -m venv .venv
.venv\Scripts\pip install -e .[dev]
.venv\Scripts\python -m pytest -m "not heavy"
heavytests need a real Ghidra/IDA or Windows Sandbox; they are not part of the default run.- Unit tests point
RH_DATA_ROOTat a temp directory;RedHarnessDataor any other directory need not exist beforehand. - Real Windows Sandbox tests run only with
RH_ALLOW_REAL_SANDBOX=1(otherwise skipped). - Engine paths and the
idaproinstall are described under "Engines" above and indocs/usage-mcp.md.
Standalone static CLIs
Read-only helper in scripts/ that needs no engine, no Windows Sandbox and executes nothing: file_strings.py (it prints its usage in its module docstring).
Scope
Use it only on targets you own or are explicitly authorized to test. The scope manifest is required, binds the target
SHA-256 and lists the effects (for example run_controlled, compute) a session may use.
Metadata
Release files for red-harness-core 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| red_harness_core-0.1.1.tar.gz | 469.8 kB | Without provenance | Details for red_harness_core-0.1.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| red_harness_core-0.1.1-py3-none-any.whl | Python 3 | none | any | Details for red_harness_core-0.1.1-py3-none-any.whl |
Total release size: 990.9 kB
Release files / red_harness_core-0.1.1.tar.gz
| Download URL | red_harness_core-0.1.1.tar.gz |
|---|---|
| Size | 469.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e304e51e55601f66987cadae57a5ae5215557d5df4263992b23a0c73edfa8ef3
|
|
BLAKE2b-256 checksum How to use checksums |
d9444817f705a70f5e35eb7601e2217e68d569e0259f174b9700c9e8ae4f1098
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.10
|
Release files / red_harness_core-0.1.1-py3-none-any.whl
| Download URL | red_harness_core-0.1.1-py3-none-any.whl |
|---|---|
| Size | 521.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2bf5e789b1a3d66bf2d85327064cc3d38d6dd8b7b40fe2f164b097d37cffef09
|
|
BLAKE2b-256 checksum How to use checksums |
a3e19ccb250ca2478662b59700186ff7a0c023726a14f8b13b2fad7b8156e789
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.10
|
Security for red-harness-core 0.1.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.