diff --git a/CHANGES.md b/CHANGES.md index 7e4327a5..9109b24f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,6 +5,7 @@ messages in case from untrusted sources - Security fix/Breaking change (xdomain): Namespace xdomain file to avoid it being used to modify non-xdomain storage +- Security fix (Imagelib): Avoid XSS - Security fix (Imagelib): Expose `dropXMLInternalSubset` to extensions for preventing billion laughs attack (and use in Imagelib) - Security fix (minor): For embedded API, avoid chance for arbitrary diff --git a/editor/extensions/ext-imagelib.js b/editor/extensions/ext-imagelib.js index 25c5f8ab..636c9935 100644 --- a/editor/extensions/ext-imagelib.js +++ b/editor/extensions/ext-imagelib.js @@ -9,7 +9,7 @@ */ export default { name: 'imagelib', - async init ({decode64, importLocale, dropXMLInteralSubset}) { + async init ({decode64, importLocale, dropXMLInternalSubset}) { const imagelibStrings = await importLocale(); const svgEditor = this; @@ -107,7 +107,7 @@ export default { $('#dialog_box').hide(); }); } else { - entry = $('
' + message + '
').data('id', curMeta.id); + entry = $('
').text(message).data('id', curMeta.id); preview.append(entry); curMeta.entry = entry; } @@ -173,15 +173,20 @@ export default { title = curMeta.name; } else { // Try to find a title - // `dropXMLInteralSubset` is to help prevent the billion laughs attack - const xml = new DOMParser().parseFromString(dropXMLInteralSubset(response), 'text/xml').documentElement; // lgtm [js/xml-bomb] + // `dropXMLInternalSubset` is to help prevent the billion laughs attack + const xml = new DOMParser().parseFromString(dropXMLInternalSubset(response), 'text/xml').documentElement; // lgtm [js/xml-bomb] title = $(xml).children('title').first().text() || '(SVG #' + response.length + ')'; } if (curMeta) { preview.children().each(function () { if ($(this).data('id') === id) { if (curMeta.preview_url) { - $(this).html('' + title); + $(this).html( + $('').append( + $('').attr('src', curMeta.preview_url), + document.createTextNode(title) + ) + ); } else { $(this).text(title); } @@ -189,7 +194,9 @@ export default { } }); } else { - preview.append('
' + title + '
'); + preview.append( + $('
').text(title) + ); submit.removeAttr('disabled'); } } else { @@ -197,9 +204,12 @@ export default { title = curMeta.name || ''; } if (curMeta && curMeta.preview_url) { - entry = '' + title; + entry = $('').append( + $('').attr('src', curMeta.preview_url), + document.createTextNode(title) + ); } else { - entry = ''; + entry = $('').attr('src', response); } if (curMeta) {