Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ Fixes:
Enterprise Fixes:
- [data-manager] Fixed editing an event whose key contains `&` creating undeletable duplicate rows in the events table

Security Fixes:
- [core] The dashboard escapes `<` when serializing the exposed `countlyGlobal` object into the inline page script, so an application name (or any exposed value) containing a `</script>` end tag in any spelling can no longer break out of the script block and run in another user's session; the active-app name is now rendered with `.text()` instead of `.html()`

## Version 24.05.51

Fixes:
Expand Down
13 changes: 9 additions & 4 deletions frontend/express/libs/express-expose.js
Original file line number Diff line number Diff line change
Expand Up @@ -186,9 +186,13 @@ function string(obj) {
else {
obj = JSON.stringify(obj);
if (obj) {
// Only escape things that could break out of script context
obj = obj.replace(/<\/script>/ig, '</scr"+"ipt>');
obj = obj.replace(/<!--/g, '<\\!--');
// Escape "<" so nothing serialized here can open or close a tag in the inline
// <script> block this value is written into. A "</script>" end tag terminates the
// script in any of its whitespace/slash spellings (</script >, </script/>, ...),
// which an exact-match replace of "</script>" misses; escaping every "<" closes all
// of those plus "<!--" and "<script". The escape parses back to "<", so runtime
// values read from the exposed object are unchanged.
obj = obj.replace(/</g, '\\u003c');
obj = obj.replace(/\u2028/g, '\\u2028'); // Line separator
obj = obj.replace(/\u2029/g, '\\u2029'); // Paragraph separator
}
Expand Down Expand Up @@ -222,7 +226,8 @@ function escape_js_string(str) {
.replace(/\0/g, '\\0') // Null character
.replace(/[\u0000-\u001F\u007F-\u009F]/g, function(ch) {
return '\\u' + ('0000' + ch.charCodeAt(0).toString(16)).slice(-4);
});
})
.replace(/</g, '\\u003c'); // "<" so a key cannot break out of the <script> block
}

exports = module.exports = function(app) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2403,7 +2403,7 @@ var AppRouter = Backbone.Router.extend({

countlyCommon.setActiveApp(activeApp._id);
self.activeAppName = activeApp.name;
$('#active-app-name').html(activeApp.name);
$('#active-app-name').text(activeApp.name);
$('#active-app-name').attr('title', activeApp.name);
$("#active-app-icon").css("background-image", "url('" + countlyGlobal.cdn + "appimages/" + countlyCommon.ACTIVE_APP_ID + ".png')");
}
Expand Down
Loading