fix(renderer): use credentialless and sandbox attributes on iframes

Websites loaded via an iframe could interrupt the user's workflow by initiating certain actions like opening print dialogs, alert boxes, etc. on the user's browser or even initiate file downloads.
By using the sandbox attribute, the iframe is limited in it's actions and can't access browser APIs such as to download files.
With the additional credentialless attribute, the page in the iframe is loaded in a completely separate browsing context on Chromium-based browsers, thus isolating the content even more.
The functionality could previously be abused to initiate certain actions on 3rd-party websites where the user is logged-in, if these 3rd-party websites have no proper CSRF protection. However, this is not a security risk to HedgeDoc itself.

Signed-off-by: Erik Michelson <github@erik.michelson.eu>
This commit is contained in:
Erik Michelson
2025-12-03 22:16:05 +01:00
parent 61e3421697
commit ef724d0fc2
2 changed files with 8 additions and 2 deletions

View File

@@ -14,6 +14,7 @@
- Ignore the healthcheck endpoint in the "too busy" limiter
- Send the referrer origin for YouTube embeddings due to their requirement
- Force kill the server after a timeout when waiting for the realtime server to close connections on shutdown
- Secure iframes with `credentialless` and `sandbox` attributes
- Fix regexes for `[time=...]`, `[name=...]` and `[color=...]` shortcodes in lists
## <i class="fa fa-tag"></i> 1.10.3 <i class="fa fa-calendar-o"></i> 2025-04-09

View File

@@ -461,7 +461,7 @@ export function finishView (view) {
inner.attr('target', '_blank')
$(value).append(inner)
})
// pdf
// pdf
view.find('div.pdf.raw').removeClass('raw')
.each(function (key, value) {
const url = $(value).attr('data-pdfurl')
@@ -471,7 +471,12 @@ export function finishView (view) {
height: '400px'
})
})
// syntax highlighting
// iframe
view.find('iframe')
.each((key, value) => {
$(value).attr('credentialless', '').attr('sandbox', '')
})
// syntax highlighting
view.find('code.raw').removeClass('raw')
.each((key, value) => {
const langDiv = $(value)