diff --git a/public/js/extra.js b/public/js/extra.js index 8d14579494..0af041c1da 100644 --- a/public/js/extra.js +++ b/public/js/extra.js @@ -28,6 +28,7 @@ import './lib/renderer/lightbox' import { renderCSVPreview } from './lib/renderer/csvpreview' import { escapeAttrValue } from './render' +import { sanitizeUrl } from './utils' import markdownit from 'markdown-it' import markdownitContainer from 'markdown-it-container' @@ -630,10 +631,11 @@ export function finishView (view) { view.find('div.pdf.raw').removeClass('raw') .each(function (key, value) { const url = $(value).attr('data-pdfurl') + const cleanUrl = sanitizeUrl(url) const inner = $('
') $(this).append(inner) setTimeout(() => { - PDFObject.embed(url, inner, { + PDFObject.embed(cleanUrl, inner, { height: '400px' }) }, 1) diff --git a/public/js/utils.js b/public/js/utils.js index 6a98ce9eb3..29ef262a34 100644 --- a/public/js/utils.js +++ b/public/js/utils.js @@ -26,3 +26,23 @@ export function decodeNoteId (encodedId) { idParts.push(id.substr(20, 12)) return idParts.join('-') } + +/** + * sanitize url to prevent XSS + * @see {@link https://github.com/braintree/sanitize-url/issues/52#issue-1593777166} + * + * @param {string} rawUrl + * @returns {string} sanitized url + */ +export function sanitizeUrl (rawUrl) { + try { + const url = new URL(rawUrl) + if (url.protocol === 'http:' || url.protocol === 'https:') { + return url.toString() + } + + throw new Error('Invalid protocol') + } catch (error) { + return 'about:blank' + } +}