Current release target: 2.0.0
MarlinSpike is a ground-up passive OT/ICS network analysis platform built in the tradition of GrassMarlin-style topology mapping, but wrapped in a multi-user web workbench designed for real engagements. It analyzes PCAP and PCAPNG captures, builds a topology graph, infers Purdue levels, fingerprints vendors, and surfaces responder-grade risk indicators such as cross-zone communication, cleartext services, beaconing, suspicious external communications, and DNS exfiltration, then exports everything as portable JSON report artifacts that travel with the team.
Designed for on-site team engagements — multi-user, zero-JS core workflows, 1 core / 1 GB RAM, and portable JSON report artifacts.
1.1M packets -> 46 nodes, 1,344 edges, 432 findings in 29 seconds.
Repository: github.com/riverrisk/marlinspike
MarlinSpike is not just a topology viewer and it is not just a packet parser.
It is a field-deployable analyst platform built around four ideas:
- Passive OT/ICS analysis first: capture files in, no packets sent back onto the network.
- Ground-up GrassMarlin-style replacement: modern topology reconstruction, protocol-aware classification, and analyst-friendly reporting without inheriting the old single-user desktop model.
- Multi-user workbench: projects, uploads, reports, history, administration, and a shared URL the whole engagement team can use at once.
- Portable report contract: the engine can run headlessly, produce report artifacts, and those artifacts can be reviewed in the built-in workbench or consumed elsewhere.
The result is a different operating model than a desktop analyzer. MarlinSpike is meant to be dropped onto a temporary engagement host, fed captures from taps, SPAN ports, or external collection, and used collaboratively during triage and assessment.
MarlinSpike is built around a few practical constraints:
- The engine remains standalone and can produce report artifacts headlessly.
- The report artifact is the handoff between packet analysis and downstream review.
- The primary workflow is
project -> scan -> report -> workbench -> triage actions. - Core web workflows remain usable without client-side JavaScript.
- The codebase stays intentionally extensible for working OT/ICS responders, not just systems programmers.
Interactive browser features can improve speed and convenience, but the core triage experience should still be accessible directly from rendered HTML.
- Passive analysis only: no active scanning or packet transmission
- OT protocol parsing for Modbus, EtherNet/IP, S7, DNP3, PROFINET, OPC UA, BACnet, and more
- Expanded Rust DPI substrate via
marlinspike-dpi: 34 protocol dissectors, Bronze v2 event output, frame-integrity inspection, ICMP anomaly inspection, and stateful L2 anomaly analysis - Topology construction with Purdue-level inference and vendor fingerprinting
- Risk surfacing for remote access exposure, C2-like beaconing, suspicious external channels, DNS entropy anomalies, policy violations, full MITRE ATT&CK mapping with tactics, sub-techniques, matrix views, response guidance, and IEC 62443 SR-oriented remediation guidance
- Flask web UI with an upgraded multi-mode analyst workbench, project management, report viewer, baseline/drift comparison, asset inventory, scan history, optional local live capture mode, and a source-backed
/capabilitiesdetection coverage catalog - Docker Compose deployment with PostgreSQL backing the application
- Optional Rust DPI stage via
marlinspike-dpi, built into the image from a pinned GitHub ref while Python analysis and report shaping remain above it - MITRE ATT&CK runtime surfaces sourced from the standalone
marlinspike-mitrerepo at a pinned GitHub ref during image build - Optional Stage 4b malware IOC runtime sourced from standalone
marlinspike-malwareandmarlinspike-malware-rulesrepos when their build args are provided
- Clone the repository and enter the project directory.
git clone https://github.com/riverrisk/marlinspike.git
cd marlinspike- Copy the example environment file and set strong secrets.
cp .env.example .env- Build and start the stack.
docker compose up -d --build- Open the app at
http://127.0.0.1:5001or through your reverse proxy.
On first boot, MarlinSpike creates an admin user. If ADMIN_PASSWORD is empty, a random password is generated and printed to the container logs.
See INSTALL.md for a generic deployment walkthrough.
If you are looking for the main repository docs, start here:
- Getting started: INSTALL.md
- Repo family and suite structure: docs/repo-family.md
- Compatibility model: COMPATIBILITY.md
- Architecture and extension boundaries: docs/extensibility-contracts.md
- Zipped report bundle format proposal: docs/msbundle-format.md
- End-user ATT&CK guide: docs/mitre-attack-guide.md
- Shared MITRE plugin repo:
/Users/butterbones/marlinspike-mitre - Vendored ATT&CK runtime copy:
plugins/marlinspike_mitre/andrules/mitre/base.yaml - MITRE bootstrap sync helper:
scripts/sync-mitre-bootstrap.sh - Suite subtree helper:
scripts/update-subtrees.sh - Bootstrap engine sync helper:
scripts/sync-msengine-bootstrap.sh - Contribution and development workflow: CONTRIBUTING.md
- Engine and product release history: releases.md
- Live viewer and streaming release history: releases-live.md
- Analyst workspace product direction: docs/analyst-workspace-roadmap.md
- Public fingerprinting research corpus: docs/public-fingerprint-corpus.md
- Preset sample library notes: presets/README.md
The key extensibility terminology in this repository is:
- Rust engines: packet-facing and event-heavy components such as DPI
- Python plugins: report-facing analysis, enrichment, and triage logic
- YAML rule packs: declarative mappings, suppressions, and local policy
The key repo-family terminology is:
marlinspike: suite repo that vendors selected component repos as subtree-based subrepos and can pin standalone build dependenciesmarlinspike-msengine: core engine repo, internal package and CLI namemsenginemarlinspike-workbench: web UI repo that can review reports with or without invoking the local enginemarlinspike-mitre: standalone shared MITRE ATT&CK plugin repo consumed as a pinned build dependency for runtime plugin and rule surfacesmarlinspike-dpi: standalone shared Rust DPI repo consumed as a pinned build dependency in the app imagemarlinspike-malware: standalone shared Rust IOC engine repo consumed as an optional pinned build dependency in the app imagemarlinspike-malware-rules: standalone shared rule-content repo consumed as an optional pinned build dependency for published IOC packs, manifests, and compiled bundle artifacts
The component repos are intended to be authoritative. The suite repo exists to pin and vendor a known-good combination for teams that want one clone with all updated parts.
The initial msengine/ subtree prefix now exists in bootstrap form. Until full extraction completes, the root _ms_engine.py remains the operational engine source and scripts/sync-msengine-bootstrap.sh mirrors it into the subtree copy.
The current Docker build pins marlinspike-dpi to de7ed06a28096a3da482831bc674ef0652c0e479 by default via MARLINSPIKE_DPI_REF, marlinspike-mitre to c3583ec2d189b8cde69f2160da6a5e8e5b643f7b via MARLINSPIKE_MITRE_REF, marlinspike-malware to 02eb369c32e5050796c76be500c009dc0cb8940d via MARLINSPIKE_MALWARE_REF, and marlinspike-malware-rules to 99cbe9358d0a5047d9b5e57a7e4ff5eafdee9bd4 via MARLINSPIKE_MALWARE_RULES_REF. On March 28, 2026, the rules ref was refreshed to a valid published commit and the malware repo was confirmed publicly readable at the pinned ref. Override those build args in your environment if you need a different known-good combination. The app prefers the published packs/ surface over the engine repo's dev/test copy when discovering rules.
MarlinSpike now includes a full ATT&CK implementation in the report workflow, including ATT&CK version metadata, tactic-grouped matrix views, sub-techniques, mitigations, and response guidance.
See the user-facing walkthrough here:
The guide includes screenshots and explains how to move between findings, ATT&CK mappings, assets, and topology during triage.
MarlinSpike is not a general-purpose desktop analyzer. It is purpose-built as a temporary on-site analyst workbench for OT security engagements and assessments.
| Aspect | MarlinSpike (this project) | Typical desktop GRASSMARLIN-style tools |
|---|---|---|
| Primary Use Case | Spin up on an IPC or field laptop during a plant-floor engagement, review team-collected PCAPs, and hand back portable assessment artifacts | Solo deep-dive analysis on a single workstation |
| User Model | Multi-user, project-scoped workflow with auth, admin controls, and audit history | Usually single-user first |
| Deployment | Lightweight Docker Compose web app with zero-JS core workflows and a 1 core / 1 GB RAM target |
Desktop GUI application with heavier client-side runtime expectations |
| Report Workflow | PCAP from anywhere to self-contained JSON report artifacts, viewable here or consumable elsewhere, plus PDF/PNG/CSV exports | Tool-centric workflow with tighter coupling to the local application |
| Operational Model | Shared URL for the engagement team, fast setup and teardown, suitable for temporary or air-gapped field use | Persistent analyst desktop environment |
| Extensibility | Python analysis pipeline and HTML templates that are approachable for most security teams | Often centered on compiled desktop stacks with a steeper customization path |
In short: Drop MarlinSpike on an air-gapped or temporary engagement host, hand the URL to the team, feed it the captures you collected, export clean portable JSON reports, and tear it down when the job is done.
If you are looking for a permanent single-user desktop application with a different feature focus, MarlinSpike is not trying to be that tool, and that is intentional.
MarlinSpike is meant to replace the core passive-mapping workflow people historically used GrassMarlin for, while changing the wrapper around it from a single-user desktop app to a shared web workbench.
| Capability | MarlinSpike status | Notes |
|---|---|---|
| Passive PCAP analysis | Yes | Accepts pcap and pcapng from the web UI or the standalone engine |
| OT-aware topology mapping | Yes | Relationship map, node/edge graph, vendor hints, and Purdue inference |
| Asset inventory | Yes | Per-asset roles, services, protocols, and responder-facing context |
| Protocol-aware OT analysis | Yes | Modbus, EtherNet/IP, S7, DNP3, PROFINET, OPC UA, BACnet, IEC 104, LLDP/CDP/STP/LACP, and more |
| Risk surfacing from passive traffic | Yes | Cleartext engineering, write-capable paths, suspicious external communications, beaconing, DNS exfiltration, and Purdue violations |
| Local live capture | Yes, optional | Exposed as an optional deployment feature rather than the main product contract |
| Exportable outputs | Yes | Portable JSON report artifacts, plus PDF/PNG/CSV export paths from the UI |
| Team analyst workflow | Exceeds | Project-scoped collaboration, shared URL access, history, baseline/drift review, and admin controls are first-class instead of bolted on |
| Headless analysis contract | Exceeds | The engine can run independently, emit portable report artifacts, and be reviewed later in the workbench or elsewhere |
| Thick desktop client | Different by design | Replaced with a browser-based workbench and zero-JS core workflows for temporary, shared field deployment |
- Fingerprint depth and classification confidence across more vendors and device families
- Server-rendered analyst drill-down flows in the viewer
- Richer use of Bronze-level protocol observations and extracted artifacts in the report UI
- Broader protocol-native enrichment beyond the current report contract
- MarlinSpike is not an active scanner.
- MarlinSpike is not a permanent desktop thick client.
- The standalone Rust DPI engine is a dissection substrate, not the whole product.
- Some protocol coverage and higher-level scoring still live in the Python analysis layer today, by design.
MarlinSpike keeps packet dissection separate from analyst workflow.
- Stage 1: capture ingestion and validation
- Stage 2: protocol dissection
- Stage 3: topology construction, Purdue inference, and fingerprinting
- Stage 4: breach-triage and risk surfacing
- Output: portable JSON report artifact consumed by the web workbench
MarlinSpike can currently run Stage 2 in two ways:
- Built-in Python/tshark-based dissection via
_ms_engine.py - External Rust dissection via
marlinspike-dpi
The Rust path is intentionally scoped as a standalone DPI engine. MarlinSpike can call it as an external Stage 2 parser, adapt its Bronze output back into the current report pipeline, and continue using the existing topology, triage, and reporting layers. That keeps the packet parser reusable without forcing the analyst product to collapse into the parser.
- It is a standalone Rust DPI engine with CLI, library, and FFI surfaces.
- It accepts classic
pcapandpcapngcapture input. - It currently ships 34 protocol dissectors across OT/ICS, IT, and L2 traffic.
- It emits Bronze v2 events that MarlinSpike can consume across five families: protocol transactions, asset observations, topology observations, parse anomalies, and extracted artifacts.
- It layers additional parser-adjacent inspection through
stovetopframe integrity checks,icmpeekerICMP anomaly analysis, andbilgepumpstateful L2 anomaly tracking. - It replaces the dissection stage, not the higher-level breach-triage logic.
That is deliberate. MarlinSpike's value is not just decoding packets quickly. Its value is turning passive OT traffic into topology, findings, and responder decisions a team can actually use.
MarlinSpike uses three extension surfaces on purpose:
- Rust engines: packet-facing or event-heavy components where throughput, memory safety, and parser reuse matter most. Today this primarily means DPI-style engines such as
marlinspike-dpi. - Python plugins: report-facing analysis, enrichment, triage logic, and post-processing that operate on the portable MarlinSpike JSON artifact rather than raw packets.
- YAML rule packs: declarative mappings, enable/disable controls, site overrides, and other policy content used by plugins without turning configuration into another programming language.
In short:
- Rust finds facts in raw traffic.
- Python turns those facts into responder-facing judgments.
- YAML declares mappings and local policy.
This split is intentional. MarlinSpike is not written as "Rust for everything" because the primary app is meant to be easy to extend by the broader OT/ICS community, including responders, defenders, and consultants who may need to adjust logic during an active remediation event. Rust is excellent for memory-safe, reusable packet engines. Python remains a better fit for fast iteration, site-specific extension, and field-friendly report logic when a team is actively triaging an environment.
Current shipped example:
marlinspike-mitre: authoritative sister repo at/Users/butterbones/marlinspike-mitre, with the app image now overlaying the runtime plugin and rule surfaces from the pinned standalone repo intoplugins/marlinspike_mitre/andrules/mitre/base.yamlduring build. Successful scans can emit a-mitre.jsonsidecar artifact, and the workbench viewer can load it from the reportextensionssurface. The current runtime exposes full ATT&CK metadata and versioning, tactics, sub-techniques, matrix-ready tactic groupings, mitigations, ATT&CK URLs, and rich response guidance in the viewer. User-facing interpretation notes live in docs/mitre-attack-guide.md.marlinspike-malware: authoritative sister repo at/Users/butterbones/marlinspike-malware, with_ms_engine.pyinvoking it as an optional Stage 4b engine. WhenMARLINSPIKE_MALWARE_REPOandMARLINSPIKE_MALWARE_REFare supplied during image build, the runtime binary is layered into/opt/marlinspike-malware/bin/.marlinspike-malware-rules: authoritative sister repo at/Users/butterbones/marlinspike-malware-rules, holding the publishedpacks/,manifests/index.yaml, and compiled bundle artifacts. The current published surface is 30 packs and 921 rules. WhenMARLINSPIKE_MALWARE_RULES_REPOandMARLINSPIKE_MALWARE_RULES_REFare supplied during image build, those assets are layered into/usr/share/marlinspike-malware/rules/, and the engine points at/usr/share/marlinspike-malware/rules/packs.
See docs/extensibility-contracts.md for the concrete contract boundaries for Rust engines, Python plugins, and YAML rule packs.
If you are deciding where new work belongs, use this rule of thumb:
- If it consumes raw
pcap, packet streams, or high-volume protocol events, it probably belongs in a Rust engine. - If it consumes the finished MarlinSpike report artifact, it probably belongs in a Python plugin.
- If analysts should be able to tune it without code changes, it probably belongs in a YAML rule pack.
MarlinSpike's current public detection and standards story is intentionally bounded to what the engine already emits today.
- Full MITRE ATT&CK implementation is now present through the shared
marlinspike-mitreruntime, including ATT&CK version metadata, tactic-aware matrix output, sub-techniques, parent-technique context, mitigations, and response guidance marlinspike-dpinow contributes a broader passive-observable surface: 34 protocol dissectors, Bronze v2 event families, and parser-adjacent anomaly streams fromstovetop,icmpeeker, andbilgepump- Purdue Model inference and cross-level communication checks are part of the core triage workflow
- Stage 4 remediation guidance is aligned to IEC 62443 SR requirements for the finding classes currently produced by the engine
- Deployed instances publish a built-in detection coverage catalog at
/capabilitiesthat is explicitly framed as what MarlinSpike can detect, not what it has already detected in a given environment - The
/capabilitiespage now groups current report finding classes,marlinspike-dpiparser coverage,marlinspike-malwareobservable and rule coverage, and the current ATT&CK mapping set behind filterable source, type, family, severity, and search controls - The current
marlinspike-malwaresection reflects the publishedmarlinspike-malware-rulescontent surface, now at 30 packs and 921 rules, and the ATT&CK section reflects the vendored full ATT&CK implementation shipped bymarlinspike-mitre
This is now positioned as a full ATT&CK implementation for MarlinSpike's report-facing workflow. It is still intentionally scoped to passive-traffic evidence and analyst triage rather than a broader compliance crosswalk or every possible ATT&CK analytic.
MarlinSpike turns raw packet captures into a workflow an OT operator, asset owner, or responder can actually use.
- Passive PCAP and PCAPNG analysis with OT-aware protocol dissection
- Relationship map and topology reconstruction with Purdue inference
- Report-driven triage with risk findings, C2 indicators, and asset context
- Detailed asset inventory, service exposure, conversation analysis, and MAC table reporting
- Ad hoc scan execution from the web UI
- Multi-capture handling, including large-PCAP processing with streaming progress
- Project-scoped organization for captures and reports
- Report history, retry support, and baseline-versus-drift review between report artifacts
- Portable JSON report artifacts that can be reviewed inside MarlinSpike or elsewhere
- Multi-user access with admin controls
- Scan history and audit trail
- System health and monitoring views
- Sample library management and optional local live-capture mode
The report workflow supports export directly from the UI:
- Print or save to PDF from the report viewer
- PNG export from the topology viewer
- CSV export from the asset inventory view
- Baseline and drift review with added, removed, changed, and unchanged topology comparison
- Live topology viewing during active scans
- Scan-stage progress streaming with ingest, analyze, classify, and report state visibility
- Per-user administration controls including password resets and upload limits
- Multi-report lifecycle actions including view, download, delete, and compare
- Retry of failed or interrupted scans from scan history
- Sample library administration with category management and PCAP upload/delete controls
- Capture filter input and ephemeral-port suppression controls in the scan workflow
- MAC table reporting alongside the main assessment view
Click any thumbnail for the full-size image.
These screenshots come from a live end-to-end smoke pass captured on March 28, 2026 against the current hosted deployment after running three preset PCAPs: Modbus.pcap, S7comm.pcap, and the 4SICS benchmark in fast mode. They show the core responder path from project -> scan -> report -> workbench -> assets.
The analyst workbench is now structured as a full operator shell instead of a single crowded viewer. A persistent left rail carries workbench identity, report context, mode navigation, and utilities, while the center stage and right-side inspector stay focused on active triage work.
The current shell supports Dashboard, Map, Findings, Evidence, Assets, Intel, Risk, and Reports surfaces without trying to cram every workflow into the topology canvas.
This screenshot comes from a live validated report artifact after the public marlinspike-dpi update and shows the denser operator shell now used by the viewer.
The operator shell uses a full-height navigation rail, compact status strip, single-row command bar, and persistent inspector so the first viewport stays focused on responder work. |
Additional screenshots show the mode-based workbench surfaces in detail.
The older live screenshots are still useful as protocol-specific validation examples:
The main environment variables are:
DB_PASSWORD: PostgreSQL passwordSECRET_KEY: Flask session secretADMIN_PASSWORD: initial admin passwordENABLE_LIVE_CAPTURE: set totrueto expose local interface capture in the UIPCAP_MAX_SIZE: maximum accepted upload size in bytesPCAP_PROCESS_SIZE: processing cap for auto-sliced uploads in bytes
The canonical application modules are:
_ms_engine.py_auth.py_models.py_config.pyapp.py
The non-underscored modules (auth.py, models.py, config.py) are compatibility shims so older tooling can still import them without drifting from the real source.
The public repository does not bundle third-party PCAP corpora. If you want a preset sample library, add captures under presets/<category>/ locally or through the admin UI after deployment.
python3 -m py_compile app.py _auth.py _config.py _models.py _ms_engine.pydocker compose up --build
See CONTRIBUTING.md for contribution guidelines, including ongoing fingerprinting and enrichment work.
MarlinSpike is the open-source core of Fathom, the commercial OT security platform from River Risk Partners.
The commercial Fathom platform adds distributed collectors, hierarchy, data diodes, forensic time-travel, and enterprise-scale baseline learning. MarlinSpike is the lightweight, open-core workbench you can spin up anywhere.
Learn more at riverriskpartners.com.
This repository is licensed under the GNU Affero General Public License v3.0. See LICENSE.
Questions? Contact me, river@riverman.io
