@@ -12,15 +12,33 @@ 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 // document.getElementById
20+ result = "indexOf" or // String.prototype.indexOf
21+ result = "assign" or // Object.assign
22+ result = "pick" or // _.pick
23+ result = getAStandardLoggerMethodName ( ) or // log.info etc.
24+ result = "val" or // $.val
25+ result = "parse" or // JSON.parse
26+ result = "stringify" or // JSON.stringify
27+ result = "test" or // RegExp.prototype.test
28+ result = "setItem" or // localStorage.setItem
29+ result = "existsSync" or
30+ // the "fs" methods are a mix of "this is safe" and "you have bigger problems".
31+ exists ( ExternalMemberDecl decl | decl .hasQualifiedName ( "fs" , result ) ) or
32+ // Array methods are generally exception safe.
33+ exists ( ExternalMemberDecl decl | decl .hasQualifiedName ( "Array" , result ) )
34+ }
35+
1536 /**
1637 * Holds if `node` is unlikely to cause an exception containing sensitive information to be thrown.
1738 */
1839 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 ( )
40+ node = any ( DataFlow:: CallNode call | call .getCalleeName ( ) = getAnUnlikelyToThrowMethodName ( ) )
41+ .getAnArgument ( )
2442 or
2543 node = DataFlow:: globalVarRef ( "console" ) .getAMemberCall ( _) .getAnArgument ( )
2644 }
@@ -38,6 +56,7 @@ module ExceptionXss {
3856 */
3957 predicate canThrowSensitiveInformation ( DataFlow:: Node node ) {
4058 not isUnlikelyToThrowSensitiveInformation ( node ) and
59+ not node instanceof Xss:: Shared:: Sink and // removes duplicates from js/xss.
4160 (
4261 // in the case of reflective calls the below ensures that both InvokeNodes have no known callee.
4362 forex ( DataFlow:: InvokeNode call | call .getAnArgument ( ) = node | not exists ( call .getACallee ( ) ) )
@@ -79,15 +98,15 @@ module ExceptionXss {
7998 }
8099
81100 /**
82- * Get the parameter in the callback that contains an error.
101+ * Gets the parameter in the callback that contains an error.
83102 * In the current implementation this is always the first parameter.
84103 */
85104 DataFlow:: Node getErrorParam ( ) { result = errorParameter }
86105 }
87106
88107 /**
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) => { ... })`.
108+ * Gets the error parameter for a callback that is supplied to the same call as `pred` is an argument to.
109+ * For example: `outerCall(foo, <pred>, bar, (<result>, val) => { ... })`.
91110 */
92111 DataFlow:: Node getCallbackErrorParam ( DataFlow:: Node pred ) {
93112 exists ( DataFlow:: CallNode call , Callback callback |
@@ -101,8 +120,8 @@ module ExceptionXss {
101120 /**
102121 * Gets the data-flow node to which any exceptions thrown by
103122 * this expression will propagate.
104- * This predicate adds, on top of `Expr::getExceptionTarget`, exceptions
105- * propagated by callbacks.
123+ * This predicate adds, on top of `Expr::getExceptionTarget`, exceptions
124+ * propagated by callbacks.
106125 */
107126 private DataFlow:: Node getExceptionTarget ( DataFlow:: Node pred ) {
108127 result = pred .asExpr ( ) .getExceptionTarget ( )
0 commit comments