Skip to content

Commit 6738270

Browse files
authored
Merge pull request #8229 from erik-krogh/parenSan
JS: step through parentheses in barrier functions
2 parents 59aedc2 + 9c5f3e9 commit 6738270

File tree

3 files changed

+49
-13
lines changed

3 files changed

+49
-13
lines changed

javascript/ql/lib/semmle/javascript/dataflow/Configuration.qll

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1977,20 +1977,26 @@ module PathGraph {
19771977
}
19781978

19791979
/**
1980-
* Gets an operand of the given `&&` operator.
1981-
*
1982-
* We use this to construct the transitive closure over a relation
1983-
* that does not include all of `BinaryExpr.getAnOperand`.
1980+
* Gets a logical `and` expression, or parenthesized expression, that contains `guard`.
19841981
*/
1985-
private Expr getALogicalAndOperand(LogAndExpr e) { result = e.getAnOperand() }
1982+
private Expr getALogicalAndParent(BarrierGuardNode guard) {
1983+
barrierGuardIsRelevant(guard) and result = guard.asExpr()
1984+
or
1985+
result.(LogAndExpr).getAnOperand() = getALogicalAndParent(guard)
1986+
or
1987+
result.getUnderlyingValue() = getALogicalAndParent(guard)
1988+
}
19861989

19871990
/**
1988-
* Gets an operand of the given `||` operator.
1989-
*
1990-
* We use this to construct the transitive closure over a relation
1991-
* that does not include all of `BinaryExpr.getAnOperand`.
1991+
* Gets a logical `or` expression, or parenthesized expression, that contains `guard`.
19921992
*/
1993-
private Expr getALogicalOrOperand(LogOrExpr e) { result = e.getAnOperand() }
1993+
private Expr getALogicalOrParent(BarrierGuardNode guard) {
1994+
barrierGuardIsRelevant(guard) and result = guard.asExpr()
1995+
or
1996+
result.(LogOrExpr).getAnOperand() = getALogicalOrParent(guard)
1997+
or
1998+
result.getUnderlyingValue() = getALogicalOrParent(guard)
1999+
}
19942000

19952001
/**
19962002
* A `BarrierGuardNode` that controls which data flow
@@ -2020,10 +2026,10 @@ private class BarrierGuardFunction extends Function {
20202026
returnExpr = guard.asExpr()
20212027
or
20222028
// ad hoc support for conjunctions:
2023-
getALogicalAndOperand+(returnExpr) = guard.asExpr() and guardOutcome = true
2029+
getALogicalAndParent(guard) = returnExpr and guardOutcome = true
20242030
or
20252031
// ad hoc support for disjunctions:
2026-
getALogicalOrOperand+(returnExpr) = guard.asExpr() and guardOutcome = false
2032+
getALogicalOrParent(guard) = returnExpr and guardOutcome = false
20272033
|
20282034
exists(SsaExplicitDefinition ssa |
20292035
ssa.getDef().getSource() = returnExpr and

javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingAssignment/PrototypePollutingAssignment.expected

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,12 @@ nodes
8888
| lib.js:92:3:92:12 | maybeProto |
8989
| lib.js:95:3:95:12 | maybeProto |
9090
| lib.js:95:3:95:12 | maybeProto |
91+
| lib.js:104:7:104:24 | one |
92+
| lib.js:104:13:104:24 | arguments[1] |
93+
| lib.js:104:13:104:24 | arguments[1] |
94+
| lib.js:108:3:108:10 | obj[one] |
95+
| lib.js:108:3:108:10 | obj[one] |
96+
| lib.js:108:7:108:9 | one |
9197
| tst.js:5:9:5:38 | taint |
9298
| tst.js:5:17:5:38 | String( ... y.data) |
9399
| tst.js:5:24:5:37 | req.query.data |
@@ -219,6 +225,11 @@ edges
219225
| lib.js:91:7:91:28 | maybeProto | lib.js:95:3:95:12 | maybeProto |
220226
| lib.js:91:20:91:28 | obj[path] | lib.js:91:7:91:28 | maybeProto |
221227
| lib.js:91:24:91:27 | path | lib.js:91:20:91:28 | obj[path] |
228+
| lib.js:104:7:104:24 | one | lib.js:108:7:108:9 | one |
229+
| lib.js:104:13:104:24 | arguments[1] | lib.js:104:7:104:24 | one |
230+
| lib.js:104:13:104:24 | arguments[1] | lib.js:104:7:104:24 | one |
231+
| lib.js:108:7:108:9 | one | lib.js:108:3:108:10 | obj[one] |
232+
| lib.js:108:7:108:9 | one | lib.js:108:3:108:10 | obj[one] |
222233
| tst.js:5:9:5:38 | taint | tst.js:8:12:8:16 | taint |
223234
| tst.js:5:9:5:38 | taint | tst.js:9:12:9:16 | taint |
224235
| tst.js:5:9:5:38 | taint | tst.js:12:25:12:29 | taint |
@@ -272,6 +283,7 @@ edges
272283
| lib.js:42:3:42:14 | obj[path[0]] | lib.js:40:14:40:20 | args[1] | lib.js:42:3:42:14 | obj[path[0]] | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | lib.js:40:14:40:20 | args[1] | library input |
273284
| lib.js:70:13:70:24 | obj[path[0]] | lib.js:59:18:59:18 | s | lib.js:70:13:70:24 | obj[path[0]] | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | lib.js:59:18:59:18 | s | library input |
274285
| lib.js:87:10:87:14 | proto | lib.js:83:14:83:25 | arguments[1] | lib.js:87:10:87:14 | proto | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | lib.js:83:14:83:25 | arguments[1] | library input |
286+
| lib.js:108:3:108:10 | obj[one] | lib.js:104:13:104:24 | arguments[1] | lib.js:108:3:108:10 | obj[one] | This assignment may alter Object.prototype if a malicious '__proto__' string is injected from $@. | lib.js:104:13:104:24 | arguments[1] | library input |
275287
| 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 | user controlled input |
276288
| 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 | user controlled input |
277289
| 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 | user controlled input |

javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingAssignment/lib.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,22 @@ module.exports.fixedProp = function (obj, path, value) {
9393

9494
var i = 0;
9595
maybeProto[i + 2] = value; // OK - number properties are OK.
96-
}
96+
}
97+
98+
function isPossibilityOfPrototypePollution(key) {
99+
return (key === '__proto__' || key === 'constructor');
100+
}
101+
102+
module.exports.sanWithFcuntion = function() {
103+
var obj = arguments[0];
104+
var one = arguments[1];
105+
var two = arguments[2];
106+
var value = arguments[3];
107+
108+
obj[one][two] = value; // NOT OK
109+
110+
if (isPossibilityOfPrototypePollution(one) || isPossibilityOfPrototypePollution(two)) {
111+
throw new Error('Prototype pollution is not allowed');
112+
}
113+
obj[one][two] = value; // OK
114+
}

0 commit comments

Comments
 (0)