Malspark

Tools

Ghidra

The decompiler-backed static provider and its container.

Ghidra is the decompiler-backed static provider, served by Ghidra MCP. The compose stack's ghidra profile, which the shipped docker/.env turns on, builds and runs the ghidra-mcp service from external/ghidra-mcp, which make setup (or make external) reconstructs. A deployment without Ghidra takes ghidra out of COMPOSE_PROFILES.

Connect it

core.static.provider          = ghidra
core.static.ghidra.enabled    = true
core.static.ghidra.transport  = http
core.static.ghidra.url        = http://ghidra-mcp:8089
core.static.ghidra.auth_token = <GHIDRA_MCP_AUTH_TOKEN from docker/.env>
core.static.provider          = ghidra
core.static.ghidra.enabled    = true
core.static.ghidra.transport  = http
core.static.ghidra.url        = http://localhost:8089
core.static.ghidra.auth_token = <GHIDRA_MCP_AUTH_TOKEN from docker/.env>

The Choose a static analyser setup guide walks the same settings and tests the connection. The shipped transport is stdio with no command, so switching Ghidra on without setting transport to http is refused at job submit with a sentence that says so.

Ghidra does not degrade

A static run with no decompiler would be a confident report grounded in nothing, so an agent that needs Ghidra fails the run when it starts. POST /api/v1/jobs therefore asks first: every agent of the chosen team that opens Ghidra is checked, and a Ghidra that is not ready is a 422 naming the agent and the address. See A team that needs Ghidra waits for it.

The samples path

The worker copies each sample under the samples directory, and the ghidra-mcp container mounts that directory at /data/samples. core.static.ghidra.sample_mount is that path inside the Ghidra container — /data/samples as shipped, matching the compose file — and never the host directory. Set to a host path, Ghidra answers every load with File not found. The worker states the path it hands Ghidra in one line at start:

Static provider 'ghidra' mirrors a sample to data/samples/.work/<sha256> and is handed it as /data/samples/.work/<sha256>.

See Where a tool server sees the sample.

Running it lighter

The ghidra-mcp service reads three variables from docker/.env:

VariableDefaultLighter
GHIDRA_JAVA_OPTS-Xmx4g -XX:+UseG1GC-Xmx2g -XX:+UseG1GC
GHIDRA_MEM_LIMIT6g4g
GHIDRA_RESTARTunless-stoppedno, to start it only for the runs that need it

Keep the memory limit about 2g above the heap: Ghidra's database is memory-mapped and its direct buffers live outside the heap. See Running Ghidra lighter.

What an agent on Ghidra gets

Before an agent on Ghidra over http starts its loop, its sample is loaded once, and a sink-reachability pre-pass gives the agent its priority functions on the first turn. The sample is mirrored for Ghidra even when Ghidra is not the deployment's global provider, so a reverser given static_provider: "ghidra" works under any global setting. The deep_static team's reversing stage and the importable all-tools team's reverser are the teams that use it most. See Which agents open a static provider.

What its tools are read as

The platform ships no table of Ghidra's tools. Each one is read from what Ghidra lists, by its verb, its object and its arguments' role words. Over HTTP that is its /mcp/schema, and over stdio its MCP listing; both read the same. The block says once that its tools run nothing, reach no network and send nothing (default_effects). A tool that says otherwise keeps what it says: emulate_function and emulate_hash_batch emulate, and run_ghidra_script and run_script_inline run whatever they are given. A read is read-only only when it names the job's program, so list_open_programs and list_scripts always run again. See A decompiler's or disassembler's tools read from what it lists.

Edit on GitHub

On this page