From de5c7efd633c166828214f7af2c992c1da8979f8 Mon Sep 17 00:00:00 2001 From: Napalys Date: Thu, 13 Mar 2025 13:03:15 +0100 Subject: [PATCH 1/2] Added test case for `unescape`. --- .../ql/lib/semmle/javascript/dataflow/TaintTracking.qll | 2 +- .../query-tests/Security/CWE-079/DomBasedXss/Xss.expected | 8 ++++++++ .../CWE-079/DomBasedXss/XssWithAdditionalSources.expected | 7 +++++++ .../test/query-tests/Security/CWE-079/DomBasedXss/tst.js | 5 +++++ 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll index 0d378a32bc5c..2dd1f622fb5b 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll @@ -494,7 +494,7 @@ module TaintTracking { succ = c and c = DataFlow::globalVarRef([ - "encodeURI", "decodeURI", "encodeURIComponent", "decodeURIComponent" + "encodeURI", "decodeURI", "encodeURIComponent", "decodeURIComponent", "unescape" ]).getACall() and pred = c.getArgument(0) ) diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected index 2e72b292f72d..7de1561f79e8 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected @@ -223,6 +223,7 @@ | tst.js:477:18:477:40 | locatio ... bstr(1) | tst.js:477:18:477:30 | location.hash | tst.js:477:18:477:40 | locatio ... bstr(1) | Cross-site scripting vulnerability due to $@. | tst.js:477:18:477:30 | location.hash | user-provided value | | tst.js:484:33:484:63 | decodeU ... n.hash) | tst.js:484:43:484:62 | window.location.hash | tst.js:484:33:484:63 | decodeU ... n.hash) | Cross-site scripting vulnerability due to $@. | tst.js:484:43:484:62 | window.location.hash | user-provided value | | tst.js:492:18:492:54 | target. ... "), '') | tst.js:491:16:491:39 | documen ... .search | tst.js:492:18:492:54 | target. ... "), '') | Cross-site scripting vulnerability due to $@. | tst.js:491:16:491:39 | documen ... .search | user-provided value | +| tst.js:499:18:499:33 | unescape(source) | tst.js:498:16:498:26 | window.name | tst.js:499:18:499:33 | unescape(source) | Cross-site scripting vulnerability due to $@. | tst.js:498:16:498:26 | window.name | user-provided value | | typeahead.js:25:18:25:20 | val | typeahead.js:20:22:20:45 | documen ... .search | typeahead.js:25:18:25:20 | val | Cross-site scripting vulnerability due to $@. | typeahead.js:20:22:20:45 | documen ... .search | user-provided value | | v-html.vue:2:8:2:23 | v-html=tainted | v-html.vue:6:42:6:58 | document.location | v-html.vue:2:8:2:23 | v-html=tainted | Cross-site scripting vulnerability due to $@. | v-html.vue:6:42:6:58 | document.location | user-provided value | | various-concat-obfuscations.js:4:4:4:31 | "
" ...
" | various-concat-obfuscations.js:2:16:2:39 | documen ... .search | various-concat-obfuscations.js:4:4:4:31 | "
" ...
" | Cross-site scripting vulnerability due to $@. | various-concat-obfuscations.js:2:16:2:39 | documen ... .search | user-provided value | @@ -745,6 +746,9 @@ edges | tst.js:491:7:491:39 | target | tst.js:492:18:492:23 | target | provenance | | | tst.js:491:16:491:39 | documen ... .search | tst.js:491:7:491:39 | target | provenance | | | tst.js:492:18:492:23 | target | tst.js:492:18:492:54 | target. ... "), '') | provenance | | +| tst.js:498:7:498:26 | source | tst.js:499:27:499:32 | source | provenance | | +| tst.js:498:16:498:26 | window.name | tst.js:498:7:498:26 | source | provenance | | +| tst.js:499:27:499:32 | source | tst.js:499:18:499:33 | unescape(source) | provenance | | | typeahead.js:20:13:20:45 | target | typeahead.js:21:12:21:17 | target | provenance | | | typeahead.js:20:22:20:45 | documen ... .search | typeahead.js:20:13:20:45 | target | provenance | | | typeahead.js:21:12:21:17 | target | typeahead.js:24:30:24:32 | val | provenance | | @@ -1397,6 +1401,10 @@ nodes | tst.js:491:16:491:39 | documen ... .search | semmle.label | documen ... .search | | tst.js:492:18:492:23 | target | semmle.label | target | | tst.js:492:18:492:54 | target. ... "), '') | semmle.label | target. ... "), '') | +| tst.js:498:7:498:26 | source | semmle.label | source | +| tst.js:498:16:498:26 | window.name | semmle.label | window.name | +| tst.js:499:18:499:33 | unescape(source) | semmle.label | unescape(source) | +| tst.js:499:27:499:32 | source | semmle.label | source | | typeahead.js:20:13:20:45 | target | semmle.label | target | | typeahead.js:20:22:20:45 | documen ... .search | semmle.label | documen ... .search | | typeahead.js:21:12:21:17 | target | semmle.label | target | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected index 132189a22f36..eb961fc83dbf 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected @@ -607,6 +607,10 @@ nodes | tst.js:491:16:491:39 | documen ... .search | semmle.label | documen ... .search | | tst.js:492:18:492:23 | target | semmle.label | target | | tst.js:492:18:492:54 | target. ... "), '') | semmle.label | target. ... "), '') | +| tst.js:498:7:498:26 | source | semmle.label | source | +| tst.js:498:16:498:26 | window.name | semmle.label | window.name | +| tst.js:499:18:499:33 | unescape(source) | semmle.label | unescape(source) | +| tst.js:499:27:499:32 | source | semmle.label | source | | typeahead.js:9:28:9:30 | loc | semmle.label | loc | | typeahead.js:10:16:10:18 | loc | semmle.label | loc | | typeahead.js:20:13:20:45 | target | semmle.label | target | @@ -1186,6 +1190,9 @@ edges | tst.js:491:7:491:39 | target | tst.js:492:18:492:23 | target | provenance | | | tst.js:491:16:491:39 | documen ... .search | tst.js:491:7:491:39 | target | provenance | | | tst.js:492:18:492:23 | target | tst.js:492:18:492:54 | target. ... "), '') | provenance | | +| tst.js:498:7:498:26 | source | tst.js:499:27:499:32 | source | provenance | | +| tst.js:498:16:498:26 | window.name | tst.js:498:7:498:26 | source | provenance | | +| tst.js:499:27:499:32 | source | tst.js:499:18:499:33 | unescape(source) | provenance | | | typeahead.js:9:28:9:30 | loc | typeahead.js:10:16:10:18 | loc | provenance | | | typeahead.js:20:13:20:45 | target | typeahead.js:21:12:21:17 | target | provenance | | | typeahead.js:20:22:20:45 | documen ... .search | typeahead.js:20:13:20:45 | target | provenance | | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/tst.js b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/tst.js index a92e6e954909..0ecc2535272d 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/tst.js +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/tst.js @@ -493,3 +493,8 @@ function nonGlobalSanitizer() { $("#foo").html(target.replace(new RegExp("<|>", unknownFlags()), '')); // OK - most likely good. We don't know what the flags are. $("#foo").html(target.replace(new RegExp("<|>", "g"), '')); } + +function FooBar() { + let source = window.name; // $ Source + $('myId').html(unescape(source)) // $ Alert +} From 0df2069575554608272071997984c7502a74e6f1 Mon Sep 17 00:00:00 2001 From: Napalys Date: Thu, 13 Mar 2025 13:08:14 +0100 Subject: [PATCH 2/2] Added change note. --- javascript/ql/lib/change-notes/2025-03-13-unescape.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 javascript/ql/lib/change-notes/2025-03-13-unescape.md diff --git a/javascript/ql/lib/change-notes/2025-03-13-unescape.md b/javascript/ql/lib/change-notes/2025-03-13-unescape.md new file mode 100644 index 000000000000..aa2d445118cb --- /dev/null +++ b/javascript/ql/lib/change-notes/2025-03-13-unescape.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Added taint-steps for `unescape()`.