diff --git a/.jules/sentinel.md b/.jules/sentinel.md new file mode 100644 index 0000000..f7628a9 --- /dev/null +++ b/.jules/sentinel.md @@ -0,0 +1,4 @@ +## 2026-02-01 - Recurring Stored XSS in Frontend +**Vulnerability:** Widespread Stored XSS across multiple dashboard pages (Devices, Users, RMCs) due to direct use of `.innerHTML` with unsanitized data from the server. +**Learning:** The application follows a pattern of building table rows as large HTML strings and injecting them into the DOM. This is particularly dangerous for a C2 server where data often originates from untrusted "infected" hosts. +**Prevention:** Always escape dynamic content before inserting it into HTML. The most robust approach in this codebase is to use jQuery's safe DOM construction methods (e.g., `.text()`) and event handlers instead of string-based `innerHTML` and `onclick` attributes. diff --git a/src/main/resources/static/js/rms/account.js b/src/main/resources/static/js/rms/account.js index 067ac48..29df492 100644 --- a/src/main/resources/static/js/rms/account.js +++ b/src/main/resources/static/js/rms/account.js @@ -1,3 +1,13 @@ +function escapeHTML(str) { + if (str === null || str === undefined) return ""; + return str.toString() + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); +} + $(document).ready(function () { $("#logoutNavBar").hide(); diff --git a/src/main/resources/static/js/rms/devices.js b/src/main/resources/static/js/rms/devices.js index b07ca80..a04017c 100644 --- a/src/main/resources/static/js/rms/devices.js +++ b/src/main/resources/static/js/rms/devices.js @@ -43,53 +43,75 @@ function loadDevicesJSONtoTable(devicesListJSON) { console.log("loadDevicesJSONtoTable"); createDevicesTableHeader(); - let devicesList = JSON.parse(devicesListJSON);//jQuery.parseJSON(devicesListJSON); - let tbody = document.createElement("tbody"); - - console.log("devicesList: " + devicesList + " type: " + typeof (devicesList) + " length: " + devicesList.length); - - for (var i = 0; i < devicesList.length; ++i) { - - console.log(devicesList[i]) - - var name = devicesList[i].name; - var IP = devicesList[i].ip; - var serverPort = devicesList[i].serverPort; - var lastConnection = devicesList[i].lastConnection; - var encryptionKey = devicesList[i].encryptionKey; - var associatedUser = devicesList[i].associatedUserEmail; - var commands = devicesList[i].commands; - var commandsOutput = devicesList[i].commandsOutput; - var installationId = devicesList[i].installationId; - var location = devicesList[i].locationAsPosition; - var deviceInfo = devicesList[i].deviceInfoDevName; - - var timeSinceNow = timeSince(new Date(Number(lastConnection))) + " ago"; - - var row = document.createElement("tr"); - row.id = "tableRow" + i; - row.innerHTML = ( - "
IP: " + IP + "
" + - "Port: " + serverPort + "
" + - "Encryption Key: " + encryptionKey + "
" + - "\"> " + name + "" + - "").text("IP: " + device.ip)); + $popoverDiv.append($("
").text("Port: " + device.serverPort)); + $popoverDiv.append($("
").text("Encryption Key: " + device.encryptionKey)); + + let $nameA = $("", { + tabindex: "0", + type: "button", + "class": "btn btn-outline-info", + "data-html": "true", + "data-toggle": "popover", + title: name + " Info", + "data-content": $popoverDiv.html(), + text: name + }); + $row.append($("