Skip to content

Commit 7656f57

Browse files
Merge pull request #1156 from basecamp/paste-vuln
Fix XSS vulnerability on paste
2 parents beabac2 + 626a4f4 commit 7656f57

File tree

5 files changed

+13
-13
lines changed

5 files changed

+13
-13
lines changed

src/test/system/pasting_test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ testGroup("Pasting", { template: "editor_empty" }, () => {
109109
const pasteData = {
110110
"text/plain": "x",
111111
"text/html": `\
112-
copy<div data-trix-attachment="{&quot;contentType&quot;:&quot;text/html&quot;,&quot;content&quot;:&quot;&lt;img src=1 onerror=window.unsanitized.push(1)&gt;HELLO123&quot;}"></div>me
112+
copy<div data-trix-attachment="{&quot;contentType&quot;:&quot;text/anything&quot;,&quot;content&quot;:&quot;&lt;img src=1 onerror=window.unsanitized.push(1)&gt;HELLO123&quot;}"></div>me
113113
`,
114114
}
115115

src/test/test_helpers/fixtures/fixtures.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,7 @@ export const fixtures = {
470470

471471
"content attachment": (() => {
472472
const content =
473-
"<blockquote class=\"twitter-tweet\" data-cards=\"hidden\"><p>ruby-build 20150413 is out, with definitions for 2.2.2, 2.1.6, and 2.0.0-p645 to address recent security issues: <a href=\"https://t.co/YEwV6NtRD8\">https://t.co/YEwV6NtRD8</a></p>&mdash; Sam Stephenson (@sstephenson) <a href=\"https://twitter.com/sstephenson/status/587715996783218688\">April 13, 2015</a></blockquote>"
473+
"<blockquote class=\"twitter-tweet\"><p>ruby-build 20150413 is out, with definitions for 2.2.2, 2.1.6, and 2.0.0-p645 to address recent security issues: <a href=\"https://t.co/YEwV6NtRD8\">https://t.co/YEwV6NtRD8</a></p>&mdash; Sam Stephenson (@sstephenson) <a href=\"https://twitter.com/sstephenson/status/587715996783218688\">April 13, 2015</a></blockquote>"
474474
const href = "https://twitter.com/sstephenson/status/587715996783218688"
475475
const contentType = "embed/twitter"
476476

src/trix/models/html_parser.js

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,7 @@ const blockForAttributes = (attributes = {}, htmlAttributes = {}) => {
4040

4141
const parseTrixDataAttribute = (element, name) => {
4242
try {
43-
const data = JSON.parse(element.getAttribute(`data-trix-${name}`))
44-
45-
if (data.contentType === "text/html" && data.content) {
46-
data.content = HTMLSanitizer.sanitize(data.content).getHTML()
47-
}
48-
49-
return data
43+
return JSON.parse(element.getAttribute(`data-trix-${name}`))
5044
} catch (error) {
5145
return {}
5246
}
@@ -90,8 +84,7 @@ export default class HTMLParser extends BasicObject {
9084
parse() {
9185
try {
9286
this.createHiddenContainer()
93-
const html = HTMLSanitizer.sanitize(this.html).getHTML()
94-
this.containerElement.innerHTML = html
87+
HTMLSanitizer.setHTML(this.containerElement, this.html)
9588
const walker = walkTree(this.containerElement, { usingFilter: nodeFilter })
9689
while (walker.nextNode()) {
9790
this.processNode(walker.currentNode)

src/trix/models/html_sanitizer.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ const DEFAULT_FORBIDDEN_PROTOCOLS = "javascript:".split(" ")
77
const DEFAULT_FORBIDDEN_ELEMENTS = "script iframe form noscript".split(" ")
88

99
export default class HTMLSanitizer extends BasicObject {
10+
static setHTML(element, html) {
11+
const sanitizedElement = new this(html).sanitize()
12+
const sanitizedHtml = sanitizedElement.getHTML ? sanitizedElement.getHTML() : sanitizedElement.outerHTML
13+
element.innerHTML = sanitizedHtml
14+
}
15+
1016
static sanitize(html, options) {
1117
const sanitizer = new this(html, options)
1218
sanitizer.sanitize()

src/trix/views/attachment_view.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as config from "trix/config"
22
import { ZERO_WIDTH_SPACE } from "trix/constants"
33
import { copyObject, makeElement } from "trix/core/helpers"
44
import ObjectView from "trix/views/object_view"
5+
import HTMLSanitizer from "trix/models/html_sanitizer"
56

67
const { css } = config
78

@@ -33,7 +34,7 @@ export default class AttachmentView extends ObjectView {
3334
}
3435

3536
if (this.attachment.hasContent()) {
36-
innerElement.innerHTML = this.attachment.getContent()
37+
HTMLSanitizer.setHTML(innerElement, this.attachment.getContent())
3738
} else {
3839
this.createContentNodes().forEach((node) => {
3940
innerElement.appendChild(node)
@@ -165,6 +166,6 @@ const createCursorTarget = (name) =>
165166

166167
const htmlContainsTagName = function(html, tagName) {
167168
const div = makeElement("div")
168-
div.innerHTML = html || ""
169+
HTMLSanitizer.setHTML(div, html || "")
169170
return div.querySelector(tagName)
170171
}

0 commit comments

Comments
 (0)