Skip to content

Cyber hunt // DCO attack reconstruction // Terrain mapping

What the adversary did, where, and in what order.

Midden is a shared case for hunt teams. Record each step of an intrusion with the evidence attached, map the terrain from nmap scans, and hand the whole thing to the next shift as a live case.

Run it
$ docker run -d --name midden \
    -p 8080:8080 \
    -v "$PWD/midden-data:/data" \
    -e MIDDEN_SECRET="$(openssl rand -base64 32)" \
    -e MIDDEN_ADMIN_USER=admin \
    -e MIDDEN_ADMIN_PASSWORD='choose something long' \
    ghcr.io/jacstrong/midden:latest

Then open localhost:8080 and sign in as admin. Deployment guide →

MIDDENOP NIGHTJARIR-2026-0412
Illustrative case. One lane per host, a branch at every pivot.

Two ways to run it

The same interface in both. Case files move freely between them.

HostedDocker
  • One container with the database, file store and web client inside.
  • About twenty analysts on one case at once, each seeing the others’ changes as they happen.
  • Runs on a laptop or a Raspberry Pi 4/5. Images for amd64 and arm64.
StandaloneSingle .html
  • One file. No server, no storage, no network calls.
  • Open it from disk, work, save a .json, reopen it later.
  • Parses nmap scans in the page.

What it does

Timeline + branch graph

One lane per host, ordered by when the adversary first reached it, with a branch wherever activity pivoted. Read every event in UTC, your local time, or the source system’s own timezone.

Hosts, indicators, ATT&CK

Indicators are deduplicated across the case with every sighting kept. Techniques roll up into the Enterprise matrix.

Terrain from nmap

Upload -oX or -oN output for a searchable inventory and a network map: a hub per subnet, case hosts overlaid by status. Promote a scanned host in one click.

Scan builder

Composes nmap commands for the two-phase workflow: find live hosts, then service-scan exactly those. Every command it can produce is checked against real nmap in CI.

Evidence

Screenshots, log excerpts and small captures attach to events and hosts. Content-addressed, and only recognised image formats ever render inline.

Reports

HTML, Markdown, a timeline CSV and an indicator list, assembled from the case.

History

Every change is an operation with an actor and a time. See before and after, and revert anything.

How it holds together

Operation log
Every change is recorded with who made it and when. Live collaboration, the history view and revert are one mechanism, not three.
Per-field last write wins
Editors send only the fields that changed, so two analysts on the same host both keep their work. On a real collision the loser is told who overwrote what.
Terrain beside the log
A /16 scan is 65,000 hosts. Scans are bulk-loaded and paged; case status is overlaid by address, so recolouring the map needs no round trip.
Zero native modules
SQLite and argon2id come from Node itself. The arm64 image is the same JavaScript as amd64.
One volume
/data holds the database and every file. Copy it and you have copied the installation.
Self-hosted. Open source.Apache-2.0. Your cases stay on your own hardware.

Released under the Apache License 2.0.