Attack-surface mapping and protocol fuzzing for distributed energy resource (DER) protocols — DNP3, SunSpec Modbus, and IEEE 2030.5 — with an MCP server that lets an AI assistant drive the tools and reason over the results.
Built as part of a DOE-funded research effort to help asset owners answer a concrete question: which device commands and registers are reachable by an unauthenticated attacker on my network?
⚠️ These are offensive tools. Mapping is read-only; fuzzing can hang or crash live grid equipment. Only use them against devices you own or are explicitly authorized to assess. See SECURITY.md.
der_common/ shared AttackSurface schema + safety/scope gate + run storage
der_sep2/ IEEE 2030.5: discover / tls / map / fuzz (most mature)
der_dnp3/ DNP3: scan / map / fuzz (boofuzz)
der_sunspec/ SunSpec Modbus: self-describing model map + device/client fuzzers
der_mcp/ MCP server exposing all of the above
examples/ sample outputs + a quickstart device simulator script
demo/ a simulated DER cluster spanning all three protocols
Every mapper/fuzzer normalizes to one AttackSurface model
(der_common/schema.py) so results are comparable across protocols — the
whole point of building this as one toolkit instead of three separate ones.
pip install -e ".[all]" # everything, or pick groups:
pip install -e ".[sunspec]" # just the SunSpec mapper
pip install -e ".[mcp]" # + the MCP serverSee it work end to end against a real (simulated) device — no hardware, no vendor docs, no target of your own required.
# 1. Install der-toolkit
pip install -e ".[sunspec]"
# 2. Start a tiny SunSpec/Modbus device simulator on 127.0.0.1:5503
# (pure Python, just uses the pymodbus dependency you already installed)
python3 examples/quickstart_server.py
# 3. In another terminal, map its attack surface
der-sunspec map 127.0.0.1 --port 5503That one unauth-writable field is real: the device's Modbus DA (Device
Address) register accepts unauthenticated writes, flagged critical in the
full JSON output (der-sunspec map ... --output result.json). Compare against
examples/sunspec_attack_surface.sample.json
for the complete shape.
der-sep2 map <host> --client-cert c.crt --client-key c.key
der-dnp3 map <host> --port 20000Every map --output result.json command saves the same {"attack_surfaces": [...]} shape regardless of protocol. der-report merges any mix of them into
one severity-ranked view — the writable, unauthenticated-reachable points
across your whole DER deployment, not three separate JSON files you have to
cross-reference by hand:
der-report dnp3_result.json sunspec_result.json sep2_result.jsonThat's real output (trimmed for length) from the demo cluster below — 7 targets, 67 writable/unauthenticated-reachable points, 19 cross-cutting findings. Full, untrimmed version: examples/demo_cluster_report.sample.txt (structured JSON).
demo/ stands up nine simulated devices at once — seven
make up the mapping cluster (three SunSpec inverters with deliberately
different control surfaces, two DNP3 outstations, and two SEP2 servers,
hardened vs. vulnerable) for a full-pipeline run against something that
looks like a real small DER deployment, plus two more purpose-built,
intentionally-vulnerable fuzzing targets:
demo/sep2_server/setup.sh # one-time: generate the SEP2 test PKI
python3 demo/run_cluster.py # starts all nine devicesThe cluster also works as an MCP demo — see demo/README.md's walkthrough for the setup and an example prompt that has an AI assistant discover, map, and summarize it on its own.
der-mcp speaks MCP over stdio; point Claude Desktop / Claude Code at it. Tools:
list_capabilities, discover_targets, map_attack_surface (read-only),
start_fuzz / get_job / get_findings (async, gated behind explicit consent).
This repo ships a project-scoped .mcp.json that registers der-mcp (after
pip install -e ".[mcp]"). Opening this directory in Claude Code prompts you
to approve it the first time — that's Claude Code's standard trust gate for
any repo-committed MCP server. To register it manually instead: claude mcp add --scope project der-mcp -- der-mcp.
All three protocols and the MCP server work end to end. Each has been checked against a real reference implementation, not just der-toolkit's own code — a real DNP3 outstation, a real SunSpec device simulator, and a real IEEE 2030.5 test server.
Known gaps: no testing yet against physical vendor hardware, and 9 of the
newer 700-series SunSpec DER control models (the ones with a runtime-sized
curve table) fall back to a coarse, model-level control point instead of a
full field-level decode — see der_sunspec/smdx/NOTICE.md.