Merge pull request #2617 from asger-semmle/prototype-pollution-utility

Approved by esbena, mchammer01
This commit is contained in:
semmle-qlci
2020-01-16 13:02:07 +00:00
committed by GitHub
14 changed files with 3254 additions and 0 deletions

View File

@@ -0,0 +1 @@
Security/CWE-400/PrototypePollutionUtility.ql

View File

@@ -0,0 +1,362 @@
import dummy from 'somewhere';
function copyUsingForIn(dst, src) {
for (let key in src) {
if (dst[key]) {
copyUsingForIn(dst[key], src[key]);
} else {
dst[key] = src[key]; // NOT OK
}
}
}
function copyUsingKeys(dst, src) {
Object.keys(src).forEach(key => {
if (dst[key]) {
copyUsingKeys(dst[key], src[key]);
} else {
dst[key] = src[key]; // NOT OK
}
});
}
function copyRest(dst, ...sources) {
for (let source of sources) {
for (let key in source) {
copyRestAux(dst, source[key], key);
}
}
}
function copyRestAux(dst, value, key) {
let dstValue = dst[key];
if (dstValue) {
copyRest(dstValue, value);
} else {
dst[key] = value; // NOT OK
}
}
function copyProtoGuarded(dst, src) {
for (let key in src) {
if (key === "__proto__") continue;
if (dst[key]) {
copyProtoGuarded(dst[key], src[key]);
} else {
dst[key] = src[key]; // NOT OK
}
}
}
function copyCtorGuarded(dst, src) {
for (let key in src) {
if (key === "constructor") continue;
if (dst[key]) {
copyCtorGuarded(dst[key], src[key]);
} else {
dst[key] = src[key]; // NOT OK
}
}
}
function copyDoubleGuarded(dst, src) {
for (let key in src) {
if (key === "constructor" || key === "__proto__") continue;
if (dst[key]) {
copyDoubleGuarded(dst[key], src[key]);
} else {
dst[key] = src[key]; // OK
}
}
}
function isSafe(key) {
return key !== "__proto__" && key !== "constructor" && key !== "prototype";
}
function copyComplex(dst, src) {
for (let key in src) {
if (isSafe(key)) {
if (dst[key]) {
copyComplex(dst[key], src[key]);
} else {
dst[key] = src[key]; // OK
}
}
}
}
function copyHasOwnProperty(dst, src) {
for (let key in src) {
// Guarding the recursive case by dst.hasOwnProperty is safe,
// since '__proto__' and 'constructor' are not own properties of the destination object.
if (dst.hasOwnProperty(key)) {
copyHasOwnProperty(dst[key], src[key]);
} else {
dst[key] = src[key]; // OK
}
}
}
function copyHasOwnPropertyBad(dst, src) {
for (let key in src) {
// Guarding using src.hasOwnProperty is *not* effective,
// since '__proto__' and 'constructor' are own properties in the payload.
if (!src.hasOwnProperty(key)) continue; // Not safe
if (dst[key]) {
copyHasOwnPropertyBad(dst[key], src[key]);
} else {
dst[key] = src[key]; // NOT OK
}
}
}
let _hasOwnProp = Object.prototype.hasOwnProperty;
function copyHasOwnPropertyTearOff(dst, src) {
for (let key in src) {
if (_hasOwnProp.call(dst, key)) {
copyHasOwnPropertyTearOff(dst[key], src[key]);
} else {
dst[key] = src[key]; // OK
}
}
}
function shallowExtend(dst, src) {
for (let key in src) {
dst[key] = src[key]; // OK
}
}
function transform(src, fn) {
if (typeof src !== 'object') return fn(src);
for (let key in src) {
src[key] = transform(src[key], fn); // OK
}
return src;
}
function clone(src) {
if (typeof src !== 'object') return src;
let result = {};
for (let key in src) {
result[key] = clone(src[key]); // OK
}
return result;
}
function higherOrderRecursion(dst, src, callback) {
for (let key in src) {
if (dst[key]) {
callback(dst, src, key);
} else {
dst[key] = src[key]; // NOT OK
}
}
}
function higherOrderRecursionEntry(dst, src) {
higherOrderRecursion(dst, src, (dst, src, key) => {
higherOrderRecursionEntry(dst[key], src[key]);
});
}
function instanceofObjectGuard(dst, src) {
for (let key in src) {
let dstValue = dst[key];
if (typeof dstValue === 'object' && dstValue instanceof Object) {
instanceofObjectGuard(dstValue, src[key]);
} else {
dst[key] = src[key]; // OK
}
}
}
let blacklist = ["__proto__", "constructor"];
function copyWithBlacklist(dst, src) {
for (let key in src) {
if (blacklist.indexOf(key) >= 0) continue;
if (dst[key]) {
copyWithBlacklist(dst[key], src[key]);
} else {
dst[key] = src[key]; // OK
}
}
}
function copyUsingPlainForLoop(dst, src) {
let keys = Object.keys(src);
for (let i = 0; i < keys.length; ++i) {
let key = keys[i];
if (dst[key]) {
copyUsingPlainForLoop(dst[key], src[key]);
} else {
dst[key] = src[key]; // NOT OK
}
}
}
function copyUsingPlainForLoopNoAlias(dst, src) {
// Like copyUsingPlainForLoop, but with keys[i] duplicated at every use-site
let keys = Object.keys(src);
for (let i = 0; i < keys.length; ++i) {
if (dst[key]) {
copyUsingPlainForLoopNoAlias(dst[keys[i]], src[keys[i]]);
} else {
dst[keys[i]] = src[keys[i]]; // NOT OK - but not flagged
}
}
}
function deepSet(map, key1, key2, value) {
if (!map[key1]) {
map[key1] = Object.create(null);
}
map[key1][key2] = value; // OK
}
function deepSetCaller(data) {
let map1 = Object.create(null);
let map2 = Object.create(null);
for (let key in data) {
deepSet(map1, key, 'x', data[key]);
deepSet(map2, 'x', key, data[key]);
}
}
function deepSetBad(map, key1, key2, value) {
if (!map[key1]) {
map[key1] = Object.create(null);
}
map[key1][key2] = value; // NOT OK - object literal can flow here
}
function deepSetCallerBad(data) {
let map1 = Object.create(null);
for (let key in data) {
deepSetBad({}, key, 'x', data[key]); // oops
deepSetBad(map1, 'x', key, data[key]);
}
}
function maybeCopy(x) {
if (x && typeof x === 'object') {
return {...x};
} else {
return x;
}
}
function mergeWithCopy(dst, src) {
if (dst == null) return src;
let result = maybeCopy(dst);
for (let key in src) {
if (src.hasOwnProperty(key)) {
result[key] = mergeWithCopy(dst[key], src[key]); // OK
}
}
return result;
}
function copyUsingEntries(dst, src) {
Object.entries(src).forEach(entry => {
let key = entry[0];
let value = entry[1];
if (dst[key]) {
copyUsingEntries(dst[key], value);
} else {
dst[key] = value; // NOT OK
}
});
}
function copyUsingReflect(dst, src) {
Reflect.ownKeys(src).forEach(key => {
if (dst[key]) {
copyUsingReflect(dst[key], src[key]);
} else {
dst[key] = src[key]; // NOT OK
}
});
}
function copyWithPath(dst, src, path) {
for (let key in src) {
if (src.hasOwnProperty(key)) {
if (dst[key]) {
copyWithPath(dst[key], src[key], path ? path + '.' + key : key);
} else {
let target = {};
target[path] = {};
target[path][key] = src[key]; // OK
doSomething(target);
}
}
}
return dst;
}
function typeofObjectTest(dst, src) {
for (let key in src) {
if (src.hasOwnProperty(key)) {
let value = src[key];
if (dst[key] && typeof value === 'object') {
typeofObjectTest(dst[key], value);
} else {
dst[key] = value; // NOT OK
}
}
}
}
function mergeRephinementNode(dst, src) {
for (let key in src) {
if (src.hasOwnProperty(key)) {
if (key === key && key === key) continue; // Create a phi-node of refinement nodes
let value = src[key];
if (dst[key] && typeof value === 'object') {
mergeRephinementNode(dst[key], value);
} else {
dst[key] = value; // NOT OK
}
}
}
}
function mergeSelective(dst, src) {
for (let key in src) {
if (src.hasOwnProperty(key)) {
// Only 'prefs' is merged recursively
if (key in dst && key !== 'prefs') {
continue;
}
if (dst[key]) {
mergeSelective(dst[key], src[key]);
} else {
dst[key] = src[key]; // OK
}
}
}
}
function isNonArrayObject(item) {
return item && typeof item === 'object' && !Array.isArray(item);
}
function mergePlainObjectsOnly(target, source) {
if (isNonArrayObject(target) && isNonArrayObject(source)) {
Object.keys(source).forEach(key => {
if (key === '__proto__') {
return;
}
if (isNonArrayObject(source[key]) && key in target) {
target[key] = mergePlainObjectsOnly(target[key], source[key], options);
} else {
target[key] = source[key]; // OK
}
});
}
return target;
}

View File

@@ -0,0 +1,10 @@
function merge(dst, src) {
for (let key in src) {
if (!src.hasOwnProperty(key)) continue;
if (isObject(dst[key])) {
merge(dst[key], src[key]);
} else {
dst[key] = src[key];
}
}
}

View File

@@ -0,0 +1,10 @@
function merge(dst, src) {
for (let key in src) {
if (!src.hasOwnProperty(key)) continue;
if (dst.hasOwnProperty(key) && isObject(dst[key])) {
merge(dst[key], src[key]);
} else {
dst[key] = src[key];
}
}
}

View File

@@ -0,0 +1,11 @@
function merge(dst, src) {
for (let key in src) {
if (!src.hasOwnProperty(key)) continue;
if (key === "__proto__" || key === "constructor") continue;
if (isObject(dst[key])) {
merge(dst[key], src[key]);
} else {
dst[key] = src[key];
}
}
}