diff --git a/CHANGELOG.md b/CHANGELOG.md index 58441f0f..ea3c2b93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## 2.0.5 (not yet released) * CHANGED: Show OS-specific copy hotkey hint (Cmd+c on Mac, Ctrl+c on others) (#1506) +* FIXED: Prevent browsers from rendering unsafe attachments like HTML in a new tab * FIXED: State corruption after "Remove attachment" (#1824) * FIXED: Copy button is hidden if the document is made as markdown (#1703) * FIXED: Shortened URLs from YOURLS received but failed to parse (#1844) diff --git a/js/privatebin.js b/js/privatebin.js index 49b90ffd..71bf6421 100644 --- a/js/privatebin.js +++ b/js/privatebin.js @@ -2997,11 +2997,18 @@ jQuery.PrivateBin = (function($) { const mimeType = me.getAttachmentMimeType(attachmentData); + // We explicitly do _not_ use the original mime type for the download link + // to always force a download instead of potentially dangerous browser rendering/parsing/interpretation + let safeMimeType = 'application/octet-stream'; + if (me.isSafeMimeType(mimeType)) { + safeMimeType = mimeType; + } + // extract data and convert to binary const rawData = attachmentData.substring(base64Start); const decodedData = rawData.length > 0 ? atob(rawData) : ''; - let blobUrl = getBlobUrl(decodedData, mimeType); + let blobUrl = getBlobUrl(decodedData, safeMimeType); attachmentLink.attr('href', blobUrl); if (typeof fileName !== 'undefined') { @@ -3031,6 +3038,28 @@ jQuery.PrivateBin = (function($) { me.handleBlobAttachmentPreview($attachmentPreview, blobUrl, mimeType); }; + + /** + * Evaluates whether this is known a safe mime type. + * + * This means, the media can safely be displayed and e.g. no XSS should be possible. + * + * @name AttachmentViewer.isSafeMimeType + * @function + * @param {string} + * @returns {bool} + */ + me.isSafeMimeType = function(mimeType) { + return ( + mimeType.startsWith('image/') && + !mimeType.includes('svg') + ) || + mimeType.startsWith('video/') || + mimeType.startsWith('audio/') || + mimeType.endsWith('/pdf') || + mimeType === 'text/plain'; + } + /** * displays the attachment * diff --git a/lib/Configuration.php b/lib/Configuration.php index e235367d..725f663c 100644 --- a/lib/Configuration.php +++ b/lib/Configuration.php @@ -122,7 +122,7 @@ class Configuration 'js/kjua-0.10.0.js' => 'sha512-BYj4xggowR7QD150VLSTRlzH62YPfhpIM+b/1EUEr7RQpdWAGKulxWnOvjFx1FUlba4m6ihpNYuQab51H6XlYg==', 'js/legacy.js' => 'sha512-RQEo1hxpNc37i+jz/D9/JiAZhG8GFx3+SNxjYnI7jUgirDIqrCSj6QPAAZeaidditcWzsJ3jxfEj5lVm7ZwTRQ==', 'js/prettify.js' => 'sha512-puO0Ogy++IoA2Pb9IjSxV1n4+kQkKXYAEUtVzfZpQepyDPyXk8hokiYDS7ybMogYlyyEIwMLpZqVhCkARQWLMg==', - 'js/privatebin.js' => 'sha512-zbka2ePFe4nT6QVb6tManMPWaZleeJk57R0eRgQTZNpRdu5LklTuSdHnIfFKtY7ZLbN2tER1vKYDx1eHwvnDfg==', + 'js/privatebin.js' => 'sha512-jjr01MrlrFg2aOLcUf/BouIVTaYNDNIKvfz5pC4lya4rbUxLinRX/h64mt/KLJotk3XXsvS37z0cGLTbor43fQ==', 'js/purify-3.4.1.js' => 'sha512-280a/Vb6fVFsYaeRrkuDp4EDmdYlt2XS+dlDEO/U9qljPrAraA2bIzHTNmP+9dpwPDDwTML+RS+h5iaagPwTzA==', 'js/showdown-2.1.0.js' => 'sha512-WYXZgkTR0u/Y9SVIA4nTTOih0kXMEd8RRV6MLFdL6YU8ymhR528NLlYQt1nlJQbYz4EW+ZsS0fx1awhiQJme1Q==', 'js/zlib-1.3.2.js' => 'sha512-RAhJgxg9siMIA8ky4c10Rc2zUgnK80olHB8Tt1IOYWY4Eh1WmrviQkDn+sgBlb38ZHq3tzufGC41kP360gmosQ==',