Universal anti-forensic dead-man gate for ESP32 security firmware Gate the boot · wipe on failure · fail safe by default.
Releases · Docs · Changelog · Cyber Controller · Discord
Successor to Suicide Marauder, the original ESP32 anti-forensic wipe system.
⚠️ Authorized, lawful use only. A security-research tool — use it only on devices you own or have explicit permission to test. It permanently destroys data by design. Provided as-is, no warranty; you assume all risk. See DISCLAIMER.md.
Latest release: v1.0.0 — cross-platform provisioner binaries
- a green release pipeline; the boot-gate firmware is complete and ships through Cyber Controller.
Honest scope: firmware is hardware-validated on classic ESP32 (CYD) only — S2/S3/C3/C6 validation is pending on
sacrificial hardware. The standalone firmware-build CI leg is a known-WIP best-effort job (fails at the link stage under
arduino-esp32 3.x, so it's continue-on-error and never blocks the repo — full diagnosis in
docs/CI-STATUS.md). It does what's documented; where it's unproven, it says so — not "stable/finished".
What's next: Tails-image host flashing (signature/checksum-verified, removable-target-only) · a fail-closed
"physical key" access gate · one canonical serial-command contract (docs/SPEC.md) · broader
board/firmware validation. Full version history → CHANGELOG.md.
A firmware-agnostic dead-man gate that sits between power-on and your security firmware. If the operator cannot authenticate — or the hardware kill line is cut — the device obliterates its own flash, SD card, and (optionally) its boot chain before anything can be recovered.
Dead Man's Switch is not tied to any single firmware. The Guardian variant works with any ESP32-based firmware — Marauder, GhostESP, Bruce, HaleHound, Meshtastic, or anything else. The Fork variant integrates directly into ESP32 Marauder for tighter coupling (and fits all flash sizes, including 4 MB).
This is a DEFENSIVE, owner-only tool — the same category as Kali's LUKS Nuke, GrapheneOS's duress PIN, and BusKill. It is for protecting hardware you own, not for evading lawful process. Read
docs/SAFETY.mdanddocs/THREAT-MODEL.mdbefore flashing or arming anything.
The gate runs once, early in boot, before the host firmware's UI loads. Its behavior is fail-safe by design:
- Unprovisioned → can never wipe. A board with no
guardcfgconfig behaves like plain firmware. Destruction is physically impossible. - Master-disarmed (default) → can never wipe. The
armedflag defaults to0. Destruct is impossible unless explicitly armed. - Correct password always boots and never wipes, regardless of switch state (after the dead-man pre-check).
- Wrong password ×N → wipe. A power-cycle-safe attempt counter is persisted before responding, so a mid-attempt reset cannot reset it. The default threshold is 2.
- Dead-man line cut → wipe (when armed). A hardware arming GPIO must read the "armed" level. Cut, unplug, or tamper with the wire and the board wipes.
The full state machine, NVS schema, and invariants are defined in docs/SPEC.md — the canonical contract that firmware, host tooling, and partition tables all conform to.
- ROM SPI bypass brick — bypasses the IDF flash protection layer via the ESP32's ROM SPI driver to erase the running application from within itself. Hardware-validated on classic ESP32 (CYD 2432S028).
- Overwrite-then-erase + verify — forensic-grade wipe of internal partitions: random overwrite, then erase, then raw-read verification (
esp_flash_read) that every byte is0xFF— so an erased sector verifies correctly even under Flash Encryption (T2). - SD full-LBA raw wipe — raw sector-level erasure of the entire SD card (LBA 0 through last sector) via the SDMMC host driver, bypassing the filesystem. Multi-pass support with secure-erase patterns; file-level overwrite fallback when raw access is unavailable.
- Guardian dead-man gate — standalone, firmware-agnostic factory partition that gates boot, then jumps to an unmodified firmware in OTA. Works with any ESP32-based firmware, not just Marauder.
- Password parity validation — PBKDF2-HMAC-SHA256 password challenge at boot, constant-time compared. Plaintext is never stored, never logged, never transmitted. Host-side provisioning only.
- 2-fail wipe — power-cycle-safe attempt counter persisted before responding. Two wrong passwords and everything wipes. Fails closed: if the counter cannot persist, the gate never degrades to unlimited guesses.
- GPIO dead-man switch — hardware arming line tied to a GPIO pin. Cut the wire, unplug, or tamper — the board wipes. Host tooling rejects non-fail-safe pull/level combinations.
- Brownout hardening — hardware brownout detection, ADC voltage monitoring, brownout event logging to NVS, and fast-wipe prioritization. A low-voltage boot suppresses destruction but still requires the correct password — no free gate skip.
- Fast wipe mode — skip the SD wipe and go straight to flash erase + boot brick in seconds. Designed for battery-powered or brownout-prone deployments.
- Dashboard hooks — serial command interface for remote management by Cyber Controller or any host tool.
SM_STATUSandSM_INFOare read-only queries;SM_WIPEroutes into the password-authenticated wipe flow.SM_ARM/SM_DISARM/SM_SET_PASSWORDare recognized but reply that they require re-provisioning from the host — thearmedflag and password hash live in theguardcfgNVS image and are not modifiable at runtime. There is noSM_FW_VERSIONcommand; the firmware version is a field inside theSM_INFOresponse. Seedocs/SPEC.md§6.1 for the canonical command table. - Multiple input backends — serial (default, headless), on-screen touch keypad, M5StickC buttons, M5Cardputer QWERTY, and Marauder Mini joystick gate-input drivers.
| Board | Status | Notes |
|---|---|---|
| ESP32 classic (Gold, CYD, DevKit) | Hardware-validated | ROM SPI bypass confirmed. Full wipe + brick verified on a blank classic ESP32 and on CYD 2432S028. |
The Guardian standalone gate was hardware-validated on a blank classic ESP32 — a wrong-password trigger over serial obliterated the entire flash (bootloader, partition table, app, and config all read back as 0xFF). See docs/HARDWARE-TEST.md.
Full matrix → docs/FIRMWARE-SUPPORT.md (every Cyber Controller firmware
profile mapped to its gate-support status, honest about shipped vs. unvalidated vs. out-of-scope).
Quick version:
| Status | |
|---|---|
| Shipped + hardware-validated | Marauder FORK on classic ESP32 (CYD 2432S028 + blank dev board: wrong-password ×2 wiped flash to 0xFF). |
| Provisionable, not yet HW-validated | ESP32-S2 / S3 / C3 / C5 / C6 (the stage-3 self-brick falls back to esp_flash off classic ESP32). C5 is host-provisionable now (0x2000 bootloader); its firmware build waits on the upstream Marauder C5 port. |
| Architecturally supported (GUARDIAN), not yet wired | Any ESP32 firmware in ota_0 — GhostESP, Bruce, HaleHound, Meshtastic, ESP32-DIV, … (needs 8 MB+). |
| Out of scope (not an ESP32 boot-gate problem) | Non-ESP32 targets: RTL8720/BW16 (Realtek AmebaD), Flipper Zero (STM32), Raspberry Pi SD images, Orbic/ADB. |
The Guardian variant is firmware-agnostic — it gates boot at the factory partition and jumps to whatever
firmware lives in ota_0, so adding a new ESP32 firmware needs no source changes (see the matrix doc §4).
The Fork variant integrates directly into ESP32 Marauder for tighter coupling and fits 4 MB. Adding a new
chip means adding its ROM-SPI entry points + partition offsets; adding a non-ESP32 platform means a
separate, platform-native mechanism, not a port of this gate.
The gate is compiled into a fork of ESP32Marauder and called early from setup(), reusing Marauder's own display/keyboard/SD drivers so the password prompt works on every hardware class with almost no new UI code. Self-destruct erases every other partition, the SD, and finally its own boot chain.
A separate tiny factory app gates boot, then sets the boot partition and restarts into an unmodified firmware in ota_0. This gives a cleaner GPL boundary and a cleaner brick (the gate is not erasing its own running region until the very end, and can re-assert via factory fallback). It does not fit in 4 MB — 8 MB minimum, 16 MB preferred.
No Secure Boot / Flash Encryption. The board is data-wiped but reflashable. Good for dev/demo and most threat models.
Secure Boot v2 + Flash Encryption release mode + brick=1. The gate cannot be reflashed past and the erased ciphertext is meaningless. eFuse burns are permanent.
Every build script and CI job defaults to SUICIDE_SAFE_MODE=1. In SAFE_MODE the entire detect → arm → trigger → erase chain runs against a dedicated scratch partition with a dummy key and only logs the simulated destruction — it never touches a live partition. If a SAFE_MODE build's partition table has no scratch partition, the firmware refuses to simulate (it logs an error and performs zero erases).
A real destruct chain requires explicitly passing --no-safe-mode, and a live-brick build requires --allow-live-brick on top of that. CI never produces a live-brick build — the Stage-3 self-erase-of-the-running-app primitive is the one UNVERIFIED capability and is only ever exercised by hand on a sacrificial board (see docs/SPIKE-PLAN.md).
- Read the safety docs first —
docs/SAFETY.md,docs/THREAT-MODEL.md. - Understand the contract —
docs/SPEC.mdis the single source of truth for names, NVS keys, offsets, build flags, and the state machine. - Build in SAFE MODE —
scripts/build.ps1(Windows) orscripts/build.sh(Linux/macOS), which default toSUICIDE_SAFE_MODE=1:Options:./scripts/build.sh --board esp32 --variant fork --tier T1
--board {esp32|esp32s2|esp32s3|esp32c3|esp32c6},--variant {fork|guardian},--tier {T1|T2},--input {serial|touch|mini_kb|cardputer|buttons},--backend {arduino-cli|pio}. - Provision a device —
host/provision.py(password via stdin/getpass, never argv) produces aguardcfg.binNVS image, abundle.jsonflash manifest, and (Guardian only) a blankotadata.bin. - Flash — either via CI bundle artifacts, or through Cyber Controller, the host that carries the provisioned bundle to the board.
The host provisioner needs only the Python 3.9+ standard library for everything security-relevant; its one external dependency is the NVS partition image generator (esp-idf-nvs-partition-gen, pinned in host/requirements.txt).
Dead Man's Switch is built to be vendored into Cyber Controller as a git submodule — Cyber Controller imports host/provision.py directly. Through it you get:
- Remote status monitoring via the serial dashboard (arm/disarm is applied by re-provisioning, not a runtime toggle).
- Host-side password provisioning (plaintext never touches the device).
- One-click flash of Dead Man's Switch builds to connected boards.
The plain-Marauder flash path stays unchanged, and every duress control is behind an opt-in that is off by default. See flasher-integration/PLAN.md for the shipped integration contract.
| Project | What it is |
|---|---|
| Cyber Controller | The flagship flash-and-control app. Vendors this repo as a submodule and does the host-side provisioning + one-click flash. Site: cybercontroller.org. |
| Headless Marauder GUI | Standalone Marauder controller + multi-firmware flasher. A sibling project — it stays standalone, with no dead-man coupling. |
| Suicide Marauder | The predecessor this project grew out of. Superseded here; kept for lineage. |
Found a way past the gate, or a way to pull the password? Email lxveace@proton.me — please don't open a public issue for anything security-sensitive. The reporting process, scope (gate bypass, password extraction, incomplete wipe), and what's explicitly out of scope are in SECURITY.md.
Design posture in one line: unprovisioned or disarmed boards can never wipe, plaintext passwords are hashed host-side and never stored or transmitted, and the attempt counter fails closed. The threat model is spelled out in docs/THREAT-MODEL.md.
Host-side tests are plain pytest:
cd host
pip install -r requirements.txt
pytestThey cover the provisioner — argv-safety (passwords never on a command line), fail-closed provisioning, and per-chip bootloader-offset resolution. Firmware changes have to keep the docs/SPEC.md contract intact; it's the source of truth every layer conforms to. Details in CONTRIBUTING.md.
deadmans-switch/
├── README.md <- you are here
├── CHANGELOG.md / SECURITY.md / CONTRIBUTING.md / DISCLAIMER.md / LICENSE
├── .github/workflows/ <- CI matrix -> per-board SAFE_MODE bundles
├── docs/
│ ├── SPEC.md <- canonical interface contract (source of truth)
│ ├── SAFETY.md <- read before flashing / arming / testing
│ ├── THREAT-MODEL.md
│ ├── FIRMWARE-SUPPORT.md <- gate-support matrix (per firmware/chip)
│ ├── ARCHITECTURE.md
│ ├── HARDWARE.md <- wiring guides
│ ├── PROVISIONING.md
│ ├── RESEARCH-DIGEST.md
│ ├── SPIKE-PLAN.md <- sacrificial-board plan for the UNVERIFIED brick
│ ├── HARDWARE-TEST.md <- validation log (classic ESP32)
│ ├── CI-STATUS.md <- firmware-build CI diagnosis
│ └── LICENSING.md <- GPL/LGPL distribution notes
├── firmware/
│ ├── bootgate/ <- gate headers + impl + input drivers
│ ├── guardian/ <- standalone firmware-agnostic gate
│ ├── integration/ <- Marauder fork hook point
│ ├── partitions/ <- 4 MB / 8 MB / 16 MB / Guardian partition CSVs
│ └── test_harness/ <- SAFE_MODE bench
├── host/
│ ├── provision.py <- builds guardcfg.bin + bundle.json
│ └── tests/ <- pytest suite for the provisioner
├── scripts/
│ ├── build.ps1 / build.sh <- parameterized build (board/variant/tier/input)
│ └── build_test_harness.{ps1,sh}
└── flasher-integration/
└── PLAN.md <- shipped Cyber Controller integration contract
Built on ESP32Marauder by justcallmekoko — the display/keyboard/SD drivers and the entire base firmware are theirs. This project is an additive, owner-only defensive layer on top of that work. Nothing upstream is vendored into this repo; the Fork variant is applied against a pinned ESP32Marauder checkout.
Originally developed as Suicide Marauder — the first ESP32 anti-forensic wipe system with boot password gating, automatic wipe on failed attempts, and a hardware dead-man switch. Dead Man's Switch is the universal successor with expanded board and firmware support.
Released under the MIT License. ESP32Marauder is MIT; distribution notes for the LGPL components statically linked in (e.g. ESPAsyncWebServer) are tracked in docs/LICENSING.md — read it before redistributing any binaries.
Discord: discord.gg/lxvelabs · GitHub: @LxveAce · Email: LxveLabs@proton.me (business) · lxveace@proton.me (direct) · Sites: lxvelabs.com · cybercontroller.org
Built by LxveAce · a LxveLabs project
Hardware supported by PCBWay — LxveLabs is developing a board in collaboration with PCBWay.