A security auditing tool for MAVLink-based drones (ArduPilot / PX4). It connects to a live drone or an ArduPilot SITL simulator runs a battery of automated security checks, and produces a timestamped audit report in both JSON and human-readable text.
I had already built a drone threat detection system which is something that watches telemetry and flags attacks as they happen. That answered "can I catch an attack in progress?" This project answers the other half: "can I find the weaknesses before an attacker does?" Detection is defense; auditing is the offensive-minded counterpart. I wanted to understand both sides, because that is how real security teams actually work.
The auditor connects over MAVLink and runs two modes.
Full audit (python -m fuzzer.packet_fuzzer) runs 16 passive and active checks:
- Firmware recon & CVE lookup — reads the drone's reported firmware version
(
AUTOPILOT_VERSION) directly off the link and cross-references it against a local database of known ArduPilot CVEs. - Link encryption & authentication — checks whether the transport is encrypted and whether MAVLink messages are signed (authenticated).
- Geofence configuration audit — reads the live
FENCE_*parameters to report whether a fence is enabled, what the breach action is, and the altitude/radius limits. - Malformed-packet fuzzing — sends out-of-spec
HEARTBEAT,PARAM_SET, andCOMMAND_LONGmessages (invalid enums, extreme parameter values, commands that should be refused) and verifies the drone stays responsive after each. - Flood stress test — blasts thousands of packets per second to test resilience under sustained load.
- Severity-graded reporting — collects every result, grades findings, and writes a JSON report plus a human-readable text report.
Live geofence breach test (python -m fuzzer.packet_fuzzer breach) goes further and
it actually flies the simulated drone to verify the firmware enforces a safety boundary:
it configures a low altitude fence, arms the drone, commands a takeoff that climbs past
the fence ceiling, and watches whether the firmware reacts. In testing against SITL the
drone correctly tripped the fence at the boundary and auto-switched to RTL (Return To
Launch) a real demonstration of a safety control working under a deliberate breach.
Run against ArduCopter SITL (ArduPilot 4.8.0):
SUMMARY
Total checks run: 16
Passed: 13
Findings: 3 (MEDIUM:3)
[PASS] FIRMWARE v4.8.0: no matching core-firmware CVEs in local DB
[MEDIUM] ENCRYPTION transport is plaintext TCP (no link-layer encryption)
[MEDIUM] ENCRYPTION MAVLink messages are unsigned (no authentication)
[MEDIUM] GEOFENCE geofence is DISABLED (FENCE_ENABLE=0)
[PASS] GEOFENCE breach action set (FENCE_ACTION=1)
[PASS] GEOFENCE limits: alt_max=100m, radius=150m
[PASS] HEARTBEAT (4 malformed-field tests)
[PASS] PARAM_SET (3 extreme-value tests)
[PASS] COMMAND (2 unauthorized-command tests)
[PASS] FLOOD 2000 packets in 0.02s (~82,000 pkt/s)
And the live breach test:
Commanding takeoff to 40m (past the 20m fence)...
>> mode changed to RTL
fence ENFORCED on altitude breach (RTL/Land triggered)
A few things worth being straight about, because they matter for interpreting any security tool:
- The fuzzing passed everything, and that's expected. ArduPilot is mature, widely-reviewed software with real input validation. It's supposed to clamp out-of-range parameters and ignore garbage enums. "No crash under malformed input" is a legitimate, reportable result and not a failure of the test.
- ArduPilot has very few formally-assigned CVEs. The one in the local database (CVE-2022-28711) is in the separate APWeb web-server component, not core flight firmware. That scarcity is itself a sign of a hardened codebase.
- The findings are real but context-dependent. Plaintext, unsigned MAVLink and a disabled fence are defaults on a local SITL test rig and are fine there. Over an actual radio link, unencrypted/unsigned MAVLink is a genuine risk (telemetry interception, command injection), and a disabled geofence removes a safety boundary. The tool reports it; the operator decides if it matters for their deployment.
conda create -n drone-security python=3.14 -y
conda activate drone-security
pip install pymavlinkTwo terminals. In the first, start the simulator:
"<path>/Mission Planner/sitl/ArduCopter.exe" -M quadWait for Waiting for connection ...., then in the second terminal:
conda activate drone-security
python -m fuzzer.packet_fuzzer # full 16-check audit
python -m fuzzer.packet_fuzzer breach # live geofence breach flight testReports save as audit_report_<timestamp>.json and .txt.
Note: the live breach test arms and flies the sim drone, so it waits for GPS lock and for the EKF to settle before arming (~30–40s). It uses
ARMING_CHECK=0, a standard SITL test-rig shortcut, which you would never use on real hardware.
Listed honestly — planned, not yet built:
- Live CVE lookup — query the NVD API at runtime instead of a local list.
- PX4 support — currently tested against ArduPilot only.
- Horizontal geofence breach — current live test breaches the altitude ceiling; a circular/polygon breach would need autonomous horizontal navigation.
- Replay / packet-capture mode — feed recorded MAVLink traffic instead of a live link.
- MAVLink internals: heartbeats, the parameter protocol, command messages, requesting
data streams, and reading
AUTOPILOT_VERSIONoff a link. - Flight-control basics: GUIDED mode, the arm/EKF-settle sequence, takeoff commands, and how a geofence breach triggers an automatic failsafe.
- That a "clean" security result is still a result — you report what you find, including "nothing," and resist the urge to manufacture a scarier conclusion.
- Severity and context matter more than raw pass/fail. The same finding (unsigned MAVLink, disabled fence) is a non-issue on a test bench and a real risk on a flying aircraft.
For educational use and authorized testing only and against simulators or drones you own and control. Do not point this at hardware or systems you do not have permission to test.