[ENG] Multiple vulnerabilities in RDK-B WebUI

This article describes the vulnerabilities CVE-2026-19505 through CVE-2026-19509, how they were discovered, and the process of reporting as well as communicating with RDK and CERT/CC.
Warning
We’re currently providing restricted details, as to our knowledge these vulnerabilities have not been remediated, and we did not receive vendor statements.
All five issues were found in the RDK-B release rdkb-2025q4-kirkstone:
| CVE | Component | Vulnerability class | Authentication | Impact |
|---|---|---|---|---|
| CVE-2026-19505 | jst_functions.c | Improper cryptographic signature verification | None | Authentication bypass, administrative access |
| CVE-2026-19506 | check.jst | Race condition | None (requires a concurrent valid login) | Unauthorised access |
| CVE-2026-19507 | check.jst | Uncontrolled resource consumption | None | Denial of service |
| CVE-2026-19508 | jst_post.c (multipart form-data parser) | Heap-based buffer overflow | None | Memory corruption and denial of service, potentially arbitrary code execution |
| CVE-2026-19509 | ajaxSet_wireless_network_configuration.jst | Improper input validation | Required | Denial of service |
0x0: Once upon a comment
As with most cybersecurity research articles, this story also starts with curiosity. While poking around the Firefox Inspector on a home router’s login page, one of us noticed this comment:

A quick GitHub code search later, we’ve already identified the software:

From many sources online, we’ve learned that RDK-B is broadband router software, used by many vendors around the world, such as Comcast, Liberty Global and T-Mobile 1. It’s probably running on millions of devices 2, and is an alternative to other operating systems like OpenWRT or prplOS.

Not only is this project open-source, but it is also rather well documented. After following steps in the documentation on how to build RDK-B for a Raspberry Pi 4B, we now had a live environment running the OS, with an SSH shell and root access. This is the best experience a security researcher can ask for. So, we started investigating.
0x1: Confusion.jst
We decided to tackle the web UI first, as that’s where the most severe vulnerabilities are usually found.

We found the below configuration file for lighttpd on the device itself:
server.document-root = "/usr/www2/"
# ...
static-file.exclude-extensions = ( ".jst", ".pl", ".fcgi", ".sh" )
# ...
cgi.assign = (
".jst" => "/usr/sbin/jst",
".pl" => "/usr/bin/perl",
".cgi" => "/usr/bin/perl",
".sh" => "/bin/sh" )The lighttpd config file pointed us to /usr/www2/. Here’s what we found in that directory (click on it to have a look!):
- ajax_at_a_glance.jst
- ajax_at_saving.jst
- ajax_ddns.jst
- ajax_hs_port_forwarding.jst
- ajax_managed_devices.jst
- ajax_managed_services.jst
- ajax_moca_diagnostics.jst
- ajax_network_diagnostic_tools.jst
- ajax_parental_reports.jst
- ajax_port_forwarding.jst
- ajax_port_triggering.jst
- ajax_remote_management.jst
- ajaxSet_add_blockedSite.jst
- ajaxSet_addDevice_blockedList.jst
- ajaxSet_add_device.jst
- ajaxSet_Battery.jst
- ajaxSet_checkRFSignal.jst
- ajaxSet_Debug_GlobalParameter.jst
- ajaxSet_DMZ_configuration.jst
- ajaxSet_edit_blockedSite.jst
- ajaxSet_enable_manageSite.jst
- ajaxSet_firewall_config.jst
- ajaxSet_firewall_config_v6.jst
- ajaxSet_hardware_lan.jst
- ajaxSet_index_userbar.jst
- ajaxSet_IP_configuration.jst
- ajaxSet_moca_config.jst
- ajaxSet_mta_Line_Diagnostics.jst
- ajaxSet_mta_sip_packet_log.jst
- ajaxSet_qos.jst
- ajaxSet_remove_blockedSite.jst
- ajaxSet_Reset_Restore.jst
- ajaxSet_RIP_configuration.jst
- ajaxSet_SIPAdvanced_ServiceProvider.jst
- ajaxSet_SIPBasic_GlobalParameter.jst
- ajaxSet_SIPBasic_ServiceProvider.jst
- ajaxSet_trust_computer.jst
- ajaxSet_trust_computer_service.jst
- ajaxSet_UPnP_configuration.jst
- ajaxSet_userbar.jst
- ajaxSet_voip_debug.jst
- ajaxSet_voip_hidden.jst
- ajaxSet_wan_network.jst
- ajaxSet_wireless_network_configuration_edit.jst
- ajaxSet_wireless_network_configuration.jst
- ajaxSet_wireless_network_configuration_redirection.jst
- ajaxSet_wireless_network_configuration_redirection_onewifi.jst
- ajaxSet_wizard_step1.jst
- ajaxSet_wizard_step2.jst
- ajaxSet_wizard_step2_onewifi.jst
- ajaxSet_wps_config.jst
- ajaxSet_wps_config_onewifi.jst
- ajax_troubleshooting_logs.jst
- ajax_wifi_spectrum_analyser.jst
- at_a_glance.jst
- at_saving.jst
- battery.jst
- callsignallog.jst
- captiveportal.jst
- check.jst
- comcastPaginator.css
- common.css
- common-min.css
- cp.css
- global.css
- highContrast.css
- ie6.css
- ie6-min.css
- ie7.css
- ie7-min.css
- jquery.foldertree.css
- jquery.radioswitch.css
- progressBar.css
- vis-network.min.css
- no_rf.css
- pause-block.css
- print.css
- styles.css
- arrows_nav.png
- bg.jpg
- btn_bg.png
- check.png
- fail.png
- gradient.png
- house.png
- icn_battery.png
- icn_on_off.png
- loading.gif
- progress.gif
- success_lg.png
- success.png
- comcastPaginator.js
- gateway.js
- bootstrap.min.js
- bootstrap-waitingfor.js
- jquery-3.7.1.js
- jquery.alerts.js
- jquery.ciscoExt.js
- jquery.foldertree.js
- jquery.highContrastDetect.js
- jquery-migrate-1.2.1.js
- jquery.radioswitch.js
- jquery.validate.js
- jquery.virtualDialog.js
- vis-network.min.js
- utilityFunctions.js
- device_pause_screen_comcast.js
- device_pause_screen_default.js
- captiveportal_arris_logo.png
- captiveportal_rogers_logo.png
- captiveportal_shaw_logo.png
- captiveportal_videotron_logo.png
- captiveportal_xfinity_logo_svg.js
- cox_color_logo.png
- cox_white_logo.png
- logo_arris.png
- logo-generic.png
- logo_rdk.png
- logo_rogers.png
- logo_shaw.png
- logo_videotron.png
- Sky_Wifi.png
- connected_devices_computers_add.jst
- connected_devices_computers.jst
- connection_status.jst
- csrfprotector.jst
- device_discovery.jst
- dmz.jst
- DPoE.jst
- DSXlog.jst
- dynamic_dns_add.jst
- dynamic_dns_edit.jst
- dynamic_dns.jst
- firewall_settings_ipv4.jst
- firewall_settings_ipv6.jst
- hardware.jst
- home_loggedout.jst
- hs_port_forwarding_add.jst
- hs_port_forwarding_edit.jst
- hs_port_forwarding.jst
- actionHandlerUtility_captiveportal.jst
- actionHandlerUtility.jst
- eng.jst
- footer.jst
- fre.jst
- hash.jst
- header.jst
- jwt.jst
- nav.jst
- php.jst
- userbar.jst
- utility.jst
- index.jst
- lan.jst
- CLDRPluralRuleParser.js
- global.js
- it.json
- jquery.i18n.emitter.bidi.js
- jquery.i18n.emitter.js
- jquery.i18n.fallbacks.js
- jquery.i18n.js
- jquery.i18n.language.js
- jquery.i18n.messagestore.js
- jquery.i18n.parser.js
- qqq.json
- local_ip_configuration.jst
- managed_devices_add_computer_allowed.jst
- managed_devices_add_computer_blocked.jst
- managed_devices_edit_allowed.jst
- managed_devices_edit_blocked.jst
- managed_devices.jst
- managed_services_add.jst
- managed_services_edit.jst
- managed_services.jst
- managed_sites_add_keyword.jst
- managed_sites_add_site.jst
- managed_sites.jst
- moca_diagnostics.jst
- moca.jst
- mta_Line_Diagnostics.jst
- mta_Line_Status.jst
- mta_sip_packet_log.jst
- network_diagnostic_tools.jst
- network_setup.jst
- no_rf_signal.jst
- parental_reports_download.jst
- parental_reports.jst
- password_change.jst
- port_forwarding_add.jst
- port_forwarding_edit.jst
- port_forwarding.jst
- port_triggering_add.jst
- port_triggering_edit.jst
- port_triggering.jst
- qos.jst
- remote_management.jst
- restore_reboot.jst
- routing.jst
- software.jst
- status-500.html
- trigger_spectrum_download.jst
- troubleshooting_logs_download.jst
- troubleshooting_logs.jst
- user_password_change.jst
- voice_quality_metrics.jst
- Voip_Debug_GlobalParameter.jst
- Voip_Debug_ServiceProvider.jst
- voip_hidden.jst
- Voip_SipAdvanced_ServiceProvider.jst
- Voip_SipBasic_GlobalParamaters.jst
- Voip_SipBasic_ServiceProvider.jst
- wan_network.jst
- wifi.jst
- wifi_spectrum_analyzer.jst
- wireless_network_configuration_edit.jst
- wireless_network_configuration.jst
- wireless_network_configuration_wps.jst
- wizard_step1.jst
- wizard_step2.jst
As you can see, there are quite a lot of files. Most of these are standalone GUI pages, but some are “action handlers”, i.e. endpoints meant to be called via
JSON from the frontend via an Ajax call. At first, we thought that maybe .jst stood for Java Servlets, but when we peeked inside here’s what we found:
<?%
/* ... 15 lines of Apache 2.0 licence header, Copyright 2018 RDK Management ... */
?>
<?% header('X-robots-tag: noindex,nofollow'); ?>
<?%
include('includes/jwt.jst');
include('includes/hash.jst');
/*
* Set the Locale for the Web UI based on the LANG setting or current linux locale
*/
$locale = getenv("LANG");
$locale = $locale ? $locale : "false";
if($locale != "false"){
if(strstr($locale, 'it')){
$locale="it";
$_SESSION['language'] = $locale;
}
}Hey, that looks like PHP! But this seems rather peculiar… why call PHP files .jst?
So at this point we just ran /usr/sbin/jst, and to our amazement:
$ /usr/sbin/jst
((o) Duktape 2.3.0 (v2.3.0)
duk>We identified the software! It’s Duktape… a JavaScript interpreter…?
Now it has to be said that we are thoroughly confused at this point. The documentation we’ve seen made us expect a rather standard PHP environment, and yet what we have here appears to be ECMAScript code, that looks like PHP, inside a custom file format. In short:
- The original source code was written in PHP, with Zend API native functions
- For some reason they decided to move away from PHP to ECMAScript
- They wrote a transpiler from PHP to ECMAScript in C
- They took the original Duktape, and added a bunch of additional code and logic to make it function as a CGI handler
Not only did they have to implement an entire programming language for their platform, but they also wrote it all in good old C.
For your information, here’s how a typical call works in the RDK-B WebUI:

Naturally we treated this discovery as additional attack surface, and so happily started researching.
0x2: CVE-2026-19509
Vulnerability description
Improper input validation in ajaxSet_wireless_network_configuration.jst in RDK-B WebUI
rdkb-2025q4-kirkstone allows an authenticated attacker to cause denial of service via a crafted
ssid_number parameter.
This was a rather simple vulnerability.
We simply traced GET/POST parameters in the source code, until we eventually found one file, ajaxSet_wireless_network_configuration.jst
where the ssid_number parameter was passed directly to a native C handler, which passed the string to RBus (a getter/setter/method bus similar to ubus in OpenWRT).
This caused rtrouted, the RBus message router, to segfault, after which a watchdog restarts it.
2026 Apr 12 01:00:04 RaspberryPi-Gateway audit[292]: ANOM_ABEND auid=4294967295 uid=0 gid=0 ses=4294967295 pid=292 comm="rtrouted" exe="/usr/bin/rtrouted" sig=11 res=1
2026 Apr 12 01:00:04 RaspberryPi-Gateway systemd[1]: rbus.service: Main process exited, code=dumped, status=11/SEGV
2026 Apr 12 01:00:04 RaspberryPi-Gateway kernel: audit: type=1701 audit(1775955604.769:57): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=292 comm="rtrouted" exe="/usr/bin/rtrouted" sig=11 res=1
2026 Apr 12 01:00:04 RaspberryPi-Gateway kernel[419]: [ 393.296069] audit: type=1701 audit(1775955604.769:57): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=292 comm="rtrouted" exe="/usr/bin/rtrouted" sig=11 res=1
2026 Apr 12 01:00:04 RaspberryPi-Gateway systemd[1]: rbus.service: Failed with result 'core-dump'.
2026 Apr 12 01:00:04 RaspberryPi-Gateway systemd[1]: Starting RBus IPC Restart Service...
2026 Apr 12 01:00:04 RaspberryPi-Gateway systemd[1]: Started RBus IPC Restart Service.As this was the first vulnerability we’ve discovered, we decided to report it immediately to RDK Central. Our first email (encrypted with PGP) was sent to the email in their documentation. While we waited for a reply, we decided to look into the software further, as clearly there were more vulnerabilities to be found.
0x3: CVE-2026-19508
Vulnerability description
A heap-based buffer overflow in the multipart form-data parser in jst_post.c in RDK-B WebUI
rdkb-2025q4-kirkstone allows a remote unauthenticated attacker to cause memory corruption and
denial of service, and potentially execute arbitrary code, via a crafted multipart/form-data request.
As mentioned in a previous section, we’re dealing with a custom CGI handler that has to parse POST/GET parameters, handle file uploads, and do many other things. This naturally sounds like a good candidate for fuzzing, and so we tried compiling JST from source using AFL++, the actively maintained fork of American Fuzzy Lop.
The difficult part was actually getting AFL on the device itself. We tried:
- Compiling AFL++ with clang (on device)
- Compiling gcc (into the image) to compile AFL++ on device
- Compiling AFL++ with clang (into the image)
- Compiling gcc and clang into the image (this was not a good idea)
- Many other things we don’t even remember
Finally, our saving grace was Docker. Yocto has a built-in Docker layer, which builds and installs it into the final image. Inside of Docker, we were able to compile AFL++ as a binary for the correct architecture (with all correct CPU extensions), to then compile the jst interpreter with it.
After writing a fuzzing harness, we’ve identified this vulnerability. We then created two PoCs, both of which allow an attacker to trigger a crash via memory corruption. Both of these crashes can be triggered remotely, without authentication.
We think that this is a particularly severe vulnerability. The crashes occur in very different ways in two very different places, which strongly suggests an attacker can interfere with the Duktape garbage collector. We have not investigated exploitability beyond that point.
Here’s what the early crash looks like in gdb:
0xb6b0bd58 in memcmp_not_common_alignment (len=8, srcp2=<optimized out>, srcp1=<optimized out>)
at memcmp.c:223
(gdb) bt
#0 0xb6b0bd58 in memcmp_not_common_alignment (len=8, srcp2=<optimized out>, srcp1=<optimized out>)
at memcmp.c:223
#1 __GI_memcmp (s1=s1@entry=0x2, s2=s2@entry=0x72510, len=<optimized out>, len@entry=34) at memcmp.c:332
#2 0x0001350c in parse_mpfd_part (parts_len=<synthetic pointer>, parts=<synthetic pointer>,
boundary_len=<optimized out>, boundary=<optimized out>, eof=<optimized out>,
cursor=<synthetic pointer>) at /usr/src/debug/jst/1.0.1-r0/git/source/jst_post.c:656
#3 parse_mpfd (parts_len=<optimized out>, parts=<optimized out>, boundary_len=<optimized out>,
boundary=<optimized out>, content_len=<optimized out>, content_data=<optimized out>)
at /usr/src/debug/jst/1.0.1-r0/git/source/jst_post.c:718
#4 process_multipart_form_data (boundary_len=<optimized out>, boundary=<optimized out>,
content_len=<optimized out>, content_data=<optimized out>)
at /usr/src/debug/jst/1.0.1-r0/git/source/jst_post.c:734
#5 ccsp_post_module_open (ctx=<optimized out>) at /usr/src/debug/jst/1.0.1-r0/git/source/jst_post.c:963
#6 0x00018918 in duk__handle_call_raw (thr=thr@entry=0x48958, idx_func=0, call_flags=call_flags@entry=0)
at /usr/src/debug/jst/1.0.1-r0/git/source/duktape/duktape.c:64393
#7 0x0002b554 in duk_handle_call_unprotected (call_flags=0, idx_func=<optimized out>, thr=0x48958)
at /usr/src/debug/jst/1.0.1-r0/git/source/duktape/duktape.c:64539
#8 0x0001491a in ccsp_extensions_load (ctx=ctx@entry=0x48958)
at /usr/src/debug/jst/1.0.1-r0/git/source/jst_extensions.c:41Compared to the late crash:
duk_hobject_refcount_finalize_norz (h=0x89f60, heap=<optimized out>, heap=<optimized out>)
at /usr/src/debug/jst/1.0.1-r0/git/source/duktape/duktape.c:50942
50942 DUK_HBUFFER_DECREF_NORZ_ALLOWNULL(thr, (duk_hbuffer *) b->buf);
(gdb) bt
#0 duk_hobject_refcount_finalize_norz (h=0x89f60, heap=<optimized out>, heap=<optimized out>)
at /usr/src/debug/jst/1.0.1-r0/git/source/duktape/duktape.c:50942
#1 0x0001a688 in duk_heaphdr_refcount_finalize_norz (hdr=0x89f60, heap=<optimized out>)
at /usr/src/debug/jst/1.0.1-r0/git/source/duktape/duktape.c:51006
#2 duk__finalize_refcounts (heap=0x451f0)
at /usr/src/debug/jst/1.0.1-r0/git/source/duktape/duktape.c:49304
#3 duk_heap_mark_and_sweep (flags=0, heap=0x451f0)
at /usr/src/debug/jst/1.0.1-r0/git/source/duktape/duktape.c:50086
#4 duk_heap_mark_and_sweep (heap=0x451f0, flags=<optimized out>)
at /usr/src/debug/jst/1.0.1-r0/git/source/duktape/duktape.c:49950
#5 0x000241a6 in duk_heap_free (heap=0x451f0)
at /usr/src/debug/jst/1.0.1-r0/git/source/duktape/duktape.c:47369
#6 0x0002427a in duk_destroy_heap (thr=<optimized out>)
at /usr/src/debug/jst/1.0.1-r0/git/source/duktape/duktape.c:16130
#7 0x0000dc76 in destroy_duktape_heap (alloc_provider=<optimized out>, ctx=0x48958)
at /usr/src/debug/jst/1.0.1-r0/git/source/duktape/duk_cmdline.c:1290
#8 main (argc=2, argv=0xbefff9a4, envp=<optimized out>)
at /usr/src/debug/jst/1.0.1-r0/git/source/duktape/duk_cmdline.c:1648Although we’re not sharing the PoCs at this moment, their resulting behaviour heavily implies complex memory corruption patterns.
Now that we’ve found another vulnerability, we decided to first do our thorough research, and then send out an email. This turned out to be a rather good decision, as otherwise we’d have to send a lot of emails.
0x4: CVE-2026-19505
Vulnerability description
Improper cryptographic signature verification in jst_functions.c in RDK-B WebUI
rdkb-2025q4-kirkstone allows a remote unauthenticated attacker to bypass authentication and obtain
administrative access via a forged JWT containing an invalid RSA signature.
The reference RDK-B WebUI has two main authentication flows - the password flow, which relies on end-user controlled login and password credentials, and the completely separate JSON Web Token-based flow.
The latter is used for administrative access from the service operator - for example employees of the telecom that lease the device to an end user. The auth relies on the Azure tenant ID baked in the software at compile time. The router, when presented with a JWT, calls the Azure API to fetch the public keys and verify the JWT signature, which in turn ensures the token was not forged by an attacker, even if they get the tenant ID from the router.
So where is the problem?
If you are familiar with Unix-style return-value semantics, they usually look like this:
result >= 0 /* success */
result < 0 /* error */The code in jst_functions.c responsible for returning the final verdict on signature verification looks like this:
err = EVP_VerifyFinal(...);
if (err >= 0) {
return 1; /* means "signature good" */
}However, if we look at the manpage for the OpenSSL function used in the signature check, the convention is quite different - “EVP_VerifyFinal() returns 1 for a correct signature, 0 for failure and -1 if some other error occurred.”
1 = signature valid
0 = signature invalid
-1 = verification errorIn other words, the “signature is invalid” return value of 0 also satisfies err >= 0, and is treated as success.
This simple error results in any JWT being accepted - with the only constraint being that the JWT must be well-formed and signed (with any key), giving us access to the router with the elevated mso account:
$ cat exploit.sh
#!/bin/bash
# This is a "preview" of the PoC for CVE-2026-19505, and as such might not be accurate.
# Please see the warning in the preamble for this article.
# token_gen.py mints a well-formed JWT signed with an attacker-controlled key.
URL_BASE="https://192.168.1.62"
URL_CHECK="$URL_BASE/check.jst"
curl -k -i -s \
-X POST -H "Content-Type: application/x-www-form-urlencoded" \
--data-raw "token=$(python token_gen.py)" \
"$URL_CHECK"
$ ./exploit.sh
HTTP/1.1 302 Found
Content-type: text/html
location: at_a_glance.jst
Set-Cookie: DUKSID=jst_sessDI17ixSUJsYGYaAL9uA20bbXti3XF5Ce; httponly
Content-Length: 3
Date: Thu, 01 Jan 1970 08:10:10 GMT
Server: RDKM BroadBand Router ServerAs you can see, we have a valid session, and have been redirected to the home page of the router’s web UI.
0x5: CVE-2026-19506
Vulnerability description
Race condition in check.jst in RDK-B WebUI rdkb-2025q4-kirkstone allows a remote
attacker to gain unauthorised access via concurrent authentication requests that exploit shared authentication state.
While the previous vulnerability requires a lot of familiarity with the OpenSSL library, the below one only requires a basic understanding of multiprocessing and/or multithreading.
Here’s a snippet that’s responsible for logging a user in:
$return_status = setStr("Device.Users.User.3.X_RDKCENTRAL-COM_ComparePassword",$_POST["password"],true);
sleep(1);
$passVal= getStr("Device.Users.User.3.X_RDKCENTRAL-COM_ComparePassword");The setStr and getStr functions are native C functions that call RBus, which then passes the parameter
to the appropriate process. This appears to be a “function call”, implemented in getters and setters. Apparently,
it’s enough to wait 1 second to retrieve the authentication result from the service responsible for it.
The result of that comparison is stored in a single shared data-model parameter, rather than per-request. The
authentication state is therefore shared between every concurrent request hitting check.jst.
Now, imagine that you know the password, and a friend sitting next to you does not. If your friend logs in first (with an invalid password), and you log in (with a valid password) within this sleep period, then for both requests the getter will return a successful authentication result.
0x6: CVE-2026-19507
Vulnerability description
Uncontrolled resource consumption in check.jst in RDK-B WebUI
rdkb-2025q4-kirkstone allows a remote unauthenticated attacker to cause denial of service via
excessively large password values.
The check.jst file, by now well examined by us, also hides another vulnerability: unrestricted resource exhaustion.
The submitted password is hashed before it’s compared, and nothing bounds its length, so the cost of that hash grows
with whatever the attacker sends. By crafting a sufficiently ridiculous password parameter, it’s possible to stall the
Duktape process for multiple seconds with a single web request:

From our testing, just a few of these large requests were enough to cause all cores of the Raspberry Pi 4 to run at maximum utilisation. This issue would probably be even more severe on a more restricted ARM processor that some home gateways might have.
0x7: Reporting the vulnerabilities to RDK & CERT/CC
We’ve initially reported all our findings to RDK, including one “privilege-escalation” vulnerability that only really affected the username shown in the WebUI. As mentioned previously, the first vulnerability was reported in April of 2026, but we received no response until we disclosed all 6 findings.
We were then notified that the attachments we’d sent were not correctly identified by their ticket management system, and so we sent our report again. After a period of no responses, we decided to involve CERT/CC, which swiftly handled our case, assigned CVE IDs to all 5 vulnerabilities (the previously mentioned privilege escalation was rejected at this stage), and attempted to coordinate remediation and disclosure of the vulnerabilities.
We followed up with RDK, informing them that the vulnerabilities were scheduled to be published on the 30th of July two weeks before that date (on the 15th of July). After a short exchange on the 16th of July regarding the PGP key used by us, we received an acknowledgement message stating that our report was decrypted successfully on the 21st of July.
Due to this acknowledgement date, we asked CERT/CC on August 10th if we could schedule release of details for a later date, and it was settled on August 19th.
0x8: Impact
According to Censys, there are 30,145 devices with their management interfaces exposed. Some of these devices are running the old PHP version which might not be vulnerable, but others are running the JST Duktape version.

The vulnerabilities described here affect routers all over the world, although it appears that most are located within the United States (approximately 19,128). Many can be found in Peru (8,372) and Canada (1,973). Smaller numbers of these devices can be found all over the world: Taiwan, Montenegro, Poland, Germany, Greece, Argentina.

We would like to thank the Censys platform for granting us research access, so that we could study and understand the potential impact that these vulnerabilities carry.
Research access from Censys
None of these statements were influenced by Censys. We reached out and asked for research access on our own, to understand the global impact these vulnerabilities might have, and to our knowledge censys is the place to get that.
0x9: Remediation & How to fix this
We advise that users/vendors disable remote management for their RDK-B based devices, as it will considerably lower the risk associated with these vulnerabilities. This will not fix the vulnerabilities themselves, but make it so that malicious actors can’t interfere with your device over the public internet.
A malicious actor already on your LAN could exploit these vulnerabilities, and only active remediation from vendors can fix that. We do not currently know if these vulnerabilities have been fixed.
Warning
If you have enabled remote management on your router, consider disabling it, even if you are not running RDK-B. This is a very easy way of reducing the attack surface of your device, and should benefit every consumer router. If in doubt, contact your ISP.
We hope that the publishing of this article alongside the CERT/CC vulnerability note and associated CVEs will bring attention to this matter. If you are a vendor, please consider contacting CERT/CC here to issue a vendor statement.
Full Timeline
- 12.04.2026 - First email to RDK.
- 14.05.2026 - Second email to RDK, describing all 6 vulnerabilities.
- 15.05.2026 - Notification to all known to us support emails about the report being submitted.
- 20.05.2026 - We receive an email informing us they did not receive the attached report.
- 27.05.2026 - We send our report again.
- 08.06.2026 - We report the vulnerabilities to CERT/CC.
- 15.06.2026 - Our CERT/CC report is approved and the five CVEs are assigned. Scheduled public date: 30.07.2026.
- 15.07.2026 - We ask RDK if our report has been received. We mention we’ve involved CERT/CC. We’re asked by RDK to send our report again, and we send our report again.
- 16.07.2026 - We’re asked which PGP key we have used for encrypting the report. We provide a response.
- 21.07.2026 - We receive acknowledgement that our report has been decrypted.
- 10.08.2026 - We ask CERT/CC for an update regarding the publishing date. Scheduled for 19.08.2026.
- 20.08.2026 - This document as well as all CVEs are published.
Disclaimer
RDK and the RDK logo are trademarks of their respective owner and have been used here for identification purposes only.
Sources & Links
Some summaries of vulnerabilities are based on the official CERT/CC vulnerability note, written by Michael Bragg. We would also like to thank Michael for answering all of our questions, and helping us greatly in the coordination process.
- CERT/CC Vulnerability note
- Censys Platform
- RDK-B WebUI source
- RDK Central wiki
- Duktape
- AFL++
- Report Security Incident - RDK Wiki
- JST Source Code
- JST Source Files
- Other pages may be linked in the article directly.