diff --git a/javascript/ql/lib/change-notes/2022-05-09-cash.md b/javascript/ql/lib/change-notes/2022-05-09-cash.md new file mode 100644 index 00000000000..e5e0056e86c --- /dev/null +++ b/javascript/ql/lib/change-notes/2022-05-09-cash.md @@ -0,0 +1,5 @@ +--- +category: minorAnalysis +--- +* The [cash](https://github.com/fabiospampinato/cash) library is now modelled as an alias for JQuery. + Sinks and sources from cash should now be handled by all XSS queries. \ No newline at end of file diff --git a/javascript/ql/lib/semmle/javascript/frameworks/jQuery.qll b/javascript/ql/lib/semmle/javascript/frameworks/jQuery.qll index 28a01dba7ab..31d1d5b99d2 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/jQuery.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/jQuery.qll @@ -406,11 +406,11 @@ module JQuery { private class DefaultRange extends Range { DefaultRange() { - // either a reference to a global variable `$` or `jQuery` - this = DataFlow::globalVarRef(any(string jq | jq = "$" or jq = "jQuery")) + // either a reference to a global variable `$`, `jQuery`, or `cash` + this = DataFlow::globalVarRef(["$", "jQuery", "cash"]) or - // or imported from a module named `jquery` or `zepto` - this = DataFlow::moduleImport(["jquery", "zepto"]) + // or imported from a module named `jquery`, `zepto`, or `cash-dom` + this = DataFlow::moduleImport(["jquery", "zepto", "cash-dom"]) or this.hasUnderlyingType("JQueryStatic") } diff --git a/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/XssThroughDom.expected b/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/XssThroughDom.expected index cc1988e5adf..57c6899d078 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/XssThroughDom.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/XssThroughDom.expected @@ -150,6 +150,13 @@ nodes | xss-through-dom.js:131:19:131:26 | linkText | | xss-through-dom.js:132:16:132:23 | linkText | | xss-through-dom.js:132:16:132:23 | linkText | +| xss-through-dom.js:139:11:139:52 | src | +| xss-through-dom.js:139:17:139:52 | documen ... k").src | +| xss-through-dom.js:139:17:139:52 | documen ... k").src | +| xss-through-dom.js:140:19:140:21 | src | +| xss-through-dom.js:140:19:140:21 | src | +| xss-through-dom.js:141:25:141:27 | src | +| xss-through-dom.js:141:25:141:27 | src | edges | forms.js:8:23:8:28 | values | forms.js:9:31:9:36 | values | | forms.js:8:23:8:28 | values | forms.js:9:31:9:36 | values | @@ -246,6 +253,12 @@ edges | xss-through-dom.js:130:17:130:68 | wSelect ... ) \|\| '' | xss-through-dom.js:130:6:130:68 | linkText | | xss-through-dom.js:130:42:130:62 | dSelect ... tring() | xss-through-dom.js:130:17:130:62 | wSelect ... tring() | | xss-through-dom.js:130:42:130:62 | dSelect ... tring() | xss-through-dom.js:130:17:130:62 | wSelect ... tring() | +| xss-through-dom.js:139:11:139:52 | src | xss-through-dom.js:140:19:140:21 | src | +| xss-through-dom.js:139:11:139:52 | src | xss-through-dom.js:140:19:140:21 | src | +| xss-through-dom.js:139:11:139:52 | src | xss-through-dom.js:141:25:141:27 | src | +| xss-through-dom.js:139:11:139:52 | src | xss-through-dom.js:141:25:141:27 | src | +| xss-through-dom.js:139:17:139:52 | documen ... k").src | xss-through-dom.js:139:11:139:52 | src | +| xss-through-dom.js:139:17:139:52 | documen ... k").src | xss-through-dom.js:139:11:139:52 | src | #select | forms.js:9:31:9:40 | values.foo | forms.js:8:23:8:28 | values | forms.js:9:31:9:40 | values.foo | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:8:23:8:28 | values | DOM text | | forms.js:12:31:12:40 | values.bar | forms.js:11:24:11:29 | values | forms.js:12:31:12:40 | values.bar | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:11:24:11:29 | values | DOM text | @@ -287,3 +300,5 @@ edges | xss-through-dom.js:131:19:131:26 | linkText | xss-through-dom.js:130:42:130:62 | dSelect ... tring() | xss-through-dom.js:131:19:131:26 | linkText | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:130:42:130:62 | dSelect ... tring() | DOM text | | xss-through-dom.js:132:16:132:23 | linkText | xss-through-dom.js:130:17:130:37 | wSelect ... tring() | xss-through-dom.js:132:16:132:23 | linkText | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:130:17:130:37 | wSelect ... tring() | DOM text | | xss-through-dom.js:132:16:132:23 | linkText | xss-through-dom.js:130:42:130:62 | dSelect ... tring() | xss-through-dom.js:132:16:132:23 | linkText | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:130:42:130:62 | dSelect ... tring() | DOM text | +| xss-through-dom.js:140:19:140:21 | src | xss-through-dom.js:139:17:139:52 | documen ... k").src | xss-through-dom.js:140:19:140:21 | src | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:139:17:139:52 | documen ... k").src | DOM text | +| xss-through-dom.js:141:25:141:27 | src | xss-through-dom.js:139:17:139:52 | documen ... k").src | xss-through-dom.js:141:25:141:27 | src | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:139:17:139:52 | documen ... k").src | DOM text | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/xss-through-dom.js b/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/xss-through-dom.js index 8e89affa0a9..7728722bd16 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/xss-through-dom.js +++ b/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/xss-through-dom.js @@ -131,4 +131,12 @@ class Sub extends Super { elem.innerHTML = linkText; // NOT OK $("#id").html(linkText); // NOT OK elem.innerText = linkText; // OK +})(); + +const cashDom = require("cash-dom"); + +(function () { + const src = document.getElementById("#link").src; + cash("#id").html(src); // NOT OK. + cashDom("#id").html(src); // NOT OK })(); \ No newline at end of file