The key never touches the agent’s disk. In the browser it is stored as raw bytes in IndexedDB, because the signature is a SHA-256 hash over the key itself and Web Crypto cannot compute that from a non-extractable key. Any script running on the Mission Control page can read it.
How it works
- Mission Control generates 32 random bytes using
crypto.getRandomValues. - Mission Control POSTs the key as hex to
/api/mavlink/signing/enroll-fcover the agent’s LAN API. That API is plain HTTP authenticated by the pairing key, so the key crosses the network in clear; enroll over a link you trust, or over USB or loopback. - The agent sends a
SETUP_SIGNINGmessage to the flight controller twice, 200 ms apart, then zeroizes the raw key buffer. - Mission Control stores a copy of the raw bytes in IndexedDB keyed by drone id, and zeroizes its own buffer.
- Every outgoing MAVLink v2 frame to this drone is signed: the signed bit is set in
incompat_flags, the CRC is recomputed, and a 13-byte tail is appended with a 1-byte link id, a 6-byte timestamp (10 µs units since 2015-01-01), and the first 6 bytes of SHA-256(key ‖ frame from the start byte through the CRC ‖ link id ‖ timestamp). - The agent passes signed frames to the flight controller unchanged.
- The flight controller validates each frame and silently drops unsigned or invalid ones, except unsigned frames arriving on its USB port.
Enabling signing
1
Open the signing panel
In Mission Control, select your drone, open the Setup tab, and pick MAVLink Signing under Security.
2
Check capability
The panel asks the agent which autopilot the flight controller reports in its heartbeat. ArduPilot is supported. If the panel shows “not available”, see Firmware support.
3
Click Enable signing
The browser generates a fresh 32-byte key and enrolls it with the flight controller. Enrollment usually completes in under two seconds.
4
Verify the fingerprint
The panel shows an 8-character key id (the first bytes of SHA-256 over the key). Note it if you want to check later that another browser is on the same key.
What the flight controller enforces
ArduPilot has no parameter that switches enforcement on or off. A non-zero key in its signing store is the switch: from the moment it holds one, it accepts unsigned frames only on its USB port (plusRADIO_STATUS from a telemetry radio) and drops them on every other link. Sending an all-zero key clears the store and turns signing off.
The flight controller never acknowledges SETUP_SIGNING. The enroll response carries verified: true when the agent saw a frame from the flight controller signed with the new key; verified: false means unconfirmed, not failed. When a request is interrupted after a frame may have gone out, Mission Control keeps both the new key and the previous one and asks the operator which one the flight controller holds. A disable is handled the same way: Mission Control keeps the key until the operator confirms unsigned commands are accepted.
Rotating keys
Click Rotate key in the signing panel to generate a new 32-byte key and enroll it with the flight controller. The old key is replaced once the agent reports the new one sent; an interrupted rotation keeps both until you confirm which one the flight controller holds. Any other browser still holding the previous key loses its ability to sign until you re-enroll it. Rotation is a per-browser action. Each browser that needs to keep working with the rotated key has to re-enroll separately, or import the new key from a browser that already has it.Firmware support
Support is decided from the autopilot type in the flight controller’s heartbeat. The signing key store is not exposed as parameters, so a parameter dump says nothing about it.
Agent REST surface
All routes live under/api/mavlink/signing/, are served natively by the agent’s control front, and are gated by the X-ADOS-Key header.
Request-body redaction strips
key_hex from structured logs. The fingerprint (key_id) is safe to log and appears in audit entries.
Signing is managed from the Mission Control signing panel. For SSH-only diagnostics or lockout recovery, call these routes with curl on the companion computer (for example GET /capability to check support or POST /disable-on-fc to clear the key).
Troubleshooting
Security posture
What signing protects against:- Unauthorized command injection over the cloud relay path.
- A WiFi peer on the same access point sending arm or takeoff commands to your drone.
- A compromised agent host forging commands to the flight controller, because the agent does not hold the key.
- An operator with physical access to the flight controller’s UART.
- Enrollment over an untrusted LAN. The enroll request is plain HTTP, so anyone who can observe that traffic captures the key. Enroll over a link you trust, or over USB or loopback.
- A browser whose JavaScript execution is compromised by a same-origin script injection. The key is raw bytes in IndexedDB, so injected script can read it, copy it off the machine, and sign with it indefinitely. Rotate the key if you suspect the browser or the Mission Control origin was compromised.
- Lost-key recovery. Keep a copy of the key fingerprint somewhere you can find it again.
Next steps
Mission Control signing
Enable, rotate and verify signing from the Setup tab.
MAVLink proxy
How the agent forwards signed frames to the flight controller.
REST API
Full API surface and authentication headers.
Safety
Checks to run before any flight.