Skip to main content
After my Silverpeas research, I wanted to try something different from another open-source web application. This recent video from Low Level, I Hacked This Temu Router. What I Found Should Be Illegal., came out at just the right time, and it made me curious about how well AI coding agents could handle firmware extraction, binary analysis, and emulation.
I briefly tried a few other router images without finding anything worth pursuing. The Netis NX10 was the first one that worked out, and the vulnerabilities were almost ridiculous in their simplicity. The final chain used two bugs to go from no credentials to a root shell on the router. Both were so basic that the firmware almost felt like a CTF challenge rather than a production device.
Disclaimer

I found no evidence that either vulnerability was deliberately introduced. I use “backdoor” here because of how direct the path was, not as a claim about Netis’s intent.

The Netis NX10

The NX10 firmware was publicly downloadable and the V4 branch was newer than the versions covered by the existing public Netis research I found. It was also suitable for local emulation, which meant I could test the actual web interface and CGI binaries instead of relying only on static analysis. This particular model was chosen by a target-recon agent specifically designed to compare available firmware images based on downloadability, emulation feasibility, and novelty. I downloaded the official V4.0.1.5808 image and later repeated the testing against V3.0.0.4142. Both firmware branches contained the same vulnerable behavior.

LLM agent orchestration

Unlike my previous research on Silverpeas, where I used more of a free-flow style, this time I used a slightly more sophisticated harness. Anthropic’s Claude Opus was the main orchestrator, with OpenAI’s Codex (GPT-5.5) as an independent reviewer.
1

Target selection

Opus first delegated a target-recon agent to compare available firmware images. It checked downloadability, architecture, emulation feasibility, existing research, and possible disclosure paths before recommending the Netis NX10.
2

Firmware and binary review

Once the target was selected, Opus started a binary-RE agent with the extracted firmware. It mapped the CGI dispatch logic, traced request parameters into command sinks, and reviewed the authentication checks.
3

Dynamic testing and redirection

The agents brought the firmware up under emulation and tested their findings against the running web interface. I mostly led the engagement by deciding the next direction, challenging claims that did not make sense, and reviewing the evidence required before accepting a result.
4

Independent review

After the complete chain was working, I brought in Codex for an independent review. GPT-5.5 then repeated the authentication and exploitation tests independently to confirm the findings.
Unlike the latest version of my harness, which uses a swarm approach, in this hunt a specialist was deployed directly for each specific area, with the results carried into the next stage. Most of the work still happened autonomously using the framework, rather than through individual prompts from me.

Building the emulation environment

Firmware emulation was new to me at the time. The LLMs introduced me to FirmAE, which I added to the framework so the agents could inspect the extracted filesystem while interacting with the actual web interface and CGI binaries. It took some work (for the agents 🤣) to get the V4 firmware running properly. Boa initially crashed because /etc/passwd and /etc/group pointed into a runtime filesystem that FirmAE left empty. We had to replace those links with files containing the expected root entries so that Boa could start, and I made sure the vulnerable netis.cgi binary was not modified. We also had to resolve QEMU image locks before the router became reachable. All dynamic testing was performed locally under FirmAE and QEMU; a physical NX10 was not tested. We also later tested the older V3.0.0.4142 firmware.

Findings

The command injection is authentication-gated, and the credential disclosure supplies the required administrator session, making the complete chain an unauthenticated root RCE.

The command injection

To hunt for a proper RCE, I asked the binary-RE agent to trace request parameters all the way into shell-command sinks. It then identified a simple command construction in the router’s ping diagnostic. A request to /web/cgi-bin/skk_set.cgi with tools_set=1 and type=1 reaches pingHandler in the stripped bin/netis.cgi binary. The handler reads the IpAddr parameter and places it directly into a command equivalent to:
Very classic command injection pattern. There was indeed an input filter, but it rejected only four characters: That still left most shell syntax available: backtick command substitution could pass the filter, and ${IFS} could replace spaces without using a literal space - both very classic CTF filter bypasses. The following IpAddr value started a bind shell:
Boa and its CGI handlers ran as root, so the injected process was root as well.

The unauthenticated RCE?

The binary-RE agent originally reported this as an unauthenticated root RCE. The agent initially thought the firmware never enforced authentication. Its first unauthenticated test worked, but only because the router was still in its passwordless factory state. The problem is, if the device had no admin password and exposed its entire management interface, then the lack of authentication was a property of the factory state. It did not make the command injection itself an “unauthenticated” vulnerability. I therefore pushed back on the severity and asked the agent to retest it after setting a proper admin password. Once the password was set up, unauthenticated requests to the diagnostic handler returned a 302 redirect to the login page and did not execute. We tested roughly 28 other setter actions and saw the same behavior. The static analysis had missed a state-dependent authentication gate elsewhere in the request flow. In reality, the command injection was an authenticated administrator-to-root RCE with a CVSS score of 7.2 High. Rather than stopping there, I then asked the agents to re-examine the pre-authentication surface on a configured device, and that led to the second auth-bypass vulnerability.

The authentication bypass

The deeper pre-authentication review began by enumerating every route that still returned 200 on a configured device. That led to /web/cgi-bin/skk_get.cgi?sysinfo. The login page requested this endpoint without a session so that it could display basic device information. The response also included a password field:
I initially had trouble understanding what I was looking at. A pre-authentication request used by the login page was returning the administrator credential I had configured. It was not a temporary login challenge or a session identifier. More importantly, the login handler accepted the disclosed value verbatim:
The response returned a valid administrator session cookie. No password cracking or recovery of the original plaintext was required; whatever representation the firmware returned in sysinfo could be replayed directly. Strictly speaking, this is an unauthenticated credential disclosure, but it acts as an authentication bypass as the disclosed value can immediately be used to obtain an admin session.

Chaining both findings to root

With the credential disclosure in front of the command injection, the complete attack required three HTTP requests and a connection to the resulting shell:
The router used a minimal BusyBox environment, so some commands I would normally use to demonstrate impact were missing. In particular, the image did not provide id or uname. I had to confirm the shell’s identity through /proc/self/status and hostname instead:
The result showed filesystem UIDs of 0 and the hostname Netis-NX10, which also distinguished the guest from the host running QEMU.

Chaining the unauthenticated credential disclosure with the ping command injection to obtain a root shell

Independent validation

While it’s nice to confirm the vulnerability, my next concern was whether the result only existed because of how we had configured the emulated environment. To test that, we changed the administrator password and repeated the process. The unauthenticated sysinfo response changed to the new stored credential, the old value stopped working, and the new value authenticated successfully. Random credentials still failed, and unauthenticated requests to skk_set.cgi continued to return a 302 redirect. To make sure this was not a hallucinated finding, I brought in Codex as an independent reviewer & triager. I made the review more “critical” by asking it to assume that the finding was incorrect or caused by the environment. Codex then repeated the password-change test and confirmed that the disclosure tracked the new value, rejected the old and random credentials, verified the pre-authentication redirect, and reproduced command execution with UID 0. Both reviews used the shipped firmware under FirmAE and QEMU rather than a physical NX10, so unfortunately hardware validation remains a limitation of this research.

Affected firmware and impact

I reproduced the complete chain under emulation on both firmware branches available during testing (V4.0.1.5808 and V3.0.0.4142). An attacker who can reach the management interface can take full control of the router without knowing its administrator password. Root access allows the attacker to read or change the device configuration, modify DNS and routing, access stored secrets, monitor or redirect traffic, install persistence, and use the router as a foothold into the local network. The management interface is available from the LAN by default. A deployment that exposes remote administration could also make the chain reachable from the WAN.

Some final thoughts

This research was a useful comparison with the earlier Silverpeas experiment. The Silverpeas review was mostly free-form: I pointed coding agents at areas of interest, reviewed their leads, and validated the promising ones manually. By the time I looked at Netis, I had started separating the work into target selection, binary analysis, and independent review. The agents still did most of the technical exploration. They selected the target, extracted and inspected the firmware, traced the command injection through a stripped MIPS binary, helped bring the firmware up under emulation, and found the credential disclosure after I redirected the search toward the pre-authentication surface. However, the agents also incorrectly flagged the factory-state result as an unauthenticated RCE. As the human operator, I was able to spot the logic flaw and reject that result. Hey - at least I was still able to contribute :P. Rather than a bunch of back-and-forth prompting, this time most of my input involved choosing the next direction, challenging weak conclusions, and deciding what evidence was required before I would accept a finding. The rest was generally autonomous. With the Netis experience, I refined my harness and made it even more structured to reduce false positives. My current framework uses specialized agent swarms to explore different parts of the attack surface, but every finding still has to pass a separate validator that reproduces the exploit against a fresh deployment and records evidence without trusting the model’s description.

Disclosure timeline

VulnCheck declined to coordinate directly with Netis because it could not identify a public security-reporting channel for the vendor. It asked me to publish the findings using the assigned IDs and indicated that it would populate the public CVE records afterward. At the time of publication, no fixed firmware had been confirmed.

References

Acknowledgements

Thank you to Low Level for publishing the router-hacking video that inspired me to explore firmware security, and to VulnCheck for triaging the vulnerabilities and assigning the CVE IDs.
Last modified on September 13, 2026