Escape a few HTML values in device details, file browser, and permission dialogs (#7823)

Wraps a handful of remaining call sites in EscapeHtml() so they match the convention already used by adjacent code in both views/default.handlebars and views/default3.handlebars. Covers the operating system attribute, volume names in the file browser, thermal sensor titles, and node/mesh names in the sharing dialog, user-group lists, and permission-removal confirmation dialogs. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

TheHermit committed May 22, 2026 at 21:41 UTC aee83b77809ee47e6ec2a2cbe50800244a155722
2 files changed +20 -20
views/default.handlebars
+10 -10
@@ -4007,7 +4007,7 @@
4007 if (xxdialogTag) break;
4008 var node = getNodeFromId(message.nodeid), x = '';
4009 if (node == null) break;
4010 - x += addHtmlValue("Device", node.name);
4010 + x += addHtmlValue("Device", EscapeHtml(node.name));
4011 x += addHtmlValue("Guest Name", message.guestname);
4012 x += addHtmlValue("User Input", message.viewOnly ? "Not allowed, view only" : "Allowed");
4013 if (message.start && message.expire) {
@@ -7817,7 +7817,7 @@
7817 //if (node.intelamt && node.intelamt.user) { x += addDeviceAttribute('Intel&reg; AMT', node.intelamt.user); }
7818
7819 // Operating system description
7820 - if (node.osdesc) { x += addDeviceAttribute("Operating System", node.osdesc); }
7820 + if (node.osdesc) { x += addDeviceAttribute("Operating System", EscapeHtml(node.osdesc)); }
7821
7822 // Windows Security Central
7823 if (node.wsc) {
@@ -11574,7 +11574,7 @@
11574 h += '<input file=999 style=float:left name=fd class=fcb type=checkbox onchange=p13setActions() value=\'' + f.nx + '\'>&nbsp;<span style=float:right title="' + title + '">' + right + '</span>';
11575 h += '<span title="' + shortname + '"><div class=fileIcon' + (f.dt == 'REMOVABLE' ? 5 : (f.dt == 'CDROM' ? 6 : f.t)) + ' onclick=p13folderset("' + encodeURIComponentEx(f.nx) + '")></div><a href=# style=cursor:pointer onclick=\'return p13folderset("' + encodeURIComponentEx(f.nx) + '")\'>';
11576 if (isWindowsNode(currentNode) && f.dt && currentNode.volumes && currentNode.volumes[shortname.charAt(0).toUpperCase()] && currentNode.volumes[shortname.charAt(0).toUpperCase()].name) {
11577 - h += currentNode.volumes[shortname.charAt(0).toUpperCase()].name + ' (' + shortname + ')';
11577 + h += EscapeHtml(currentNode.volumes[shortname.charAt(0).toUpperCase()].name) + ' (' + shortname + ')';
11578 } else {
11579 h += shortname;
11580 }
@@ -12369,7 +12369,7 @@
12369 if (message != null) {
12370 if (Array.isArray(message.thermals) && (message.thermals.length > 0)) {
12371 var x = '&nbsp;';
12372 - for (var i in message.thermals) { x += '<div class=thermalSensor title="'+message.thermals[i].InstanceName+'">' + parseFloat(message.thermals[i].CurrentTemperature).toFixed(2) + '&deg;C / ' + parseFloat((message.thermals[i].CurrentTemperature * 1.8) + 32).toFixed(2) + '&deg;F' + '</div>'; }
12372 + for (var i in message.thermals) { x += '<div class=thermalSensor title="'+EscapeHtml(message.thermals[i].InstanceName)+'">' + parseFloat(message.thermals[i].CurrentTemperature).toFixed(2) + '&deg;C / ' + parseFloat((message.thermals[i].CurrentTemperature * 1.8) + 32).toFixed(2) + '&deg;F' + '</div>'; }
12373 QV('extraGraphValues', true);
12374 QH('extraGraphValues', x);
12375 }
@@ -17087,7 +17087,7 @@
17087 var cr = 0, mesh = omeshes[i], r = currentUserGroup.links[mesh._id].rights, trash = '', rights = makeDeviceGroupRightsString(r);
17088 if ((userinfo.links) && (userinfo.links[mesh._id] != null) && (userinfo.links[mesh._id].rights != null)) { cr = userinfo.links[mesh._id].rights; }
17089 var meshname = '<i>' + "Unknown Device Group" + '</i>';
17090 - if (mesh) { meshname = '<a href=# onclick=\'gotoMesh("' + mesh._id + '");haltEvent(event);\'>' + mesh.name + '</a>'; } else {}
17090 + if (mesh) { meshname = '<a href=# onclick=\'gotoMesh("' + mesh._id + '");haltEvent(event);\'>' + EscapeHtml(mesh.name) + '</a>'; } else {}
17091 if ((cr & 2) != 0) {
17092 trash = '<a href=# onclick=\'return p51removeMeshFromUserGroup(event,"' + encodeURIComponentEx(mesh._id) + '")\' title="' + "Remove user group rights to this device group" + '" style=cursor:pointer><img src=images/trash.png border=0 height=10 width=10></a>';
17093 rights = '<span style=cursor:pointer onclick=p20showAddMeshUserDialog(3,"' + encodeURIComponentEx(mesh._id) + '")>' + rights + ' <img class=hoverButton style=cursor:pointer src=images/link5.png></span>';
@@ -17110,7 +17110,7 @@
17110 for (var i in onodes) {
17111 var node = onodes[i], r = currentUserGroup.links[node._id].rights, trash = '', rights = makeUserDeviceRightsString(r), cr = GetNodeRights(node);
17112 var nodename = '<i>' + "Unknown Device" + '</i>';
17113 - if (node) { nodename = '<a href=# onclick=\'gotoDevice("' + node._id + '");haltEvent(event);\'>' + node.name + '</a>'; } else {}
17113 + if (node) { nodename = '<a href=# onclick=\'gotoDevice("' + node._id + '");haltEvent(event);\'>' + EscapeHtml(node.name) + '</a>'; } else {}
17114 if ((cr & 2) != 0) {
17115 trash = '<a href=# onclick=\'return p51removeDeviceFromUserGroup(event,"' + encodeURIComponentEx(node._id) + '")\' title="' + "Remove user group rights to this device" + '" style=cursor:pointer><img src=images/trash.png border=0 height=10 width=10></a>';
17116 rights = '<span style=cursor:pointer onclick=p20showAddMeshUserDialog(7,"' + encodeURIComponentEx(node._id) + '")>' + rights + ' <img class=hoverButton style=cursor:pointer src=images/link5.png></span>';
@@ -17158,7 +17158,7 @@
17158 if (xxdialogMode) return;
17159 var node = getNodeFromId(decodeURIComponent(nodeid));
17160 if (node == null) return;
17161 - setDialogMode(2, "Remove Device Permissions", 3, p51removeDeviceFromUserGroupEx, format("Confirm removal of access rights for device \"{0}\"?", node.name), node._id);
17161 + setDialogMode(2, "Remove Device Permissions", 3, p51removeDeviceFromUserGroupEx, format("Confirm removal of access rights for device \"{0}\"?", EscapeHtml(node.name)), node._id);
17162 }
17163
17164 function p51removeDeviceFromUserGroupEx(b, nodeid) {
@@ -17169,7 +17169,7 @@
17169 if (xxdialogMode) return;
17170 var mesh = meshes[decodeURIComponent(meshid)];
17171 if (mesh == null) return;
17172 - setDialogMode(2, "Remove Device Group Permissions", 3, p51removeMeshFromUserGroupEx, format("Confirm removal of access rights for device group \"{0}\"?", mesh.name), mesh._id);
17172 + setDialogMode(2, "Remove Device Group Permissions", 3, p51removeMeshFromUserGroupEx, format("Confirm removal of access rights for device group \"{0}\"?", EscapeHtml(mesh.name)), mesh._id);
17173 }
17174
17175 function p51removeMeshFromUserGroupEx(b, meshid) {
@@ -17865,7 +17865,7 @@
17865 function p30removeNodeFromUser(event, nodeid) {
17866 if (xxdialogMode) return;
17867 var node = getNodeFromId(decodeURIComponent(nodeid));
17868 - setDialogMode(2, "Remove Device Permissions", 3, function(b, node) { meshserver.send({ action: 'adddeviceuser', nodeid: node._id, nodename: node.name, userids: [ currentUser._id ], rights: 0, remove: true }); }, format("Confirm removal of access rights for device \"{0}\"?", node.name), node);
17868 + setDialogMode(2, "Remove Device Permissions", 3, function(b, node) { meshserver.send({ action: 'adddeviceuser', nodeid: node._id, nodename: node.name, userids: [ currentUser._id ], rights: 0, remove: true }); }, format("Confirm removal of access rights for device \"{0}\"?", EscapeHtml(node.name)), node);
17869 }
17870
17871 function p30removeUserFromNode(event, userid) {
@@ -17913,7 +17913,7 @@
17913 if (xxdialogMode) return;
17914 var mesh = meshes[decodeURIComponent(meshid)];
17915 if (mesh == null) return;
17916 - setDialogMode(2, "Remove Device Group Permissions", 3, p30removeMeshFromUserEx, format("Confirm removal of access rights for device group \"{0}\"?", mesh.name), mesh._id);
17916 + setDialogMode(2, "Remove Device Group Permissions", 3, p30removeMeshFromUserEx, format("Confirm removal of access rights for device group \"{0}\"?", EscapeHtml(mesh.name)), mesh._id);
17917 }
17918
17919 function p30removeMeshFromUserEx(b, meshid) {
views/default3.handlebars
+10 -10
@@ -4692,7 +4692,7 @@
4692 case 'createDeviceShareLink': { // Guest sharing link
4693 var node = getNodeFromId(message.nodeid), x = '';
4694 if (node == null) break;
4695 - x += addHtmlValue("Device", node.name);
4695 + x += addHtmlValue("Device", EscapeHtml(node.name));
4696 x += addHtmlValue("Guest Name", message.guestname);
4697 x += addHtmlValue("User Input", message.viewOnly ? "Not allowed, view only" : "Allowed");
4698 if (message.start && message.expire) {
@@ -8710,7 +8710,7 @@
8710 //if (node.intelamt && node.intelamt.user) { x += addDeviceAttribute('Intel&reg; AMT', node.intelamt.user); }
8711
8712 // Operating system description
8713 - if (node.osdesc) { x += addDeviceAttribute("Operating System", node.osdesc); }
8713 + if (node.osdesc) { x += addDeviceAttribute("Operating System", EscapeHtml(node.osdesc)); }
8714
8715 // Windows Security Central
8716 if (node.wsc) {
@@ -12609,7 +12609,7 @@
12609 h += '<input file=999 style=float:left name=fd class=fcb type=checkbox class="form-check-input me-2" onchange=p13setActions() value=\'' + f.nx + '\'>&nbsp;<span style=float:right title="' + title + '">' + right + '</span>';
12610 h += '<span title="' + shortname + '"><div class=fileIcon' + (f.dt == 'REMOVABLE' ? 5 : (f.dt == 'CDROM' ? 6 : f.t)) + ' onclick=p13folderset("' + encodeURIComponentEx(f.nx) + '")></div><a href=# style=cursor:pointer onclick=\'return p13folderset("' + encodeURIComponentEx(f.nx) + '")\'>';
12611 if (isWindowsNode(currentNode) && f.dt && currentNode.volumes && currentNode.volumes[shortname.charAt(0).toUpperCase()] && currentNode.volumes[shortname.charAt(0).toUpperCase()].name) {
12612 - h += currentNode.volumes[shortname.charAt(0).toUpperCase()].name + ' (' + shortname + ')';
12612 + h += EscapeHtml(currentNode.volumes[shortname.charAt(0).toUpperCase()].name) + ' (' + shortname + ')';
12613 } else {
12614 h += shortname;
12615 }
@@ -13499,7 +13499,7 @@
13499 if (message != null) {
13500 if (Array.isArray(message.thermals) && (message.thermals.length > 0)) {
13501 var x = '&nbsp;';
13502 - for (var i in message.thermals) { x += '<div class=thermalSensor title="' + message.thermals[i].InstanceName + '">' + parseFloat(message.thermals[i].CurrentTemperature).toFixed(2) + '&deg;C / ' + parseFloat((message.thermals[i].CurrentTemperature * 1.8) + 32).toFixed(2) + '&deg;F' + '</div>'; }
13502 + for (var i in message.thermals) { x += '<div class=thermalSensor title="' + EscapeHtml(message.thermals[i].InstanceName) + '">' + parseFloat(message.thermals[i].CurrentTemperature).toFixed(2) + '&deg;C / ' + parseFloat((message.thermals[i].CurrentTemperature * 1.8) + 32).toFixed(2) + '&deg;F' + '</div>'; }
13503 QV('extraGraphValues', true);
13504 QH('extraGraphValues', x);
13505 }
@@ -18599,7 +18599,7 @@
18599 var cr = 0, mesh = omeshes[i], r = currentUserGroup.links[mesh._id].rights, trash = '', rights = makeDeviceGroupRightsString(r);
18600 if ((userinfo.links) && (userinfo.links[mesh._id] != null) && (userinfo.links[mesh._id].rights != null)) { cr = userinfo.links[mesh._id].rights; }
18601 var meshname = '<i>' + "Unknown Device Group" + '</i>';
18602 - if (mesh) { meshname = '<a href=# onclick=\'gotoMesh("' + mesh._id + '");haltEvent(event);\'>' + mesh.name + '</a>'; } else { }
18602 + if (mesh) { meshname = '<a href=# onclick=\'gotoMesh("' + mesh._id + '");haltEvent(event);\'>' + EscapeHtml(mesh.name) + '</a>'; } else { }
18603 if ((cr & 2) != 0) {
18604 trash = '<a href=# onclick=\'return p51removeMeshFromUserGroup(event,"' + encodeURIComponentEx(mesh._id) + '")\' title="' + "Remove user group rights to this device group" + '" style=cursor:pointer><i class="fa-solid fa-trash text-danger hoverButton"></i></a>';
18605 rights = '<span style=cursor:pointer onclick=p20showAddMeshUserDialog(3,"' + encodeURIComponentEx(mesh._id) + '")>' + rights + ' <img class=hoverButton style=cursor:pointer src=images/link5.png></span>';
@@ -18622,7 +18622,7 @@
18622 for (var i in onodes) {
18623 var node = onodes[i], r = currentUserGroup.links[node._id].rights, trash = '', rights = makeUserDeviceRightsString(r), cr = GetNodeRights(node);
18624 var nodename = '<i>' + "Unknown Device" + '</i>';
18625 - if (node) { nodename = '<a href=# onclick=\'gotoDevice("' + node._id + '");haltEvent(event);\'>' + node.name + '</a>'; } else { }
18625 + if (node) { nodename = '<a href=# onclick=\'gotoDevice("' + node._id + '");haltEvent(event);\'>' + EscapeHtml(node.name) + '</a>'; } else { }
18626 if ((cr & 2) != 0) {
18627 trash = '<a href=# onclick=\'return p51removeDeviceFromUserGroup(event,"' + encodeURIComponentEx(node._id) + '")\' title="' + "Remove user group rights to this device" + '" style=cursor:pointer><img src=images/trash.png border=0 height=10 width=10></a>';
18628 rights = '<span style=cursor:pointer onclick=p20showAddMeshUserDialog(7,"' + encodeURIComponentEx(node._id) + '")>' + rights + ' <img class=hoverButton style=cursor:pointer src=images/link5.png></span>';
@@ -18672,7 +18672,7 @@
18672 if (xxdialogMode) return;
18673 var node = getNodeFromId(decodeURIComponent(nodeid));
18674 if (node == null) return;
18675 - setModalContent('xxAddAgent', "Remove Device Permissions", format("Confirm removal of access rights for device \"{0}\"?", node.name));
18675 + setModalContent('xxAddAgent', "Remove Device Permissions", format("Confirm removal of access rights for device \"{0}\"?", EscapeHtml(node.name)));
18676 showModal('xxAddAgentModal', 'idx_dlgOkButton', () => p51removeDeviceFromUserGroupEx(3, node._id));
18677 }
18678
@@ -18684,7 +18684,7 @@
18684 if (xxdialogMode) return;
18685 var mesh = meshes[decodeURIComponent(meshid)];
18686 if (mesh == null) return;
18687 - setModalContent('xxAddAgent', "Remove Device Group Permissions", format("Confirm removal of access rights for device group \"{0}\"?", mesh.name));
18687 + setModalContent('xxAddAgent', "Remove Device Group Permissions", format("Confirm removal of access rights for device group \"{0}\"?", EscapeHtml(mesh.name)));
18688 showModal('xxAddAgentModal', 'idx_dlgOkButton', () => { meshserver.send({ action: 'removemeshuser', meshid: decodeURIComponent(meshid), userid: currentUserGroup._id }); });;
18689 }
18690 function p51editgroup(focus, nameReadOnly) {
@@ -19410,7 +19410,7 @@
19410 function p30removeNodeFromUser(event, nodeid) {
19411 if (xxdialogMode) return;
19412 var node = getNodeFromId(decodeURIComponent(nodeid));
19413 - setModalContent('xxAddAgent', "Remove Device Permissions", format("Confirm removal of access rights for device \"{0}\"?", node.name));
19413 + setModalContent('xxAddAgent', "Remove Device Permissions", format("Confirm removal of access rights for device \"{0}\"?", EscapeHtml(node.name)));
19414 showModal('xxAddAgentModal', 'idx_dlgOkButton', function (b, node) { meshserver.send({ action: 'adddeviceuser', nodeid: node._id, nodename: node.name, userids: [currentUser._id], rights: 0, remove: true }); }, 3, node);
19415 }
19416
@@ -19471,7 +19471,7 @@
19471 var mesh = meshes[decodeURIComponent(meshid)];
19472 if (mesh == null) return;
19473
19474 - setModalContent('xxAddAgent', "Remove Device Group Permissions", format("Confirm removal of access rights for device group \"{0}\"?", mesh.name));
19474 + setModalContent('xxAddAgent', "Remove Device Group Permissions", format("Confirm removal of access rights for device group \"{0}\"?", EscapeHtml(mesh.name)));
19475 showModal('xxAddAgentModal', 'idx_dlgOkButton', function () {
19476 p30removeMeshFromUserEx(3, mesh._id);
19477 });