CVE-2018-9986: Fix XSS issues with frontend markdown processor.

This fixes a set of XSS issues with Zulip's frontend markdown
processor, which is used in a limited set of contexts, such as local
echo of messages and the drafts feature.

The implementation of several syntax elements, including the <em>
syntax, user and stream mentions, and some others failed to properly
escape the content inside the syntax.

Fix this, and add tests for each corrected code path.

Thanks to w2w for reporting this issue.
This commit is contained in:
Rohitt Vashishtha
2018-03-29 03:55:58 +05:30
committed by Tim Abbott
parent 1207a08b36
commit 3bdc8bbaa5
4 changed files with 72 additions and 14 deletions

View File

@@ -11,6 +11,17 @@ var exports = {};
var realm_filter_map = {};
var realm_filter_list = [];
// Helper function
function escape(html, encode) {
return html
.replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
// Regexes that match some of our common bugdown markup
var backend_only_markdown_re = [
// Inline image previews, check for contiguous chars ending in image suffix
@@ -55,7 +66,7 @@ exports.apply_markdown = function (message) {
message.mentioned_me_directly = true;
}
return '<span class="user-mention" data-user-id="' + person.user_id + '">' +
'@' + person.full_name +
'@' + escape(person.full_name, true) +
'</span>';
} else if (name === 'all' || name === 'everyone' || name === 'stream') {
message.mentioned = true;
@@ -72,7 +83,7 @@ exports.apply_markdown = function (message) {
message.mentioned = true;
}
return '<span class="user-group-mention" data-user-group-id="' + group.id + '">' +
'@' + group.name +
'@' + escape(group.name, true) +
'</span>';
}
return;
@@ -117,15 +128,6 @@ exports.is_status_message = function (raw_content, content) {
content.lastIndexOf('</p>') === content.length - 4);
};
function escape(html, encode) {
return html
.replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
function handleUnicodeEmoji(unicode_emoji) {
var codepoint = unicode_emoji.codePointAt(0).toString(16);
if (emoji_codes.codepoint_to_name.hasOwnProperty(codepoint)) {
@@ -170,7 +172,7 @@ function handleStream(streamName) {
var href = window.location.origin + '/#narrow/stream/' + hash_util.encode_stream_name(stream.name);
return '<a class="stream" data-stream-id="' + stream.stream_id + '" ' +
'href="' + href + '"' +
'>' + '#' + stream.name + '</a>';
'>' + '#' + escape(stream.name) + '</a>';
}