Repository navigation
fix(editor): strip event handler attributes from pasted HTML - #3841
dielduarte wants to merge 1 commit into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🦋 Changeset detectedLatest commit: 2125999 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
commit: |
There was a problem hiding this comment.
1 issue found across 3 files
Confidence score: 4/5
removeEventHandlerAttributesinpackages/editor/src/utils/paste-sanitizer.tsmisses elements inside<template>content, so event-handler attributes can remain in the returned HTML. Traversetemplate.contentas well.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/editor/src/utils/paste-sanitizer.ts">
<violation number="1" location="packages/editor/src/utils/paste-sanitizer.ts:64">
P3: `removeEventHandlerAttributes` doesn't reach `<template>` content, because `getElementsByTagName` only walks child nodes. `<template><img onerror="...\"></template>` keeps its handler in the returned HTML, so the sanitizer still relies on `generateJSON` to drop it. Recurse into `template.content`.</violation>
</file>
Reply with feedback, questions, or to request a fix.
View guided diff | Re-trigger cubic
| } | ||
|
|
||
| function removeEventHandlerAttributes(root: Element): void { | ||
| for (const el of Array.from(root.getElementsByTagName('*'))) { |
There was a problem hiding this comment.
P3: removeEventHandlerAttributes doesn't reach <template> content, because getElementsByTagName only walks child nodes. <template><img onerror="...\"></template> keeps its handler in the returned HTML, so the sanitizer still relies on generateJSON to drop it. Recurse into template.content.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At packages/editor/src/utils/paste-sanitizer.ts, line 64:
<comment>`removeEventHandlerAttributes` doesn't reach `<template>` content, because `getElementsByTagName` only walks child nodes. `<template><img onerror="...\"></template>` keeps its handler in the returned HTML, so the sanitizer still relies on `generateJSON` to drop it. Recurse into `template.content`.</comment>
<file context>
@@ -59,6 +60,16 @@ function removeForbiddenElements(root: Element): void {
}
+function removeEventHandlerAttributes(root: Element): void {
+ for (const el of Array.from(root.getElementsByTagName('*'))) {
+ for (const attr of Array.from(el.attributes)) {
+ if (attr.name.toLowerCase().startsWith('on')) {
</file context>
3a9dbbd to
2125999
Compare
|
Closing: tiptap's schema already drops undeclared attributes, and the alert was dismissed as a false positive. |
Stacked on #3840.
Hardens the paste sanitizer flagged by code scanning alert #312 (
js/xss).sanitizePastedHtmlskips its attribute allowlist when the pasted HTML contains the editor'snode-*class marker, so intra-editor copy/paste keepsclass,styleanddata-*. Anyone can put that marker in HTML they serve, and then event handler attributes went through the sanitizer too:This wasn't exploitable: the sanitized HTML goes through Tiptap's
generateJSON, and the schema keeps only declared attributes. Running the payload above through sanitizer →generateJSON→ editor →composeReactEmailleft noon*attribute in the JSON, the editor HTML or the exported email. But the sanitizer shouldn't rely on the schema for that, so it now strips them itself.Changes
utils/paste-sanitizer.ts: newremoveEventHandlerAttributesstep that always runs, next toremoveForbiddenElementsandscrubUnsafeUrlAttributes. No editor extension declares an attribute starting withon, so nothing that round-trips today is affected..changeset/editor-strip-paste-event-handlers.md: patch for@react-email/editor.The flagged line itself (
DOMParser.parseFromString) builds an inert document where scripts and handlers don't run, so CodeQL may keep reporting it; that part is a false positive.Testing
onclick/onMouseOver/onerrorcomes out with noon*attributes and with itsnode-*classes kept.pnpm build,pnpm typecheckand biome pass.Summary by cubic
Hardens the paste sanitizer so event handler attributes (
onclick,onerror, ...) are stripped from pasted HTML even when it carries the editor'snode-*class marker. Previously that marker made the sanitizer skip its attribute allowlist, lettingon*attributes through; although Tiptap's schema filtered them later, the sanitizer now removes them directly.Notes
DOMParser.parseFromStringline; that finding is a false positive because the parser builds an inert document where scripts and handlers don't run.on, so intra-editor copy/paste round-trips are unaffected.Written for commit 2125999. Summary will update on new commits.