fix xss in generic iframe embed (#1419)

This commit is contained in:
Philip Okugbe
2025-07-29 19:28:48 +01:00
committed by GitHub
parent 78bce0e29d
commit 6b627d289c
5 changed files with 42 additions and 11 deletions

View File

@ -1,5 +1,6 @@
import { Node, mergeAttributes } from '@tiptap/core';
import { ReactNodeViewRenderer } from '@tiptap/react';
import { sanitizeUrl } from './utils';
export interface EmbedOptions {
HTMLAttributes: Record<string, any>;
@ -40,9 +41,12 @@ export const Embed = Node.create<EmbedOptions>({
return {
src: {
default: '',
parseHTML: (element) => element.getAttribute('data-src'),
parseHTML: (element) => {
const src = element.getAttribute('data-src');
return sanitizeUrl(src);
},
renderHTML: (attributes: EmbedAttributes) => ({
'data-src': attributes.src,
'data-src': sanitizeUrl(attributes.src),
}),
},
provider: {
@ -85,6 +89,9 @@ export const Embed = Node.create<EmbedOptions>({
},
renderHTML({ HTMLAttributes }) {
const src = HTMLAttributes["data-src"];
const safeHref = sanitizeUrl(src);
return [
"div",
mergeAttributes(
@ -95,10 +102,10 @@ export const Embed = Node.create<EmbedOptions>({
[
"a",
{
href: HTMLAttributes["data-src"],
href: safeHref,
target: "blank",
},
`${HTMLAttributes["data-src"]}`,
safeHref,
],
];
},
@ -108,9 +115,15 @@ export const Embed = Node.create<EmbedOptions>({
setEmbed:
(attrs: EmbedAttributes) =>
({ commands }) => {
// Validate the URL before inserting
const validatedAttrs = {
...attrs,
src: sanitizeUrl(attrs.src),
};
return commands.insertContent({
type: 'embed',
attrs: attrs,
attrs: validatedAttrs,
});
},
};

View File

@ -4,6 +4,7 @@ import { Selection, Transaction } from "@tiptap/pm/state";
import { CellSelection, TableMap } from "@tiptap/pm/tables";
import { Node, ResolvedPos } from "@tiptap/pm/model";
import Table from "@tiptap/extension-table";
import { sanitizeUrl as braintreeSanitizeUrl } from "@braintree/sanitize-url";
export const isRectSelected = (rect: any) => (selection: CellSelection) => {
const map = TableMap.get(selection.$anchorCell.node(-1));
@ -379,3 +380,12 @@ export function setAttributes(
export function icon(name: string) {
return `<span class="ProseMirror-icon ProseMirror-icon-${name}"></span>`;
}
export function sanitizeUrl(url: string | undefined): string {
if (!url) return "";
const sanitized = braintreeSanitizeUrl(url);
// Return empty string instead of "about:blank"
return sanitized === "about:blank" ? "" : sanitized;
}