|
3 | 3 | * @description Conditions that the user controls are not suited for making security-related decisions. |
4 | 4 | * @kind problem |
5 | 5 | * @problem.severity error |
6 | | - * @precision high |
| 6 | + * @precision medium |
7 | 7 | * @id js/user-controlled-bypass |
8 | 8 | * @tags security |
9 | 9 | * external/cwe/cwe-807 |
@@ -83,8 +83,32 @@ predicate isTaintedGuardForSensitiveAction(Sink sink, DataFlow::Node source, Sen |
83 | 83 | ) |
84 | 84 | } |
85 | 85 |
|
| 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 | + |
86 | 109 | 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) |
88 | 112 | select sink, "This condition guards a sensitive $@, but $@ controls it.", |
89 | 113 | action, "action", |
90 | 114 | source, "a user-provided value" |
0 commit comments