mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-30 19:21:54 +00:00
[backport cloud/1.38] fix: prevent XSS vulnerability in context menu labels (#8923)
Backport of #8887 to `cloud/1.38` Automatically created by backport workflow. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-8923-backport-cloud-1-38-fix-prevent-XSS-vulnerability-in-context-menu-labels-3096d73d365081baa2dce3b6c8027736) by [Unito](https://www.unito.io) Co-authored-by: Alexander Brown <drjkl@comfy.org> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 99 KiB After Width: | Height: | Size: 93 KiB |
@@ -1,3 +1,5 @@
|
|||||||
|
import DOMPurify from 'dompurify'
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ContextMenuDivElement,
|
ContextMenuDivElement,
|
||||||
IContextMenuOptions,
|
IContextMenuOptions,
|
||||||
@@ -5,6 +7,38 @@ import type {
|
|||||||
} from './interfaces'
|
} from './interfaces'
|
||||||
import { LiteGraph } from './litegraph'
|
import { LiteGraph } from './litegraph'
|
||||||
|
|
||||||
|
const ALLOWED_TAGS = ['span', 'b', 'i', 'em', 'strong']
|
||||||
|
const ALLOWED_STYLE_PROPS = new Set([
|
||||||
|
'display',
|
||||||
|
'color',
|
||||||
|
'background-color',
|
||||||
|
'padding-left',
|
||||||
|
'border-left'
|
||||||
|
])
|
||||||
|
|
||||||
|
DOMPurify.addHook('uponSanitizeAttribute', (_node, data) => {
|
||||||
|
if (data.attrName === 'style') {
|
||||||
|
const sanitizedStyle = data.attrValue
|
||||||
|
.split(';')
|
||||||
|
.map((s) => s.trim())
|
||||||
|
.filter((s) => {
|
||||||
|
const colonIdx = s.indexOf(':')
|
||||||
|
if (colonIdx === -1) return false
|
||||||
|
const prop = s.slice(0, colonIdx).trim().toLowerCase()
|
||||||
|
return ALLOWED_STYLE_PROPS.has(prop)
|
||||||
|
})
|
||||||
|
.join('; ')
|
||||||
|
data.attrValue = sanitizedStyle
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function sanitizeMenuHTML(html: string): string {
|
||||||
|
return DOMPurify.sanitize(html, {
|
||||||
|
ALLOWED_TAGS,
|
||||||
|
ALLOWED_ATTR: ['style']
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Replace this pattern with something more modern.
|
// TODO: Replace this pattern with something more modern.
|
||||||
export interface ContextMenu<TValue = unknown> {
|
export interface ContextMenu<TValue = unknown> {
|
||||||
constructor: new (
|
constructor: new (
|
||||||
@@ -123,7 +157,7 @@ export class ContextMenu<TValue = unknown> {
|
|||||||
if (options.title) {
|
if (options.title) {
|
||||||
const element = document.createElement('div')
|
const element = document.createElement('div')
|
||||||
element.className = 'litemenu-title'
|
element.className = 'litemenu-title'
|
||||||
element.innerHTML = options.title
|
element.textContent = options.title
|
||||||
root.append(element)
|
root.append(element)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,11 +252,18 @@ export class ContextMenu<TValue = unknown> {
|
|||||||
if (value === null) {
|
if (value === null) {
|
||||||
element.classList.add('separator')
|
element.classList.add('separator')
|
||||||
} else {
|
} else {
|
||||||
const innerHtml = name === null ? '' : String(name)
|
const label = name === null ? '' : String(name)
|
||||||
if (typeof value === 'string') {
|
if (typeof value === 'string') {
|
||||||
element.innerHTML = innerHtml
|
element.textContent = label
|
||||||
} else {
|
} else {
|
||||||
element.innerHTML = value?.title ?? innerHtml
|
// Use innerHTML for content that contains HTML tags, textContent otherwise
|
||||||
|
const hasHtmlContent =
|
||||||
|
value?.content !== undefined && /<[a-z][\s\S]*>/i.test(value.content)
|
||||||
|
if (hasHtmlContent) {
|
||||||
|
element.innerHTML = sanitizeMenuHTML(value.content!)
|
||||||
|
} else {
|
||||||
|
element.textContent = value?.title ?? label
|
||||||
|
}
|
||||||
|
|
||||||
if (value.disabled) {
|
if (value.disabled) {
|
||||||
disabled = true
|
disabled = true
|
||||||
|
|||||||
Reference in New Issue
Block a user