Index: notebook-4.2.0/notebook/static/notebook/js/outputarea.js =================================================================== --- notebook-4.2.0/notebook/static/notebook/js/outputarea.js +++ notebook-4.2.0/notebook/static/notebook/js/outputarea.js 2018-03-18 20:00:55.135031081 +0100 @@ -554,16 +554,21 @@ var type = OutputArea.display_order[i]; var append = OutputArea.append_map[type]; if ((json.data[type] !== undefined) && append) { + var md = json.metadata || {}; var value = json.data[type]; + var toinsert; if (!this.trusted && !OutputArea.safe_outputs[type]) { // not trusted, sanitize HTML if (type==='text/html' || type==='text/svg') { - value = security.sanitize_html(value); + var parsed = $(security.sanitize_html_and_parse(value)); + toinsert = append.apply(this, [parsed, md, element, handle_inserted]); } else { // don't display if we don't know how to sanitize it console.log("Ignoring untrusted " + type + " output."); continue; } + } else { + toinsert = append.apply(this, [value, md, element, handle_inserted]); } var md = json.metadata || {}; var toinsert = append.apply(this, [value, md, element, handle_inserted]); Index: notebook-4.2.0/notebook/static/notebook/js/textcell.js =================================================================== --- notebook-4.2.0/notebook/static/notebook/js/textcell.js +++ notebook-4.2.0/notebook/static/notebook/js/textcell.js 2018-03-18 20:04:04.846222930 +0100 @@ -274,8 +274,7 @@ math = text_and_math[1]; marked(text, function (err, html) { html = mathjaxutils.replace_math(html, math); - html = security.sanitize_html(html); - html = $($.parseHTML(html)); + html = $(security.sanitize_html_and_parse(html)); // add anchors to headings html.find(":header").addBack(":header").each(function (i, h) { h = $(h); Index: notebook-4.2.0/notebook/static/base/js/security.js =================================================================== --- notebook-4.2.0/notebook/static/base/js/security.js +++ notebook-4.2.0/notebook/static/base/js/security.js 2018-03-18 19:58:13.814017593 +0100 @@ -115,10 +115,30 @@ } return sanitized; + + var sanitize_html_and_parse = function (html, allow_css) { + /** + * Sanitize HTML and parse it safely using jQuery. + * + * This disable's jQuery's html 'prefilter', which can make invalid + * HTML valid after the sanitizer has checked it. + * + * Returns an array of DOM nodes. + */ + var sanitized_html = sanitize_html(html, allow_css); + var prev_htmlPrefilter = $.htmlPrefilter; + $.htmlPrefilter = function(html) {return html;}; // Don't modify HTML + try { + return $.parseHTML(sanitized_html); + } finally { + $.htmlPrefilter = prev_htmlPrefilter; // Set it back again + } + }; }; var security = { caja: caja, + sanitize_html_and_parse: sanitize_html_and_parse, sanitize_html: sanitize_html };