Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: serialize-javascript vulnerability by updating package (#10910) #10911

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
22 changes: 14 additions & 8 deletions dist/vue.runtime.common.dev.js
Expand Up @@ -1956,7 +1956,7 @@ if (typeof Promise !== 'undefined' && isNative(Promise)) {
isUsingMicroTask = true;
} else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
// Fallback to setImmediate.
// Techinically it leverages the (macro) task queue,
// Technically it leverages the (macro) task queue,
// but it is still a better choice than setTimeout.
timerFunc = function () {
setImmediate(flushCallbacks);
Expand Down Expand Up @@ -2022,7 +2022,7 @@ var initProxy;
warn(
"Property \"" + key + "\" must be accessed with \"$data." + key + "\" because " +
'properties starting with "$" or "_" are not proxied in the Vue instance to ' +
'prevent conflicts with Vue internals' +
'prevent conflicts with Vue internals. ' +
'See: https://vuejs.org/v2/api/#data',
target
);
Expand Down Expand Up @@ -2905,7 +2905,7 @@ function bindDynamicKeys (baseObj, values) {
if (typeof key === 'string' && key) {
baseObj[values[i]] = values[i + 1];
} else if (key !== '' && key !== null) {
// null is a speical value for explicitly removing a binding
// null is a special value for explicitly removing a binding
warn(
("Invalid value for dynamic directive argument (expected string or null): " + key),
this
Expand Down Expand Up @@ -3400,6 +3400,12 @@ function _createElement (
ns = (context.$vnode && context.$vnode.ns) || config.getTagNamespace(tag);
if (config.isReservedTag(tag)) {
// platform built-in elements
if (isDef(data) && isDef(data.nativeOn)) {
warn(
("The .native modifier for v-on is only valid on components but it was used on <" + tag + ">."),
context
);
}
vnode = new VNode(
config.parsePlatformTagName(tag), data, children,
undefined, undefined, context
Expand Down Expand Up @@ -3525,7 +3531,7 @@ function renderMixin (Vue) {
// render self
var vnode;
try {
// There's no need to maintain a stack becaues all render fns are called
// There's no need to maintain a stack because all render fns are called
// separately from one another. Nested component's render fns are called
// when parent component is patched.
currentRenderingInstance = vm;
Expand Down Expand Up @@ -6095,7 +6101,7 @@ function createPatchFunction (backend) {
}
}

function removeVnodes (parentElm, vnodes, startIdx, endIdx) {
function removeVnodes (vnodes, startIdx, endIdx) {
for (; startIdx <= endIdx; ++startIdx) {
var ch = vnodes[startIdx];
if (isDef(ch)) {
Expand Down Expand Up @@ -6206,7 +6212,7 @@ function createPatchFunction (backend) {
refElm = isUndef(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx + 1].elm;
addVnodes(parentElm, refElm, newCh, newStartIdx, newEndIdx, insertedVnodeQueue);
} else if (newStartIdx > newEndIdx) {
removeVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx);
removeVnodes(oldCh, oldStartIdx, oldEndIdx);
}
}

Expand Down Expand Up @@ -6298,7 +6304,7 @@ function createPatchFunction (backend) {
if (isDef(oldVnode.text)) { nodeOps.setTextContent(elm, ''); }
addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue);
} else if (isDef(oldCh)) {
removeVnodes(elm, oldCh, 0, oldCh.length - 1);
removeVnodes(oldCh, 0, oldCh.length - 1);
} else if (isDef(oldVnode.text)) {
nodeOps.setTextContent(elm, '');
}
Expand Down Expand Up @@ -6527,7 +6533,7 @@ function createPatchFunction (backend) {

// destroy old node
if (isDef(parentElm)) {
removeVnodes(parentElm, [oldVnode], 0, 0);
removeVnodes([oldVnode], 0, 0);
} else if (isDef(oldVnode.tag)) {
invokeDestroyHook(oldVnode);
}
Expand Down
2 changes: 1 addition & 1 deletion dist/vue.runtime.common.prod.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -133,7 +133,7 @@
"rollup-plugin-node-resolve": "^4.0.0",
"rollup-plugin-replace": "^2.0.0",
"selenium-server": "^2.53.1",
"serialize-javascript": "^1.3.0",
"serialize-javascript": "^2.1.0",
"shelljs": "^0.8.1",
"terser": "^3.10.2",
"typescript": "^3.6.4",
Expand Down
31 changes: 23 additions & 8 deletions packages/vue-server-renderer/basic.js
Expand Up @@ -3373,7 +3373,7 @@
var startTagClose = /^\s*(\/?)>/;
var endTag = new RegExp(("^<\\/" + qnameCapture + "[^>]*>"));
var doctype = /^<!DOCTYPE [^>]+>/i;
// #7298: escape - to avoid being pased as HTML comment when inlined in page
// #7298: escape - to avoid being passed as HTML comment when inlined in page
var comment = /^<!\--/;
var conditionalComment = /^<!\[/;

Expand Down Expand Up @@ -3806,7 +3806,7 @@
/* */

var onRE = /^@|^v-on:/;
var dirRE = /^v-|^@|^:/;
var dirRE = /^v-|^@|^:|^#/;
var forAliasRE = /([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/;
var forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/;
var stripParensRE = /^\(|\)$/g;
Expand Down Expand Up @@ -4430,7 +4430,7 @@
if (el.parent && !maybeComponent(el.parent)) {
warn$1(
"<template v-slot> can only appear at the root level inside " +
"the receiving the component",
"the receiving component",
el
);
}
Expand Down Expand Up @@ -5032,7 +5032,7 @@

/* */

var fnExpRE = /^([\w$_]+|\([^)]*?\))\s*=>|^function\s*(?:[\w$]+)?\s*\(/;
var fnExpRE = /^([\w$_]+|\([^)]*?\))\s*=>|^function(?:\s+[\w$]+)?\s*\(/;
var fnInvokeRE = /\([^)]*?\);*$/;
var simplePathRE = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['[^']*?']|\["[^"]*?"]|\[\d+]|\[[A-Za-z_$][\w$]*])*$/;

Expand Down Expand Up @@ -6272,6 +6272,8 @@
var range = node.rawAttrsMap[name];
if (name === 'v-for') {
checkFor(node, ("v-for=\"" + value + "\""), warn, range);
} else if (name === 'v-slot' || name[0] === '#') {
checkFunctionParameterExpression(value, (name + "=\"" + value + "\""), warn, range);
} else if (onRE.test(name)) {
checkEvent(value, (name + "=\"" + value + "\""), warn, range);
} else {
Expand All @@ -6291,9 +6293,9 @@
}

function checkEvent (exp, text, warn, range) {
var stipped = exp.replace(stripStringRE, '');
var keywordMatch = stipped.match(unaryOperatorsRE);
if (keywordMatch && stipped.charAt(keywordMatch.index - 1) !== '$') {
var stripped = exp.replace(stripStringRE, '');
var keywordMatch = stripped.match(unaryOperatorsRE);
if (keywordMatch && stripped.charAt(keywordMatch.index - 1) !== '$') {
warn(
"avoid using JavaScript unary operator as property name: " +
"\"" + (keywordMatch[0]) + "\" in expression " + (text.trim()),
Expand Down Expand Up @@ -6348,6 +6350,19 @@
}
}

function checkFunctionParameterExpression (exp, text, warn, range) {
try {
new Function(exp, '');
} catch (e) {
warn(
"invalid function parameter expression: " + (e.message) + " in\n\n" +
" " + exp + "\n\n" +
" Raw expression: " + (text.trim()) + "\n",
range
);
}
}

/* */

var range = 2;
Expand Down Expand Up @@ -7473,7 +7488,7 @@
if (typeof key === 'string' && key) {
baseObj[values[i]] = values[i + 1];
} else if (key !== '' && key !== null) {
// null is a speical value for explicitly removing a binding
// null is a special value for explicitly removing a binding
warn(
("Invalid value for dynamic directive argument (expected string or null): " + key),
this
Expand Down
31 changes: 23 additions & 8 deletions packages/vue-server-renderer/build.dev.js
Expand Up @@ -3123,7 +3123,7 @@ var startTagOpen = new RegExp(("^<" + qnameCapture));
var startTagClose = /^\s*(\/?)>/;
var endTag = new RegExp(("^<\\/" + qnameCapture + "[^>]*>"));
var doctype = /^<!DOCTYPE [^>]+>/i;
// #7298: escape - to avoid being pased as HTML comment when inlined in page
// #7298: escape - to avoid being passed as HTML comment when inlined in page
var comment = /^<!\--/;
var conditionalComment = /^<!\[/;

Expand Down Expand Up @@ -3556,7 +3556,7 @@ function parseString (chr) {
/* */

var onRE = /^@|^v-on:/;
var dirRE = /^v-|^@|^:/;
var dirRE = /^v-|^@|^:|^#/;
var forAliasRE = /([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/;
var forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/;
var stripParensRE = /^\(|\)$/g;
Expand Down Expand Up @@ -4180,7 +4180,7 @@ function processSlotContent (el) {
if (el.parent && !maybeComponent(el.parent)) {
warn$1(
"<template v-slot> can only appear at the root level inside " +
"the receiving the component",
"the receiving component",
el
);
}
Expand Down Expand Up @@ -4782,7 +4782,7 @@ var baseOptions = {

/* */

var fnExpRE = /^([\w$_]+|\([^)]*?\))\s*=>|^function\s*(?:[\w$]+)?\s*\(/;
var fnExpRE = /^([\w$_]+|\([^)]*?\))\s*=>|^function(?:\s+[\w$]+)?\s*\(/;
var fnInvokeRE = /\([^)]*?\);*$/;
var simplePathRE = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['[^']*?']|\["[^"]*?"]|\[\d+]|\[[A-Za-z_$][\w$]*])*$/;

Expand Down Expand Up @@ -6022,6 +6022,8 @@ function checkNode (node, warn) {
var range = node.rawAttrsMap[name];
if (name === 'v-for') {
checkFor(node, ("v-for=\"" + value + "\""), warn, range);
} else if (name === 'v-slot' || name[0] === '#') {
checkFunctionParameterExpression(value, (name + "=\"" + value + "\""), warn, range);
} else if (onRE.test(name)) {
checkEvent(value, (name + "=\"" + value + "\""), warn, range);
} else {
Expand All @@ -6041,9 +6043,9 @@ function checkNode (node, warn) {
}

function checkEvent (exp, text, warn, range) {
var stipped = exp.replace(stripStringRE, '');
var keywordMatch = stipped.match(unaryOperatorsRE);
if (keywordMatch && stipped.charAt(keywordMatch.index - 1) !== '$') {
var stripped = exp.replace(stripStringRE, '');
var keywordMatch = stripped.match(unaryOperatorsRE);
if (keywordMatch && stripped.charAt(keywordMatch.index - 1) !== '$') {
warn(
"avoid using JavaScript unary operator as property name: " +
"\"" + (keywordMatch[0]) + "\" in expression " + (text.trim()),
Expand Down Expand Up @@ -6098,6 +6100,19 @@ function checkExpression (exp, text, warn, range) {
}
}

function checkFunctionParameterExpression (exp, text, warn, range) {
try {
new Function(exp, '');
} catch (e) {
warn(
"invalid function parameter expression: " + (e.message) + " in\n\n" +
" " + exp + "\n\n" +
" Raw expression: " + (text.trim()) + "\n",
range
);
}
}

/* */

var range = 2;
Expand Down Expand Up @@ -7223,7 +7238,7 @@ function bindDynamicKeys (baseObj, values) {
if (typeof key === 'string' && key) {
baseObj[values[i]] = values[i + 1];
} else if (key !== '' && key !== null) {
// null is a speical value for explicitly removing a binding
// null is a special value for explicitly removing a binding
warn(
("Invalid value for dynamic directive argument (expected string or null): " + key),
this
Expand Down
2 changes: 1 addition & 1 deletion packages/vue-server-renderer/build.prod.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/vue-server-renderer/package.json
Expand Up @@ -25,7 +25,7 @@
"lodash.template": "^4.5.0",
"lodash.uniq": "^4.5.0",
"resolve": "^1.2.0",
"serialize-javascript": "^1.3.0",
"serialize-javascript": "^2.1.0",
"source-map": "0.5.6"
},
"devDependencies": {
Expand Down