Open-source project
lukeswitz/AntiHunter avatar
lukeswitz/AntiHunter

AntiHunter: an ESP32 node that listens for the things hunting you

AntiHunter Perimeter Defense Systems - DIGI Node Firmware

713 stars96 forksC++AGPL-3.0

At a glance

What is it?
AntiHunter is firmware for an ESP32 based detection node that watches the wireless environment for watchlist targets, new devices, drones and tampering, logging everything to SD card with no cloud in the loop. Nodes can share alerts over a Meshtastic LoRa mesh, and a companion Command Center project drives the fleet.
Who is it for?
AntiHunter suits a user who wants to know what is transmitting near a home, a fence line or an event, with hardware you own and logs that never leave the SD card. It does not suit someone who needs reliable identification rather than detection, since a MAC address or an SSID is a signal of presence and not proof of intent, and it does not suit a jurisdiction where scanning the radio spectrum is not permitted.
Can I use it commercially?
Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
Is it still maintained?
Yes. The repository last received commits 5 days ago.
What is it written in?
Mainly C++, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

It inverts the assumption that the defender is the one transmitting

AntiHunter is described as a wireless and physical tripwire for your perimeter, with no subscription and no cloud, and the data staying with you.

The framing sentence is the useful part. AntiHunter turns the hunt around: drones, phones and attack tools give themselves away by transmitting, and AntiHunter listens. The detection model is passive radio observation rather than active probing.

What it flags, according to the description, is watchlist targets, new devices, drones, wireless attacks and tampering. When something is flagged, it alerts, collects evidence, and can erase itself. The self-erasure is not a metaphor; there is a secure data destruction feature with an erase key that must be set before the wipe function is enabled at all.

The deployment story is deliberately low friction. It runs at home, on a fence line, at an event, or off-grid on battery. No internet is needed and everything logs to SD. One node works alone, and adding more means they share alerts and can pinpoint a device together, which the documentation marks as experimental.

The project is firmware for a node rather than a standalone application, and the README calls it the DIGI Detection Node Firmware, with the primary language recorded as C++. The control plane is a separate repository, the AntiHunter Command Center, and the project is licensed under AGPL-3.0. The last push was on 2026-10-18 and the current release is v1.0.4 from 2026-10-04.

Four detection modes, each started with a one line command

The detection table is where the project's real scope becomes clear, and each feature maps to a command that can be sent over the mesh rather than through the web UI.

Target scan alerts when the node hears a MAC address, a vendor prefix or an SSID that is on the watchlist. The command is a short string with a type and a duration.

code
SCAN_START:2:300

Baseline anomaly detection is the more interesting one. It learns which devices are normally present, then reports the ones that are new, the ones that have gone, the ones that have returned, and the ones whose properties have changed. That is a different question from watchlisting. You do not have to know in advance what to look for; the node builds a picture of the ordinary and tells you about the deviation.

code
BASELINE_START:300

Device discovery is the reconnaissance mode. It lists nearby access points and BLE devices with RSSI, channel and name.

code
DEVICE_SCAN_START:2:300

The fourth listed mode is a probe request scanner, and the table row for it is cut off in the visible documentation, so the command and its output fields are not something this page can state.

The command format itself is worth noting. It is a colon-separated verb, a type selector and a duration in seconds, sent as plain text over the mesh. That means a node can be driven by the Command Center, by a phone on the same Meshtastic channel, or by hand from a serial monitor, without a protocol, a session or a login.

The tradeoff is that the format is terse and undocumented beyond the table, and a malformed command has no obvious error path in the visible documentation.

Full and headless are two different products sharing a codebase

The node comes in two variants and the difference is larger than it first appears.

The Full variant has a web interface. You join its Wi-Fi access point, which by default is the network named Antihunter with the published password antihunt3r123, and open http://192.168.4.1, logging in as admin with the Wi-Fi password. There is a System and Wi-Fi Access Point settings area where you can set a separate web password or turn the login off entirely.

The Headless variant has no access point at all. You open a serial monitor at 115200 baud and drive it from there. The documentation recommends Headless for covert work, and to go further you can turn off the radio's screen, LED and Bluetooth with the radio plugged in on its own USB.

code
python3 scripts/meshtastic_config.py --screen off --led off --ble off

That is a meaningful design decision rather than a stripped-down build. A node with a visible Wi-Fi network announces itself; removing the access point, the screen, the LED and Bluetooth removes the radio emissions and the physical indicators that would make a detector detectable. The web interface on the Full variant is convenient and also the most conspicuous part of the device.

The two variants are separate source trees in the repository, Antihunter/full/src and Antihunter/headless/src, and the Makefile builds them separately with PlatformIO environments named AntiHunter-full and AntiHunter-headless.

bash
pio run -e AntiHunter-full

They also share the exclusion list in the lint configuration, which is a detail worth noticing: the wifi.c and opendroneid.c files are excluded from static analysis in both variants. Those two files are where the Wi-Fi and Open Drone ID handling lives, and the exclusions mean the most protocol-heavy code in the project is the part cppcheck does not examine.

Every unit ships with the same published credentials, which is the first thing to change

The lock-down section of the quick start is the most useful part of the documentation, because it names a specific failure mode rather than gesturing at security.

Every unit ships with the same published defaults, so anyone can join an unchanged node. The fix is to change the access point name and password under RF Settings, and to set the node ID in the web UI or with CONFIG_NODEID over the mesh. The radio needs its region set and a new BLE pairing pin, and the instructions give the command.

code
python3 scripts/meshtastic_config.py --region US --pin 481920

The example values are placeholders, and the documentation is explicit that you should use your own region and your own six digit pin. The BLE pairing pin is the credential that pairs a phone to the radio, so a device left on the factory pin is a device whose radio channel anyone nearby can join.

The mesh side has a parallel instruction: in the Meshtastic app, under Channels, make your own encrypted channel primary and turn the public channel off. Combined with the region setting, that is what keeps the alerts on a channel that is not a shared public one.

Then there is the erase key. Wipe is off until you set one, and the documentation points to the secure data destruction section for the detail. The feature is a tripwire, and the tripwire includes the evidence and the device itself, so being able to wipe what you have collected is part of the design rather than a bolt-on.

One caution about Privacy Mode is buried in the middle of the quick start and is easy to skim past. It hides MACs, SSIDs and GPS in the web UI only. Exported logs and SD files still contain them, and GPS coordinates identify places. The documentation says to check files before posting them, which is the right advice given that the whole point of the tool is to avoid handing over a map of where you live.

Cppcheck and PlatformIO are the build and quality story

The build is PlatformIO with a platformio.ini at the root, and the firmware is compiled as C++17.

The Makefile is the interesting part, because it shows the quality gate the project has chosen. Static analysis is cppcheck with a wide set of checks enabled: warning, style, performance, portability and unusedFunction, at check-level exhaustive, with inline suppressions allowed and an error exit code of 1.

make
CPPCHECK := cppcheck
CPPCHECK_FLAGS := --enable=warning,style,performance,portability,unusedFunction --std=c++17 \
	--check-level=exhaustive \
	--suppress=useStlAlgorithm \
	--inline-suppr \
	-DPROGMEM= \
	-DAH_GIT_SHA=\"dev\" \
	-DAH_BUILD_EPOCH=0 \
	--error-exitcode=1

The lint target runs both variants, and the exclusion list is applied to each: wifi.c and opendroneid.c are skipped, along with a pair of suppressed headers.

There is also a host-side unit test that does not need hardware. It compiles a single source file with the C++17 standard and runs it.

bash
c++ -std=c++17 -O1 -I$(FULL_SRC) scripts/test_ble_class.cpp $(FULL_SRC)/ble_class.cpp -o /tmp/test_ble_class
/tmp/test_ble_class

That is the BLE class, compiled and run on the build machine, which is the part of the codebase most likely to have logic bugs that a device-based test would not catch anyway.

The CI badges match this. There is a lint workflow, a PlatformIO workflow, and CodeQL for code scanning, and a size badge that tracks the code size in bytes for the Antihunter directory, which is a reasonable proxy for the flash budget of an ESP32-S3.

The repository also carries CLA.md, CONTRIBUTING.md, SECURITY.md, PATENTS.md and NOTICE at the root, alongside a hw/ directory with the Prototype_STL_Files including the assembly manual PDF, a Dist/ directory, a scripts/ directory and a docs/ directory holding the Operator's Guide.

Where AntiHunter is the wrong tool

The first wrong-tool case is a use case that needs identification rather than detection. The node reports a MAC address, a vendor prefix, an SSID, an RSSI value and a channel. That tells you something is present and roughly what it is. It does not tell you what the device is doing, who is carrying it, or whether it is a threat. Anyone with a phone in the same room produces similar emissions, and the documentation is careful about the difference between passive reception and interception, which is one reason the legal section matters.

The second case is a jurisdiction where radio scanning is restricted. The documentation says the rules differ by country and to scan only where you have authority. That sentence is the binding constraint on where this can be deployed, and a fence line or an event in a public space is exactly the situation where the legal question is least comfortable.

The third case is a deployment that needs a fleet-scale control plane. The Command Center is a separate repository, and the multi-node features, where nodes share alerts and can pinpoint a device together, are explicitly marked experimental. For a single node the project is self-contained; for twenty nodes, you are depending on a companion project and on a mesh that has to work over LoRa range.

There is also a question of what the node does about what it finds. It alerts, it logs, and it can wipe itself. It does not act. If your requirement is to respond to a detected device rather than to know about it, that response mechanism is not in this firmware.

On licensing, the project is AGPL-3.0, which is the term to look at hardest for hardware-adjacent work. The copyleft obligation of AGPL reaches a network interaction, and a node that a user flashes onto their own device is a distribution of a modified work if they change the firmware, which means the source of their modification has to be offered. For a personal deployment that is not a problem. For an organisation planning to ship a modified version of the firmware to customers, it is a decision that needs a lawyer rather than a README.

The repository also carries PATENTS.md and NOTICE files, which suggests the project takes the IP question seriously, and the hardware is sold commercially through a Lectronz store while the firmware stays open, which is a licensing arrangement worth understanding before you build a product on top of it.

Editorial conclusion

AntiHunter suits a user who wants to know what is transmitting near a home, a fence line or an event, with hardware you own and logs that never leave the SD card. It does not suit someone who needs reliable identification rather than detection, since a MAC address or an SSID is a signal of presence and not proof of intent, and it does not suit a jurisdiction where scanning the radio spectrum is not permitted. Before deploying, change the published default access point credentials, set your own LoRa region and BLE pairing pin, set an erase key so the wipe function is available, and read the legal disclaimer in the documentation, because passive reception and interception are treated differently in different countries.

Frequently asked questions

What is AntiHunter?

AntiHunter is firmware for a DIGI detection node, an ESP32 based wireless and physical tripwire for a perimeter. It flags watchlist targets, new devices, drones, wireless attacks and tampering, logs to SD card with no cloud service, and can share alerts with other nodes over a Meshtastic mesh.

How do I flash an AntiHunter node?

Attach all three antennas before powering on, then open the Web Flasher in Chrome or Edge on a desktop, pick Full or Headless and Stable or Beta, plug in the ESP32-S3 and select Connect and Flash. The flasher asks whether to erase the device first, which clears saved settings.

What are the default credentials for an AntiHunter node?

Every unit ships with the same published defaults. The Full variant's access point is the Antihunter network with password antihunt3r123, and you log in as admin with the Wi-Fi password at http://192.168.4.1. The documentation says to change the AP name and password under RF Settings before deploying.

What does Privacy Mode hide in AntiHunter?

Privacy Mode hides MACs, SSIDs and GPS in the web UI only. Exported logs and SD files still contain them, and GPS coordinates identify places, so the documentation advises checking files before posting them.

What license is AntiHunter released under?

The project is licensed under AGPL-3.0, with the LICENSE file at the root of the repository. The firmware is built with PlatformIO for two environments, AntiHunter-full and AntiHunter-headless, and is statically analysed with cppcheck.

Official sources

  1. License: AGPL-3.0
  2. lukeswitz/AntiHunter on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/lukeswitz-antihunter.svg)](https://hysenlabs.com/projects/lukeswitz-antihunter)

Was this useful?