fix(HTML Node): Prevent XSS in execution-data preview (#6432)

This commit is contained in:
कारतोफ्फेलस्क्रिप्ट™ 2023-06-16 17:42:13 +02:00 committed by GitHub
parent 4ec755513a
commit 16e0df553c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -1,11 +1,26 @@
<template>
<div class="__html-display ph-no-capture" v-html="html"></div>
<iframe class="__html-display ph-no-capture" :srcdoc="html" />
</template>
<script lang="ts">
import type { PropType } from 'vue';
import sanitizeHtml, { defaults, type IOptions as SanitizeOptions } from 'sanitize-html';
import type { INodeExecutionData } from 'n8n-workflow';
const sanitizeOptions: SanitizeOptions = {
allowVulnerableTags: false,
enforceHtmlBoundary: false,
disallowedTagsMode: 'discard',
allowedTags: [...defaults.allowedTags, 'style', 'img', 'title'],
allowedAttributes: {
...defaults.allowedAttributes,
'*': ['class', 'style'],
},
transformTags: {
head: '',
},
};
export default {
name: 'RunDataHtml',
props: {
@ -15,29 +30,8 @@ export default {
},
computed: {
html() {
if (!this.inputData) return '';
return this.scopeCss(this.inputData[0].json.html as string);
},
},
methods: {
/**
* Scope all CSS selectors to prevent user stylesheets from leaking.
*/
scopeCss(str: string) {
const stylesheets = str.match(/<style>([\s\S]*?)<\/style>/g);
if (!stylesheets) return str;
const map = stylesheets.reduce<Record<string, string>>((acc, match) => {
match.split('\n').forEach((line) => {
if (line.endsWith('{')) acc[line] = ['.__html-display', line].join(' ');
});
return acc;
}, {});
return Object.entries(map).reduce((acc, [key, value]) => acc.replace(key, value), str);
const markup = (this.inputData?.[0].json.html as string) ?? '';
return sanitizeHtml(markup, sanitizeOptions);
},
},
};
@ -45,6 +39,7 @@ export default {
<style lang="scss">
.__html-display {
padding: 0 var(--spacing-s);
width: 100%;
height: 100%;
}
</style>