From 0a3cccee0e89d92560d47d7209167a2efa404021 Mon Sep 17 00:00:00 2001 From: Pavan Kumar Date: Fri, 13 Feb 2026 22:11:33 +0530 Subject: [PATCH] RDKB-61882: WebUI - HTML Injection in wifi_spectrum_analyzer.jst Reason for change: WebUI - HTML Injection in wifi_spectrum_analyzer.jst Test Procedure: Test for HTML Injection in wifi_spectrum_analyzer.jst Risks:low Priority: P0 Signed-off-by: pavankumarreddy_balireddy@comcast.com --- .../xb3/jst/actionHandler/ajax_at_saving.jst | 118 +++++++++++++++++- 1 file changed, 117 insertions(+), 1 deletion(-) diff --git a/source/Styles/xb3/jst/actionHandler/ajax_at_saving.jst b/source/Styles/xb3/jst/actionHandler/ajax_at_saving.jst index bc9fd28..fb90e82 100644 --- a/source/Styles/xb3/jst/actionHandler/ajax_at_saving.jst +++ b/source/Styles/xb3/jst/actionHandler/ajax_at_saving.jst @@ -21,6 +21,122 @@ if ($_SESSION["loginuser"] == "" || $_SESSION["loginuser"] == false || $_SESSION echo( ''); exit(0); } + +function sanitize_html(input) { + // keepAttrs: true -> keep attributes for allowed tags (default) + // stripDangerous: true -> remove on* handlers and javascript: urls + var KEEP_ATTRS = true; + var STRIP_DANGEROUS = true; + + var ALLOWED_TAGS = ["H2", "DIV", "TABLE", "TBODY", "TR", "TH", "TD"]; + + function isAllowed(tagName) { + for (var i = 0; i < ALLOWED_TAGS.length; i++) { + if (tagName === ALLOWED_TAGS[i]) return true; + } + return false; + } + + // Optional lightweight attribute filter (only used if STRIP_DANGEROUS = true) + function filterAttributes(attrText) { + // Parse attributes in a conservative way: name[=value] + // Keeps spacing as minimal as possible when reconstructing. + var out = []; + var re = /([^\s=\/"'>]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+)))?/g; + var m; + while ((m = re.exec(attrText)) !== null) { + var name = (m[1] || '').toLowerCase(); + var val = (m[2] != null) ? m[2] : (m[3] != null ? m[3] : (m[4] != null ? m[4] : '')); + + // Drop obvious dangerous attributes + if (name.indexOf('on') === 0) continue; // onclick, onload, ... + if (name === 'style') continue; // inline CSS often abused + + // Disallow javascript: and data: in URLish attributes + if (name === 'href' || name === 'src' || name === 'xlink:href') { + var v = String(val).replace(/^\s+|\s+$/g, '').toLowerCase(); + if (!v || v.indexOf('javascript:') === 0 || v.indexOf('data:') === 0) continue; + } + + // Reconstruct attribute (quote with double-quotes) + if (val === '') out.push(name); + else out.push(name + '="' + val.replace(/"/g, '"') + '"'); + } + return out.length ? ' ' + out.join(' ') : ''; + } + + var result = ""; + var i = 0; + var lowerInput = input.toLowerCase(); + + while (i < input.length) { + if (input[i] === '<') { + var start = i; + var end = input.indexOf('>', start); + if (end === -1) { + // no closing '>' — append the rest and stop + result += input.slice(i); + break; + } + + // Raw tag content between '<' and '>' + var raw = input.substring(start + 1, end); + var tagContent = raw.replace(/^\s+|\s+$/g, ''); + var isClosing = tagContent.charAt(0) === '/'; + + // Separate tag name and attributes (for opening tags) + var namePart = isClosing ? tagContent.slice(1) : tagContent; + var spaceIdx = namePart.indexOf(' '); + var tagName = (spaceIdx === -1 ? namePart : namePart.slice(0, spaceIdx)).toUpperCase(); + var attrsPart = (spaceIdx === -1 || isClosing) ? '' : namePart.slice(spaceIdx); + + // Detect self-closing "/>" (rare for your table tags but harmless to support) + var selfClosing = /\/\s*$/.test(tagContent) && !isClosing; + + if (isAllowed(tagName)) { + var tn = tagName.toLowerCase(); + if (isClosing) { + result += ""; + } else { + var attrsOut = ''; + if (KEEP_ATTRS) { + attrsOut = STRIP_DANGEROUS ? filterAttributes(attrsPart) : (attrsPart || ''); + } + // Normalize: ensure a leading space before attributes when present and not already spaced + if (attrsOut && !STRIP_DANGEROUS) { + // If original attrsPart doesn't start with space, add one + if (!/^\s/.test(attrsOut)) attrsOut = ' ' + attrsOut; + } + result += "<" + tn + (attrsOut || '') + (selfClosing ? "/>" : ">"); + } + i = end + 1; + continue; + } + + // Not allowed tag + if (!isClosing) { + // Strip the entire element including its content until the matching closing tag + // (simple depth-1 removal; good enough for this whitelist) + var closing = ""; + var nextClosing = lowerInput.indexOf(closing, end); + if (nextClosing !== -1) { + i = nextClosing + closing.length; + continue; + } + } + + // For disallowed closing tags or unmatched structures, just skip the tag itself + i = end + 1; + } else { + result += input[i++]; + } + } + + return result; +} + +$configInfo = sanitize_html($_POST['configInfo']); + $myfile = fopen("/var/tmp/Wifi_Spectrum_Analyzer_Table.html", "w"); fwrite($myfile, ""); fwrite($myfile, ""); -fwrite($myfile, $_POST['configInfo']); +fwrite($myfile, $configInfo); fclose($myfile); echo( htmlspecialchars(json_encode({"status": "success"}), ENT_NOQUOTES, 'UTF-8')); ?>