Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ffbbb80

Browse files
author
Esben Sparre Andreasen
committed
JS: avoid flagging early returns in js/user-controlled-bypass
1 parent 6a03bd8 commit ffbbb80

4 files changed

Lines changed: 60 additions & 2 deletions

File tree

change-notes/1.19/analysis-javascript.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
| Remote property injection | Fewer results | The precision of this rule has been revised to "medium". Results are no longer shown on LGTM by default. |
3434
| Missing CSRF middleware | Fewer false-positive results | This rule now recognizes additional CSRF protection middlewares. |
3535
| Server-side URL redirect | More results | This rule now recognizes redirection calls in more cases. |
36+
| User-controlled bypass of security check | Fewer results | This rule no longer flags conditions that guard early returns. The precision of this rule has been revised to "medium". Results are no longer shown on LGTM by default. |
3637
| Whitespace contradicts operator precedence | Fewer false-positive results | This rule no longer flags operators with asymmetric whitespace. |
3738

3839
## Changes to QL libraries

javascript/ql/src/Security/CWE-807/ConditionalBypass.ql

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* @description Conditions that the user controls are not suited for making security-related decisions.
44
* @kind problem
55
* @problem.severity error
6-
* @precision high
6+
* @precision medium
77
* @id js/user-controlled-bypass
88
* @tags security
99
* external/cwe/cwe-807
@@ -83,8 +83,32 @@ predicate isTaintedGuardForSensitiveAction(Sink sink, DataFlow::Node source, Sen
8383
)
8484
}
8585

86+
/**
87+
* Holds if `e` effectively guards access to `action` by returning or throwing early.
88+
*
89+
* Example: `if (e) return; action(x)`.
90+
*/
91+
predicate isEarlyAbortGuard(Sink e, SensitiveAction action) {
92+
exists (IfStmt guard |
93+
// `e` is in the condition of an if-statement ...
94+
e.asExpr().getParentExpr*() = guard.getCondition() and
95+
// ... where the then-branch always throws or returns
96+
exists (Stmt abort |
97+
abort instanceof ThrowStmt or
98+
abort instanceof ReturnStmt |
99+
abort.nestedIn(guard) and
100+
abort.getBasicBlock().(ReachableBasicBlock).postDominates(guard.getThen().getBasicBlock() )
101+
) and
102+
// ... and the else-branch does not exist
103+
not exists (guard.getElse()) |
104+
// ... and `action` is outside the if-statement
105+
not action.asExpr().getEnclosingStmt().nestedIn(guard)
106+
)
107+
}
108+
86109
from DataFlow::Node source, DataFlow::Node sink, SensitiveAction action
87-
where isTaintedGuardForSensitiveAction(sink, source, action)
110+
where isTaintedGuardForSensitiveAction(sink, source, action) and
111+
not isEarlyAbortGuard(sink, action)
88112
select sink, "This condition guards a sensitive $@, but $@ controls it.",
89113
action, "action",
90114
source, "a user-provided value"

javascript/ql/test/query-tests/Security/CWE-807/ConditionalBypass.expected

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@
1010
| tst.js:76:9:76:10 | v1 | This condition guards a sensitive $@, but $@ controls it. | tst.js:78:9:78:22 | process.exit() | action | tst.js:75:14:75:24 | req.cookies | a user-provided value |
1111
| tst.js:76:9:76:10 | v1 | This condition guards a sensitive $@, but $@ controls it. | tst.js:78:9:78:22 | process.exit() | action | tst.js:75:39:75:58 | req.params.requestId | a user-provided value |
1212
| tst.js:90:9:90:41 | req.coo ... secret" | This condition guards a sensitive $@, but $@ controls it. | tst.js:92:9:92:22 | process.exit() | action | tst.js:90:9:90:19 | req.cookies | a user-provided value |
13+
| tst.js:111:13:111:32 | req.query.vulnerable | This condition guards a sensitive $@, but $@ controls it. | tst.js:114:9:114:16 | verify() | action | tst.js:111:13:111:32 | req.query.vulnerable | a user-provided value |
14+
| tst.js:118:13:118:32 | req.query.vulnerable | This condition guards a sensitive $@, but $@ controls it. | tst.js:121:13:121:20 | verify() | action | tst.js:118:13:118:32 | req.query.vulnerable | a user-provided value |

javascript/ql/test/query-tests/Security/CWE-807/tst.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,34 @@ app.get('/user/:id', function(req, res) {
9999
console.log(commit.author().toString());
100100
}
101101
});
102+
103+
app.get('/user/:id', function(req, res) {
104+
if (!req.body || !username || !password || riskAssessnment == null) { // OK: early return below
105+
res.status(400).send({ error: '...', id: '...' });
106+
return
107+
}
108+
customerLogin.customerLogin(username, password, riskAssessment, clientIpAddress);
109+
110+
while (!verified) {
111+
if (req.query.vulnerable) { // NOT OK
112+
break;
113+
}
114+
verify();
115+
}
116+
117+
while (!verified) {
118+
if (req.query.vulnerable) { // NOT OK
119+
break;
120+
} else {
121+
verify();
122+
}
123+
}
124+
125+
while (!verified) {
126+
if (req.query.vulnerable) { // OK: early return
127+
return;
128+
}
129+
verify();
130+
}
131+
132+
});

0 commit comments

Comments
 (0)