What Is MAVLink? MAVLink 2 Message Signing in PX4 and ArduPilot
MAVLink is the protocol drones and ground stations use to talk. How a MAVLink 2 frame is built, how message signing works, and why PX4 ships with it off.
MAVLink is a lightweight messaging protocol that drones, ground control stations and companion computers use to talk to each other. PX4 and ArduPilot, the two main open-source flight stacks, both speak it. Telemetry, commands, mission uploads and parameter changes all travel as MAVLink messages. This post covers what a frame looks like and what message signing does.
What a MAVLink 2 frame looks like
A MAVLink 2 frame starts with the magic byte 0xFD, followed by:
- payload length,
- incompatibility flags and compatibility flags,
- a sequence number,
- the sender's system ID and component ID,
- a 3-byte message ID,
- the payload,
- a 2-byte checksum,
- optionally, a 13-byte signature.
Every message has a numeric ID (HEARTBEAT is 0) and defined fields. The system ID and component ID say who sent it, but nothing in an unsigned frame proves that. Any device on the link can write any ID.
How message signing works
Signing is MAVLink 2's authentication feature. The sender sets the signed flag (0x01) in the incompatibility flags and appends 13 bytes:
- a link ID,
- a 48-bit timestamp,
- a 48-bit signature, the truncated SHA-256 of the packet, the timestamp, the link ID and a 32-byte secret key.
The receiver recomputes the signature with its copy of the key. The timestamp must increase on each stream (system ID, component ID and link ID), and frames more than a minute behind are rejected, which blocks simple replay.
What signing doesn't do
- It doesn't encrypt. Messages are still readable on the wire.
- It proves key possession, not identity. Everyone who holds the shared key looks the same.
- Rotation is manual, and a lost key may mean removing the SD card or reflashing.
- Some message types stay open. PX4's documentation says HEARTBEAT, RADIO_STATUS, ADSB_VEHICLE and COLLISION stay spoofable even with signing on.
Defaults differ by flight stack
On PX4, signing is off by default. The key and timestamp live in a file on the SD card, and once a key exists, signing applies on every link, USB included. Provisioning and key changes use the SETUP_SIGNING message, which PX4 rejects while the vehicle is armed.
ArduPilot protects only the serial ports set to MAVLink 2, so a port left on MAVLink 1 is unprotected, and its key is sent in plaintext during setup, so it should be provisioned over a secure link.
The Remote ID connection
MAVLink also carries Remote ID data to a transmitter module, using OPEN_DRONE_ID_* messages. The MAVLink documentation says the Remote ID component should report readiness through OPEN_DRONE_ID_ARM_STATUS, and the flight stack should refuse to arm until it does. See What Is Remote ID? for the broadcast side.
Checking whether a link is signed
You can tell whether a captured link is signed without the key: look at the incompatibility flag on each frame and the extra 13 bytes. Verifying that a signature is valid needs the key, and whether a vehicle actually rejects unsigned frames depends on its configuration, not on the capture. Those are the two things a capture alone can't answer.
Follow Trango Compute on LinkedIn
We post updates on new tools, context engineering patterns, and LLM cost research.