From 630bc5cbb9e215be1b0f89def24b3d1ef3412a8e Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 1 Aug 2018 16:53:45 -0400 Subject: [PATCH 1/3] sanitize spread attributes and disallow invalid attribute names --- src/compile/Compiler.ts | 3 ++- src/shared/ssr.js | 13 ++++++++++++- .../attribute-escaped-quotes/_expected.html | 4 ++++ .../samples/attribute-escaped-quotes/main.html | 16 ++++++++++++++++ 4 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 test/server-side-rendering/samples/attribute-escaped-quotes/_expected.html create mode 100644 test/server-side-rendering/samples/attribute-escaped-quotes/main.html diff --git a/src/compile/Compiler.ts b/src/compile/Compiler.ts index bb2ffd1d5e9b..8ef184fb826d 100644 --- a/src/compile/Compiler.ts +++ b/src/compile/Compiler.ts @@ -310,11 +310,12 @@ export default class Compiler { : `_svelteTransitionManager`; inlineHelpers += `\n\nvar ${this.alias(name)} = window.${global} || (window.${global} = ${code});\n\n`; - } else if (name === 'escaped' || name === 'missingComponent') { + } else if (name === 'escaped' || name === 'missingComponent' || name === 'invalidAttributeNameCharacter') { // vars are an awkward special case... would be nice to avoid this const alias = this.alias(name); inlineHelpers += `\n\nconst ${alias} = ${code};` } else { + if (!expression.id) console.log(name, expression); const alias = this.alias(expression.id.name); if (alias !== expression.id.name) { code.overwrite(expression.id.start, expression.id.end, alias); diff --git a/src/shared/ssr.js b/src/shared/ssr.js index 63a5659cf401..11942bdb4b0e 100644 --- a/src/shared/ssr.js +++ b/src/shared/ssr.js @@ -1,12 +1,23 @@ +// https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 +// https://infra.spec.whatwg.org/#noncharacter +export const invalidAttributeNameCharacter = /[\s'"<\/=\u{FDD0}-\u{FDEF}\u{FFFE}\u{FFFF}\u{1FFFE}\u{1FFFF}\u{2FFFE}\u{2FFFF}\u{3FFFE}\u{3FFFF}\u{4FFFE}\u{4FFFF}\u{5FFFE}\u{5FFFF}\u{6FFFE}\u{6FFFF}\u{7FFFE}\u{7FFFF}\u{8FFFE}\u{8FFFF}\u{9FFFE}\u{9FFFF}\u{AFFFE}\u{AFFFF}\u{BFFFE}\u{BFFFF}\u{CFFFE}\u{CFFFF}\u{DFFFE}\u{DFFFF}\u{EFFFE}\u{EFFFF}\u{FFFFE}\u{FFFFF}\u{10FFFE}\u{10FFFF}]/u; + export function spread(args) { const attributes = Object.assign({}, ...args); let str = ''; Object.keys(attributes).forEach(name => { + if (invalidAttributeNameCharacter.test(name)) return; + const value = attributes[name]; if (value === undefined) return; if (value === true) str += " " + name; - str += " " + name + "=" + JSON.stringify(value); + + const escaped = String(value) + .replace(/"/g, '"') + .replace(/'/g, '''); + + str += " " + name + "=" + JSON.stringify(escaped); }); return str; diff --git a/test/server-side-rendering/samples/attribute-escaped-quotes/_expected.html b/test/server-side-rendering/samples/attribute-escaped-quotes/_expected.html new file mode 100644 index 000000000000..bc31ce8bc352 --- /dev/null +++ b/test/server-side-rendering/samples/attribute-escaped-quotes/_expected.html @@ -0,0 +1,4 @@ +
\ No newline at end of file diff --git a/test/server-side-rendering/samples/attribute-escaped-quotes/main.html b/test/server-side-rendering/samples/attribute-escaped-quotes/main.html new file mode 100644 index 000000000000..669d7664acff --- /dev/null +++ b/test/server-side-rendering/samples/attribute-escaped-quotes/main.html @@ -0,0 +1,16 @@ +
+ + \ No newline at end of file From e937060de21e59f16c30575770cc99b64a6a86e7 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 1 Aug 2018 16:56:42 -0400 Subject: [PATCH 2/3] add non-spread test for attribute safety --- .../_expected.html | 4 ++++ .../attribute-escaped-quotes-spread/main.html | 16 ++++++++++++++++ .../attribute-escaped-quotes/_expected.html | 1 - .../samples/attribute-escaped-quotes/main.html | 8 ++------ 4 files changed, 22 insertions(+), 7 deletions(-) create mode 100644 test/server-side-rendering/samples/attribute-escaped-quotes-spread/_expected.html create mode 100644 test/server-side-rendering/samples/attribute-escaped-quotes-spread/main.html diff --git a/test/server-side-rendering/samples/attribute-escaped-quotes-spread/_expected.html b/test/server-side-rendering/samples/attribute-escaped-quotes-spread/_expected.html new file mode 100644 index 000000000000..bc31ce8bc352 --- /dev/null +++ b/test/server-side-rendering/samples/attribute-escaped-quotes-spread/_expected.html @@ -0,0 +1,4 @@ +
\ No newline at end of file diff --git a/test/server-side-rendering/samples/attribute-escaped-quotes-spread/main.html b/test/server-side-rendering/samples/attribute-escaped-quotes-spread/main.html new file mode 100644 index 000000000000..669d7664acff --- /dev/null +++ b/test/server-side-rendering/samples/attribute-escaped-quotes-spread/main.html @@ -0,0 +1,16 @@ +
+ + \ No newline at end of file diff --git a/test/server-side-rendering/samples/attribute-escaped-quotes/_expected.html b/test/server-side-rendering/samples/attribute-escaped-quotes/_expected.html index bc31ce8bc352..c3c9405d7b10 100644 --- a/test/server-side-rendering/samples/attribute-escaped-quotes/_expected.html +++ b/test/server-side-rendering/samples/attribute-escaped-quotes/_expected.html @@ -1,4 +1,3 @@
\ No newline at end of file diff --git a/test/server-side-rendering/samples/attribute-escaped-quotes/main.html b/test/server-side-rendering/samples/attribute-escaped-quotes/main.html index 669d7664acff..47e3466ab0de 100644 --- a/test/server-side-rendering/samples/attribute-escaped-quotes/main.html +++ b/test/server-side-rendering/samples/attribute-escaped-quotes/main.html @@ -1,15 +1,11 @@ -
+