From 8599ab25036a7483df432de55f6a457840ade994 Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 11 Mar 2025 12:47:16 +0100 Subject: [PATCH 1/2] JS: Fix attributes nodes missing an enclosing callable --- .../dataflow/internal/DataFlowPrivate.qll | 18 +++++++++++++++--- .../Security/CWE-079/DomBasedXss/Xss.expected | 4 ++++ .../XssWithAdditionalSources.expected | 3 +++ .../Security/CWE-079/DomBasedXss/v-html.vue | 4 ++-- 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll index 4b82d895f642..2fcc2acbd167 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll @@ -372,10 +372,11 @@ class CastNode extends DataFlow::Node { cached newtype TDataFlowCallable = MkSourceCallable(StmtContainer container) or - MkLibraryCallable(LibraryCallable callable) + MkLibraryCallable(LibraryCallable callable) or + MkFileCallable(File file) /** - * A callable entity. This is a wrapper around either a `StmtContainer` or a `LibraryCallable`. + * A callable entity. This is a wrapper around either a `StmtContainer`, `LibraryCallable`, or `File`. */ class DataFlowCallable extends TDataFlowCallable { /** Gets a string representation of this callable. */ @@ -383,14 +384,21 @@ class DataFlowCallable extends TDataFlowCallable { result = this.asSourceCallable().toString() or result = this.asLibraryCallable() + or + result = this.asFileCallable().toString() } /** Gets the location of this callable, if it is present in the source code. */ - Location getLocation() { result = this.asSourceCallable().getLocation() } + Location getLocation() { + result = this.asSourceCallable().getLocation() or result = this.asFileCallable().getLocation() + } /** Gets the corresponding `StmtContainer` if this is a source callable. */ StmtContainer asSourceCallable() { this = MkSourceCallable(result) } + /** Gets the corresponding `File` if this is a file representing a callable. */ + File asFileCallable() { this = MkFileCallable(result) } + /** Gets the corresponding `StmtContainer` if this is a source callable. */ pragma[nomagic] StmtContainer asSourceCallableNotExterns() { @@ -537,6 +545,10 @@ DataFlowCallable nodeGetEnclosingCallable(Node node) { result.asLibraryCallable() = node.(FlowSummaryDefaultExceptionalReturn).getSummarizedCallable() or node = TGenericSynthesizedNode(_, _, result) + or + node instanceof DataFlow::HtmlAttributeNode and result.asFileCallable() = node.getFile() + or + node instanceof DataFlow::XmlAttributeNode and result.asFileCallable() = node.getFile() } newtype TDataFlowType = 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 de03bca13d4b..2e72b292f72d 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 @@ -224,6 +224,7 @@ | 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 | | 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 | | various-concat-obfuscations.js:5:4:5:26 | `
$ ...
` | various-concat-obfuscations.js:2:16:2:39 | documen ... .search | various-concat-obfuscations.js:5:4:5:26 | `
$ ...
` | Cross-site scripting vulnerability due to $@. | various-concat-obfuscations.js:2:16:2:39 | documen ... .search | user-provided value | | various-concat-obfuscations.js:6:4:6:43 | "
" ... /div>") | various-concat-obfuscations.js:2:16:2:39 | documen ... .search | various-concat-obfuscations.js:6:4:6:43 | "
" ... /div>") | Cross-site scripting vulnerability due to $@. | various-concat-obfuscations.js:2:16:2:39 | documen ... .search | user-provided value | @@ -748,6 +749,7 @@ edges | 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 | | | typeahead.js:24:30:24:32 | val | typeahead.js:25:18:25:20 | val | provenance | | +| v-html.vue:6:42:6:58 | document.location | v-html.vue:2:8:2:23 | v-html=tainted | provenance | | | various-concat-obfuscations.js:2:6:2:39 | tainted | various-concat-obfuscations.js:4:14:4:20 | tainted | provenance | | | various-concat-obfuscations.js:2:6:2:39 | tainted | various-concat-obfuscations.js:5:12:5:18 | tainted | provenance | | | various-concat-obfuscations.js:2:6:2:39 | tainted | various-concat-obfuscations.js:6:19:6:25 | tainted | provenance | | @@ -1400,6 +1402,8 @@ nodes | typeahead.js:21:12:21:17 | target | semmle.label | target | | typeahead.js:24:30:24:32 | val | semmle.label | val | | typeahead.js:25:18:25:20 | val | semmle.label | val | +| v-html.vue:2:8:2:23 | v-html=tainted | semmle.label | v-html=tainted | +| v-html.vue:6:42:6:58 | document.location | semmle.label | document.location | | various-concat-obfuscations.js:2:6:2:39 | tainted | semmle.label | tainted | | various-concat-obfuscations.js:2:16:2:39 | documen ... .search | semmle.label | documen ... .search | | various-concat-obfuscations.js:4:4:4:31 | "
" ...
" | semmle.label | "
" ...
" | 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 62627ff7ceba..132189a22f36 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 @@ -614,6 +614,8 @@ nodes | typeahead.js:21:12:21:17 | target | semmle.label | target | | typeahead.js:24:30:24:32 | val | semmle.label | val | | typeahead.js:25:18:25:20 | val | semmle.label | val | +| v-html.vue:2:8:2:23 | v-html=tainted | semmle.label | v-html=tainted | +| v-html.vue:6:42:6:58 | document.location | semmle.label | document.location | | various-concat-obfuscations.js:2:6:2:39 | tainted | semmle.label | tainted | | various-concat-obfuscations.js:2:16:2:39 | documen ... .search | semmle.label | documen ... .search | | various-concat-obfuscations.js:4:4:4:31 | "
" ...
" | semmle.label | "
" ...
" | @@ -1189,6 +1191,7 @@ edges | 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 | | | typeahead.js:24:30:24:32 | val | typeahead.js:25:18:25:20 | val | provenance | | +| v-html.vue:6:42:6:58 | document.location | v-html.vue:2:8:2:23 | v-html=tainted | provenance | | | various-concat-obfuscations.js:2:6:2:39 | tainted | various-concat-obfuscations.js:4:14:4:20 | tainted | provenance | | | various-concat-obfuscations.js:2:6:2:39 | tainted | various-concat-obfuscations.js:5:12:5:18 | tainted | provenance | | | various-concat-obfuscations.js:2:6:2:39 | tainted | various-concat-obfuscations.js:6:19:6:25 | tainted | provenance | | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/v-html.vue b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/v-html.vue index 3964d4adad36..d75413a527b2 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/v-html.vue +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/v-html.vue @@ -1,9 +1,9 @@