@@ -12,15 +12,39 @@ module ExceptionXss {
1212 import Xss as Xss
1313 private import semmle.javascript.dataflow.InferredTypes
1414
15+ /**
16+ * Gets the name of a method that does not leak taint from its arguments if an exception is thrown by the method.
17+ */
18+ private string getAnUnlikelyToThrowMethodName ( ) {
19+ result = "getElementById" or
20+ result = "indexOf" or
21+ result = "stringify" or
22+ result = "assign" or
23+ // fs methods. (The callback argument to the async functions are vulnerable, but its unlikely that the callback is the user-controlled part).
24+ result = "existsSync" or
25+ result = "exists" or
26+ result = "writeFileSync" or
27+ result = "writeFile" or
28+ result = "appendFile" or
29+ result = "appendFileSync" or
30+ result = "pick" or
31+ // log.info etc.
32+ result = "info" or
33+ result = "warn" or
34+ result = "error" or
35+ result = "join" or
36+ result = "val" or // $.val
37+ result = "parse" or // JSON.parse
38+ result = "push" or // Array.prototype.push
39+ result = "test" // RegExp.prototype.test
40+ }
41+
1542 /**
1643 * Holds if `node` is unlikely to cause an exception containing sensitive information to be thrown.
1744 */
1845 private predicate isUnlikelyToThrowSensitiveInformation ( DataFlow:: Node node ) {
19- node = any ( DataFlow:: CallNode call | call .getCalleeName ( ) = "getElementById" ) .getAnArgument ( )
20- or
21- node = any ( DataFlow:: CallNode call | call .getCalleeName ( ) = "indexOf" ) .getAnArgument ( )
22- or
23- node = any ( DataFlow:: CallNode call | call .getCalleeName ( ) = "stringify" ) .getAnArgument ( )
46+ node = any ( DataFlow:: CallNode call | call .getCalleeName ( ) = getAnUnlikelyToThrowMethodName ( ) )
47+ .getAnArgument ( )
2448 or
2549 node = DataFlow:: globalVarRef ( "console" ) .getAMemberCall ( _) .getAnArgument ( )
2650 }
@@ -38,6 +62,7 @@ module ExceptionXss {
3862 */
3963 predicate canThrowSensitiveInformation ( DataFlow:: Node node ) {
4064 not isUnlikelyToThrowSensitiveInformation ( node ) and
65+ not node instanceof Xss:: Shared:: Sink and // removes duplicates from js/xss.
4166 (
4267 // in the case of reflective calls the below ensures that both InvokeNodes have no known callee.
4368 forex ( DataFlow:: InvokeNode call | call .getAnArgument ( ) = node | not exists ( call .getACallee ( ) ) )
@@ -79,15 +104,15 @@ module ExceptionXss {
79104 }
80105
81106 /**
82- * Get the parameter in the callback that contains an error.
107+ * Get the parameter in the callback that contains an error.
83108 * In the current implementation this is always the first parameter.
84109 */
85110 DataFlow:: Node getErrorParam ( ) { result = errorParameter }
86111 }
87112
88113 /**
89- * Gets the error parameter for a callback that is supplied to the same call as `pred` is an argument to.
90- * For example: `outerCall(foo, <pred>, bar, (<result>, val) => { ... })`.
114+ * Gets the error parameter for a callback that is supplied to the same call as `pred` is an argument to.
115+ * For example: `outerCall(foo, <pred>, bar, (<result>, val) => { ... })`.
91116 */
92117 DataFlow:: Node getCallbackErrorParam ( DataFlow:: Node pred ) {
93118 exists ( DataFlow:: CallNode call , Callback callback |
@@ -101,8 +126,8 @@ module ExceptionXss {
101126 /**
102127 * Gets the data-flow node to which any exceptions thrown by
103128 * this expression will propagate.
104- * This predicate adds, on top of `Expr::getExceptionTarget`, exceptions
105- * propagated by callbacks.
129+ * This predicate adds, on top of `Expr::getExceptionTarget`, exceptions
130+ * propagated by callbacks.
106131 */
107132 private DataFlow:: Node getExceptionTarget ( DataFlow:: Node pred ) {
108133 result = pred .asExpr ( ) .getExceptionTarget ( )
0 commit comments