mirror of
https://github.com/github/codeql.git
synced 2026-05-02 12:15:17 +02:00
Merge pull request #4778 from asgerf/js/more-prototype-pollution
Approved by erik-krogh, mchammer01
This commit is contained in:
@@ -31,6 +31,7 @@ typeInferenceMismatch
|
||||
| callbacks.js:44:17:44:24 | source() | callbacks.js:41:10:41:10 | x |
|
||||
| callbacks.js:50:18:50:25 | source() | callbacks.js:30:29:30:29 | y |
|
||||
| callbacks.js:51:18:51:25 | source() | callbacks.js:30:29:30:29 | y |
|
||||
| callbacks.js:53:23:53:30 | source() | callbacks.js:58:10:58:10 | x |
|
||||
| capture-flow.js:9:11:9:18 | source() | capture-flow.js:14:10:14:16 | outer() |
|
||||
| captured-sanitizer.js:25:3:25:10 | source() | captured-sanitizer.js:15:10:15:10 | x |
|
||||
| closure.js:6:15:6:22 | source() | closure.js:8:8:8:31 | string. ... (taint) |
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
| callbacks.js:44:17:44:24 | source() | callbacks.js:41:10:41:10 | x |
|
||||
| callbacks.js:50:18:50:25 | source() | callbacks.js:30:29:30:29 | y |
|
||||
| callbacks.js:51:18:51:25 | source() | callbacks.js:30:29:30:29 | y |
|
||||
| callbacks.js:53:23:53:30 | source() | callbacks.js:58:10:58:10 | x |
|
||||
| capture-flow.js:9:11:9:18 | source() | capture-flow.js:14:10:14:16 | outer() |
|
||||
| captured-sanitizer.js:25:3:25:10 | source() | captured-sanitizer.js:15:10:15:10 | x |
|
||||
| constructor-calls.js:4:18:4:25 | source() | constructor-calls.js:18:8:18:14 | c.taint |
|
||||
|
||||
@@ -49,4 +49,12 @@ function test() {
|
||||
|
||||
middleCallback(source());
|
||||
middleCallback(source());
|
||||
|
||||
let capturedTaint = source();
|
||||
function helper2(cb) {
|
||||
cb(capturedTaint);
|
||||
}
|
||||
helper2(x => {
|
||||
sink(x); // NOT OK
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
Security/CWE-400/PrototypePollution.ql
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1 +0,0 @@
|
||||
Security/CWE-400/PrototypePollutionUtility.ql
|
||||
@@ -25,6 +25,13 @@ nodes
|
||||
| tst.js:45:15:45:35 | ctx.req ... ery.foo |
|
||||
| tst.js:46:5:46:7 | foo |
|
||||
| tst.js:46:5:46:7 | foo |
|
||||
| tst.js:77:25:77:38 | req.query.path |
|
||||
| tst.js:77:25:77:38 | req.query.path |
|
||||
| tst.js:80:23:80:23 | p |
|
||||
| tst.js:81:9:81:9 | p |
|
||||
| tst.js:81:9:81:9 | p |
|
||||
| tst.js:82:9:82:9 | p |
|
||||
| tst.js:82:9:82:9 | p |
|
||||
edges
|
||||
| tst.js:5:9:5:27 | foo | tst.js:6:5:6:7 | foo |
|
||||
| tst.js:5:9:5:27 | foo | tst.js:6:5:6:7 | foo |
|
||||
@@ -50,13 +57,21 @@ edges
|
||||
| tst.js:45:9:45:35 | foo | tst.js:46:5:46:7 | foo |
|
||||
| tst.js:45:15:45:35 | ctx.req ... ery.foo | tst.js:45:9:45:35 | foo |
|
||||
| tst.js:45:15:45:35 | ctx.req ... ery.foo | tst.js:45:9:45:35 | foo |
|
||||
| tst.js:77:25:77:38 | req.query.path | tst.js:80:23:80:23 | p |
|
||||
| tst.js:77:25:77:38 | req.query.path | tst.js:80:23:80:23 | p |
|
||||
| tst.js:80:23:80:23 | p | tst.js:81:9:81:9 | p |
|
||||
| tst.js:80:23:80:23 | p | tst.js:81:9:81:9 | p |
|
||||
| tst.js:80:23:80:23 | p | tst.js:82:9:82:9 | p |
|
||||
| tst.js:80:23:80:23 | p | tst.js:82:9:82:9 | p |
|
||||
#select
|
||||
| tst.js:6:5:6:7 | foo | tst.js:5:15:5:27 | req.query.foo | tst.js:6:5:6:7 | foo | Potential type confusion for $@. | tst.js:5:15:5:27 | req.query.foo | HTTP request parameter |
|
||||
| tst.js:8:5:8:7 | foo | tst.js:5:15:5:27 | req.query.foo | tst.js:8:5:8:7 | foo | Potential type confusion for $@. | tst.js:5:15:5:27 | req.query.foo | HTTP request parameter |
|
||||
| tst.js:11:9:11:11 | foo | tst.js:5:15:5:27 | req.query.foo | tst.js:11:9:11:11 | foo | Potential type confusion for $@. | tst.js:5:15:5:27 | req.query.foo | HTTP request parameter |
|
||||
| tst.js:15:9:15:11 | bar | tst.js:5:15:5:27 | req.query.foo | tst.js:15:9:15:11 | bar | Potential type confusion for $@. | tst.js:5:15:5:27 | req.query.foo | HTTP request parameter |
|
||||
| tst.js:27:5:27:7 | foo | tst.js:5:15:5:27 | req.query.foo | tst.js:27:5:27:7 | foo | Potential type confusion for $@. | tst.js:5:15:5:27 | req.query.foo | HTTP request parameter |
|
||||
| tst.js:28:5:28:7 | foo | tst.js:5:15:5:27 | req.query.foo | tst.js:28:5:28:7 | foo | Potential type confusion for $@. | tst.js:5:15:5:27 | req.query.foo | HTTP request parameter |
|
||||
| tst.js:36:9:36:11 | foo | tst.js:5:15:5:27 | req.query.foo | tst.js:36:9:36:11 | foo | Potential type confusion for $@. | tst.js:5:15:5:27 | req.query.foo | HTTP request parameter |
|
||||
| tst.js:41:5:41:7 | foo | tst.js:5:15:5:27 | req.query.foo | tst.js:41:5:41:7 | foo | Potential type confusion for $@. | tst.js:5:15:5:27 | req.query.foo | HTTP request parameter |
|
||||
| tst.js:46:5:46:7 | foo | tst.js:45:15:45:35 | ctx.req ... ery.foo | tst.js:46:5:46:7 | foo | Potential type confusion for $@. | tst.js:45:15:45:35 | ctx.req ... ery.foo | HTTP request parameter |
|
||||
| tst.js:6:5:6:7 | foo | tst.js:5:15:5:27 | req.query.foo | tst.js:6:5:6:7 | foo | Potential type confusion as $@ may be either an array or a string. | tst.js:5:15:5:27 | req.query.foo | this HTTP request parameter |
|
||||
| tst.js:8:5:8:7 | foo | tst.js:5:15:5:27 | req.query.foo | tst.js:8:5:8:7 | foo | Potential type confusion as $@ may be either an array or a string. | tst.js:5:15:5:27 | req.query.foo | this HTTP request parameter |
|
||||
| tst.js:11:9:11:11 | foo | tst.js:5:15:5:27 | req.query.foo | tst.js:11:9:11:11 | foo | Potential type confusion as $@ may be either an array or a string. | tst.js:5:15:5:27 | req.query.foo | this HTTP request parameter |
|
||||
| tst.js:15:9:15:11 | bar | tst.js:5:15:5:27 | req.query.foo | tst.js:15:9:15:11 | bar | Potential type confusion as $@ may be either an array or a string. | tst.js:5:15:5:27 | req.query.foo | this HTTP request parameter |
|
||||
| tst.js:27:5:27:7 | foo | tst.js:5:15:5:27 | req.query.foo | tst.js:27:5:27:7 | foo | Potential type confusion as $@ may be either an array or a string. | tst.js:5:15:5:27 | req.query.foo | this HTTP request parameter |
|
||||
| tst.js:28:5:28:7 | foo | tst.js:5:15:5:27 | req.query.foo | tst.js:28:5:28:7 | foo | Potential type confusion as $@ may be either an array or a string. | tst.js:5:15:5:27 | req.query.foo | this HTTP request parameter |
|
||||
| tst.js:36:9:36:11 | foo | tst.js:5:15:5:27 | req.query.foo | tst.js:36:9:36:11 | foo | Potential type confusion as $@ may be either an array or a string. | tst.js:5:15:5:27 | req.query.foo | this HTTP request parameter |
|
||||
| tst.js:41:5:41:7 | foo | tst.js:5:15:5:27 | req.query.foo | tst.js:41:5:41:7 | foo | Potential type confusion as $@ may be either an array or a string. | tst.js:5:15:5:27 | req.query.foo | this HTTP request parameter |
|
||||
| tst.js:46:5:46:7 | foo | tst.js:45:15:45:35 | ctx.req ... ery.foo | tst.js:46:5:46:7 | foo | Potential type confusion as $@ may be either an array or a string. | tst.js:45:15:45:35 | ctx.req ... ery.foo | this HTTP request parameter |
|
||||
| tst.js:81:9:81:9 | p | tst.js:77:25:77:38 | req.query.path | tst.js:81:9:81:9 | p | Potential type confusion as $@ may be either an array or a string. | tst.js:77:25:77:38 | req.query.path | this HTTP request parameter |
|
||||
| tst.js:82:9:82:9 | p | tst.js:77:25:77:38 | req.query.path | tst.js:82:9:82:9 | p | Potential type confusion as $@ may be either an array or a string. | tst.js:77:25:77:38 | req.query.path | this HTTP request parameter |
|
||||
|
||||
@@ -71,3 +71,16 @@ express().get('/some/path/:foo', function(req, res) {
|
||||
|
||||
p.length < 1; // OK
|
||||
});
|
||||
|
||||
express().get('/some/path/:foo', function(req, res) {
|
||||
let someObject = {};
|
||||
safeGet(someObject, req.query.path).bar = 'baz'; // prototype pollution here - but flagged in `safeGet`
|
||||
});
|
||||
|
||||
function safeGet(obj, p) {
|
||||
if (p === '__proto__' || // NOT OK - could be singleton array
|
||||
p === 'constructor') { // NOT OK - could be singleton array
|
||||
return null;
|
||||
}
|
||||
return obj[p];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
import javascript
|
||||
import testUtilities.ConsistencyChecking
|
||||
import semmle.javascript.security.dataflow.PrototypePollutingAssignment
|
||||
|
||||
class Config extends ConsistencyConfiguration, PrototypePollutingAssignment::Configuration {
|
||||
override File getAFile() { any() }
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
nodes
|
||||
| tst.js:5:9:5:38 | taint |
|
||||
| tst.js:5:17:5:38 | String( ... y.data) |
|
||||
| tst.js:5:24:5:37 | req.query.data |
|
||||
| tst.js:5:24:5:37 | req.query.data |
|
||||
| tst.js:8:5:8:17 | object[taint] |
|
||||
| tst.js:8:5:8:17 | object[taint] |
|
||||
| tst.js:8:12:8:16 | taint |
|
||||
| tst.js:9:5:9:17 | object[taint] |
|
||||
| tst.js:9:5:9:17 | object[taint] |
|
||||
| tst.js:9:12:9:16 | taint |
|
||||
| tst.js:12:18:12:30 | object[taint] |
|
||||
| tst.js:12:25:12:29 | taint |
|
||||
| tst.js:14:5:14:32 | unsafeG ... taint) |
|
||||
| tst.js:14:5:14:32 | unsafeG ... taint) |
|
||||
| tst.js:14:27:14:31 | taint |
|
||||
| tst.js:33:23:33:25 | obj |
|
||||
| tst.js:34:5:34:7 | obj |
|
||||
| tst.js:34:5:34:7 | obj |
|
||||
| tst.js:39:9:39:11 | obj |
|
||||
| tst.js:39:9:39:11 | obj |
|
||||
| tst.js:45:9:45:11 | obj |
|
||||
| tst.js:45:9:45:11 | obj |
|
||||
| tst.js:48:9:48:11 | obj |
|
||||
| tst.js:48:9:48:11 | obj |
|
||||
edges
|
||||
| tst.js:5:9:5:38 | taint | tst.js:8:12:8:16 | taint |
|
||||
| tst.js:5:9:5:38 | taint | tst.js:9:12:9:16 | taint |
|
||||
| tst.js:5:9:5:38 | taint | tst.js:12:25:12:29 | taint |
|
||||
| tst.js:5:9:5:38 | taint | tst.js:14:27:14:31 | taint |
|
||||
| tst.js:5:17:5:38 | String( ... y.data) | tst.js:5:9:5:38 | taint |
|
||||
| tst.js:5:24:5:37 | req.query.data | tst.js:5:17:5:38 | String( ... y.data) |
|
||||
| tst.js:5:24:5:37 | req.query.data | tst.js:5:17:5:38 | String( ... y.data) |
|
||||
| tst.js:8:12:8:16 | taint | tst.js:8:5:8:17 | object[taint] |
|
||||
| tst.js:8:12:8:16 | taint | tst.js:8:5:8:17 | object[taint] |
|
||||
| tst.js:9:12:9:16 | taint | tst.js:9:5:9:17 | object[taint] |
|
||||
| tst.js:9:12:9:16 | taint | tst.js:9:5:9:17 | object[taint] |
|
||||
| tst.js:12:18:12:30 | object[taint] | tst.js:33:23:33:25 | obj |
|
||||
| tst.js:12:25:12:29 | taint | tst.js:12:18:12:30 | object[taint] |
|
||||
| tst.js:14:27:14:31 | taint | tst.js:14:5:14:32 | unsafeG ... taint) |
|
||||
| tst.js:14:27:14:31 | taint | tst.js:14:5:14:32 | unsafeG ... taint) |
|
||||
| tst.js:33:23:33:25 | obj | tst.js:34:5:34:7 | obj |
|
||||
| tst.js:33:23:33:25 | obj | tst.js:34:5:34:7 | obj |
|
||||
| tst.js:33:23:33:25 | obj | tst.js:39:9:39:11 | obj |
|
||||
| tst.js:33:23:33:25 | obj | tst.js:39:9:39:11 | obj |
|
||||
| tst.js:33:23:33:25 | obj | tst.js:45:9:45:11 | obj |
|
||||
| tst.js:33:23:33:25 | obj | tst.js:45:9:45:11 | obj |
|
||||
| tst.js:33:23:33:25 | obj | tst.js:48:9:48:11 | obj |
|
||||
| tst.js:33:23:33:25 | obj | tst.js:48:9:48:11 | obj |
|
||||
#select
|
||||
| tst.js:8:5:8:17 | object[taint] | tst.js:5:24:5:37 | req.query.data | tst.js:8:5:8:17 | object[taint] | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | tst.js:5:24:5:37 | req.query.data | here |
|
||||
| tst.js:9:5:9:17 | object[taint] | tst.js:5:24:5:37 | req.query.data | tst.js:9:5:9:17 | object[taint] | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | tst.js:5:24:5:37 | req.query.data | here |
|
||||
| tst.js:14:5:14:32 | unsafeG ... taint) | tst.js:5:24:5:37 | req.query.data | tst.js:14:5:14:32 | unsafeG ... taint) | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | tst.js:5:24:5:37 | req.query.data | here |
|
||||
| tst.js:34:5:34:7 | obj | tst.js:5:24:5:37 | req.query.data | tst.js:34:5:34:7 | obj | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | tst.js:5:24:5:37 | req.query.data | here |
|
||||
| tst.js:39:9:39:11 | obj | tst.js:5:24:5:37 | req.query.data | tst.js:39:9:39:11 | obj | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | tst.js:5:24:5:37 | req.query.data | here |
|
||||
| tst.js:45:9:45:11 | obj | tst.js:5:24:5:37 | req.query.data | tst.js:45:9:45:11 | obj | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | tst.js:5:24:5:37 | req.query.data | here |
|
||||
| tst.js:48:9:48:11 | obj | tst.js:5:24:5:37 | req.query.data | tst.js:48:9:48:11 | obj | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | tst.js:5:24:5:37 | req.query.data | here |
|
||||
@@ -0,0 +1 @@
|
||||
Security/CWE-915/PrototypePollutingAssignment.ql
|
||||
@@ -0,0 +1,73 @@
|
||||
let express = require('express');
|
||||
let app = express();
|
||||
|
||||
app.get('/', (req, res) => {
|
||||
let taint = String(req.query.data);
|
||||
|
||||
let object = {};
|
||||
object[taint][taint] = taint; // NOT OK
|
||||
object[taint].foo = 'bar'; // NOT OK - may pollute, although attacker has no control over data being injected
|
||||
object.baz[taint] = taint; // OK
|
||||
|
||||
mutateObject(object[taint], 'blah');
|
||||
|
||||
unsafeGetProp(object, taint).foo = 'bar'; // NOT OK
|
||||
unsafeGetProp(object, 'safe').foo = 'bar'; // OK
|
||||
|
||||
safeGetProp(object, taint).foo = 'bar'; // OK
|
||||
|
||||
let possiblyProto = object[taint] || new Box();
|
||||
possiblyProto.m();
|
||||
|
||||
let prototypeLessObject = Object.create(null);
|
||||
prototypeLessObject[taint][taint] = taint; // OK
|
||||
|
||||
let directlyMutated = {};
|
||||
directlyMutated[taint] = taint; // OK - can't affect Object.prototype
|
||||
|
||||
if (object.hasOwnProperty(taint)) {
|
||||
object[taint].foo = 'bar'; // OK
|
||||
}
|
||||
});
|
||||
|
||||
function mutateObject(obj, x) {
|
||||
obj.foo = x; // NOT OK
|
||||
if (obj instanceof Object) {
|
||||
obj.foo = x; // OK
|
||||
}
|
||||
if (obj != null) {
|
||||
obj.foo = x; // NOT OK
|
||||
}
|
||||
if (typeof obj === 'function') {
|
||||
obj.foo = x; // OK
|
||||
}
|
||||
if (typeof obj !== 'function') {
|
||||
obj.foo = x; // NOT OK
|
||||
}
|
||||
if (typeof obj === 'object') {
|
||||
obj.foo = x; // NOT OK
|
||||
}
|
||||
if (typeof obj !== 'object') {
|
||||
obj.foo = x; // OK
|
||||
}
|
||||
}
|
||||
|
||||
function unsafeGetProp(obj, prop) {
|
||||
return obj ? obj[prop] : null;
|
||||
}
|
||||
|
||||
function safeGetProp(obj, prop) {
|
||||
if (prop === '__proto__' || prop === 'constructor') {
|
||||
return null;
|
||||
}
|
||||
return obj ? obj[prop] : null;
|
||||
}
|
||||
|
||||
class Box {
|
||||
constructor(x) {
|
||||
this.x = x;
|
||||
}
|
||||
m() {
|
||||
this.foo = 'bar'; // OK - 'this' won't refer to Object.prototype
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1 @@
|
||||
Security/CWE-915/PrototypePollutingFunction.ql
|
||||
@@ -0,0 +1 @@
|
||||
Security/CWE-915/PrototypePollutingMergeCall.ql
|
||||
Reference in New Issue
Block a user