From 25962a9ba6dbe776cb12a78ecbd66ef4ad785bc1 Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 5 Oct 2023 09:23:45 +0200 Subject: [PATCH] JS: Port TemplateObjectInjection --- .../dataflow/TemplateObjectInjectionQuery.qll | 41 ++++++- .../CWE-073/TemplateObjectInjection.ql | 7 +- .../CWE-073/TemplateObjectInjection.expected | 116 ++++++------------ 3 files changed, 81 insertions(+), 83 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/TemplateObjectInjectionQuery.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/TemplateObjectInjectionQuery.qll index 22bb06e4af3..0d3c7657810 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/TemplateObjectInjectionQuery.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/TemplateObjectInjectionQuery.qll @@ -14,7 +14,46 @@ private import semmle.javascript.security.TaintedObject /** * A taint tracking configuration for reasoning about template object injection vulnerabilities. */ -class TemplateObjInjectionConfig extends TaintTracking::Configuration { +module TemplateObjectInjectionConfig implements DataFlow::StateConfigSig { + class FlowState = DataFlow::FlowLabel; + + predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) { + source.(Source).getAFlowLabel() = label + } + + predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel label) { + sink instanceof Sink and label = TaintedObject::label() + } + + predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer } + + predicate isBarrier(DataFlow::Node node, DataFlow::FlowLabel label) { + TaintTracking::defaultSanitizer(node) and + label.isTaint() + or + node = TaintedObject::SanitizerGuard::getABarrierNode(label) + } + + predicate isAdditionalFlowStep( + DataFlow::Node src, DataFlow::FlowLabel inlbl, DataFlow::Node trg, DataFlow::FlowLabel outlbl + ) { + TaintedObject::step(src, trg, inlbl, outlbl) + or + inlbl.isTaint() and + TaintTracking::defaultTaintStep(src, trg) and + inlbl = outlbl + } +} + +/** + * Taint tracking for reasoning about template object injection vulnerabilities. + */ +module TemplateObjectInjectionFlow = DataFlow::GlobalWithState; + +/** + * DEPRECATED. Use the `TemplateObjectInjectionFlow` module instead. + */ +deprecated class TemplateObjInjectionConfig extends TaintTracking::Configuration { TemplateObjInjectionConfig() { this = "TemplateObjInjectionConfig" } override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) { diff --git a/javascript/ql/src/Security/CWE-073/TemplateObjectInjection.ql b/javascript/ql/src/Security/CWE-073/TemplateObjectInjection.ql index 68ef1b12c79..1db62b2e7f0 100644 --- a/javascript/ql/src/Security/CWE-073/TemplateObjectInjection.ql +++ b/javascript/ql/src/Security/CWE-073/TemplateObjectInjection.ql @@ -12,10 +12,11 @@ */ import javascript -import DataFlow::PathGraph import semmle.javascript.security.dataflow.TemplateObjectInjectionQuery +import DataFlow::DeduplicatePathGraph -from DataFlow::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink -where cfg.hasFlowPath(source, sink) +from PathNode source, PathNode sink +where + TemplateObjectInjectionFlow::flowPath(source.getAnOriginalPathNode(), sink.getAnOriginalPathNode()) select sink.getNode(), source, sink, "Template object depends on a $@.", source.getNode(), "user-provided value" diff --git a/javascript/ql/test/query-tests/Security/CWE-073/TemplateObjectInjection.expected b/javascript/ql/test/query-tests/Security/CWE-073/TemplateObjectInjection.expected index eee80b29592..3ba1cc1d2d9 100644 --- a/javascript/ql/test/query-tests/Security/CWE-073/TemplateObjectInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-073/TemplateObjectInjection.expected @@ -1,112 +1,70 @@ nodes -| routes.js:2:23:2:30 | req.body | -| routes.js:2:23:2:30 | req.body | -| routes.js:2:23:2:30 | req.body | -| tst2.js:6:9:6:46 | bodyParameter | -| tst2.js:6:25:6:32 | req.body | -| tst2.js:6:25:6:32 | req.body | -| tst2.js:6:25:6:46 | req.bod ... rameter | -| tst2.js:7:28:7:40 | bodyParameter | -| tst2.js:7:28:7:40 | bodyParameter | -| tst2.js:26:9:26:46 | bodyParameter | -| tst2.js:26:25:26:32 | req.body | -| tst2.js:26:25:26:32 | req.body | -| tst2.js:26:25:26:46 | req.bod ... rameter | -| tst2.js:27:28:27:40 | bodyParameter | -| tst2.js:27:28:27:40 | bodyParameter | -| tst2.js:34:9:34:46 | bodyParameter | -| tst2.js:34:25:34:32 | req.body | -| tst2.js:34:25:34:32 | req.body | -| tst2.js:34:25:34:46 | req.bod ... rameter | -| tst2.js:35:28:35:40 | bodyParameter | -| tst2.js:35:28:35:40 | bodyParameter | -| tst2.js:42:9:42:46 | bodyParameter | -| tst2.js:42:25:42:32 | req.body | -| tst2.js:42:25:42:32 | req.body | -| tst2.js:42:25:42:46 | req.bod ... rameter | -| tst2.js:43:28:43:40 | bodyParameter | -| tst2.js:43:28:43:40 | bodyParameter | -| tst2.js:51:9:51:46 | bodyParameter | -| tst2.js:51:25:51:32 | req.body | -| tst2.js:51:25:51:32 | req.body | -| tst2.js:51:25:51:46 | req.bod ... rameter | -| tst2.js:52:28:52:40 | bodyParameter | -| tst2.js:52:28:52:40 | bodyParameter | -| tst.js:7:9:7:46 | bodyParameter | -| tst.js:7:25:7:32 | req.body | -| tst.js:7:25:7:32 | req.body | -| tst.js:7:25:7:46 | req.bod ... rameter | -| tst.js:8:9:8:49 | queryParameter | -| tst.js:8:9:8:49 | queryParameter | -| tst.js:8:26:8:49 | req.que ... rameter | -| tst.js:8:26:8:49 | req.que ... rameter | -| tst.js:8:26:8:49 | req.que ... rameter | -| tst.js:10:28:10:40 | bodyParameter | -| tst.js:10:28:10:40 | bodyParameter | -| tst.js:11:28:11:41 | queryParameter | -| tst.js:11:28:11:41 | queryParameter | -| tst.js:20:19:20:32 | queryParameter | -| tst.js:20:19:20:32 | queryParameter | -| tst.js:23:24:23:26 | obj | -| tst.js:23:24:23:26 | obj | -| tst.js:24:28:24:30 | obj | -| tst.js:24:28:24:30 | obj | -| tst.js:26:11:26:24 | str | -| tst.js:26:17:26:19 | obj | -| tst.js:26:17:26:24 | obj + "" | -| tst.js:29:28:29:42 | JSON.parse(str) | -| tst.js:29:28:29:42 | JSON.parse(str) | -| tst.js:29:39:29:41 | str | +| routes.js:2:23:2:30 | req.body | semmle.label | req.body | +| tst2.js:6:9:6:46 | bodyParameter | semmle.label | bodyParameter | +| tst2.js:6:25:6:32 | req.body | semmle.label | req.body | +| tst2.js:6:25:6:46 | req.bod ... rameter | semmle.label | req.bod ... rameter | +| tst2.js:7:28:7:40 | bodyParameter | semmle.label | bodyParameter | +| tst2.js:26:9:26:46 | bodyParameter | semmle.label | bodyParameter | +| tst2.js:26:25:26:32 | req.body | semmle.label | req.body | +| tst2.js:26:25:26:46 | req.bod ... rameter | semmle.label | req.bod ... rameter | +| tst2.js:27:28:27:40 | bodyParameter | semmle.label | bodyParameter | +| tst2.js:34:9:34:46 | bodyParameter | semmle.label | bodyParameter | +| tst2.js:34:25:34:32 | req.body | semmle.label | req.body | +| tst2.js:34:25:34:46 | req.bod ... rameter | semmle.label | req.bod ... rameter | +| tst2.js:35:28:35:40 | bodyParameter | semmle.label | bodyParameter | +| tst2.js:42:9:42:46 | bodyParameter | semmle.label | bodyParameter | +| tst2.js:42:25:42:32 | req.body | semmle.label | req.body | +| tst2.js:42:25:42:46 | req.bod ... rameter | semmle.label | req.bod ... rameter | +| tst2.js:43:28:43:40 | bodyParameter | semmle.label | bodyParameter | +| tst2.js:51:9:51:46 | bodyParameter | semmle.label | bodyParameter | +| tst2.js:51:25:51:32 | req.body | semmle.label | req.body | +| tst2.js:51:25:51:46 | req.bod ... rameter | semmle.label | req.bod ... rameter | +| tst2.js:52:28:52:40 | bodyParameter | semmle.label | bodyParameter | +| tst.js:7:9:7:46 | bodyParameter | semmle.label | bodyParameter | +| tst.js:7:25:7:32 | req.body | semmle.label | req.body | +| tst.js:7:25:7:46 | req.bod ... rameter | semmle.label | req.bod ... rameter | +| tst.js:8:9:8:49 | queryParameter | semmle.label | queryParameter | +| tst.js:8:26:8:49 | req.que ... rameter | semmle.label | req.que ... rameter | +| tst.js:10:28:10:40 | bodyParameter | semmle.label | bodyParameter | +| tst.js:11:28:11:41 | queryParameter | semmle.label | queryParameter | +| tst.js:20:19:20:32 | queryParameter | semmle.label | queryParameter | +| tst.js:23:24:23:26 | obj | semmle.label | obj | +| tst.js:24:28:24:30 | obj | semmle.label | obj | +| tst.js:26:11:26:24 | str | semmle.label | str | +| tst.js:26:17:26:19 | obj | semmle.label | obj | +| tst.js:26:17:26:24 | obj + "" | semmle.label | obj + "" | +| tst.js:29:28:29:42 | JSON.parse(str) | semmle.label | JSON.parse(str) | +| tst.js:29:39:29:41 | str | semmle.label | str | edges -| routes.js:2:23:2:30 | req.body | routes.js:2:23:2:30 | req.body | | tst2.js:6:9:6:46 | bodyParameter | tst2.js:7:28:7:40 | bodyParameter | -| tst2.js:6:9:6:46 | bodyParameter | tst2.js:7:28:7:40 | bodyParameter | -| tst2.js:6:25:6:32 | req.body | tst2.js:6:25:6:46 | req.bod ... rameter | | tst2.js:6:25:6:32 | req.body | tst2.js:6:25:6:46 | req.bod ... rameter | | tst2.js:6:25:6:46 | req.bod ... rameter | tst2.js:6:9:6:46 | bodyParameter | | tst2.js:26:9:26:46 | bodyParameter | tst2.js:27:28:27:40 | bodyParameter | -| tst2.js:26:9:26:46 | bodyParameter | tst2.js:27:28:27:40 | bodyParameter | -| tst2.js:26:25:26:32 | req.body | tst2.js:26:25:26:46 | req.bod ... rameter | | tst2.js:26:25:26:32 | req.body | tst2.js:26:25:26:46 | req.bod ... rameter | | tst2.js:26:25:26:46 | req.bod ... rameter | tst2.js:26:9:26:46 | bodyParameter | | tst2.js:34:9:34:46 | bodyParameter | tst2.js:35:28:35:40 | bodyParameter | -| tst2.js:34:9:34:46 | bodyParameter | tst2.js:35:28:35:40 | bodyParameter | -| tst2.js:34:25:34:32 | req.body | tst2.js:34:25:34:46 | req.bod ... rameter | | tst2.js:34:25:34:32 | req.body | tst2.js:34:25:34:46 | req.bod ... rameter | | tst2.js:34:25:34:46 | req.bod ... rameter | tst2.js:34:9:34:46 | bodyParameter | | tst2.js:42:9:42:46 | bodyParameter | tst2.js:43:28:43:40 | bodyParameter | -| tst2.js:42:9:42:46 | bodyParameter | tst2.js:43:28:43:40 | bodyParameter | -| tst2.js:42:25:42:32 | req.body | tst2.js:42:25:42:46 | req.bod ... rameter | | tst2.js:42:25:42:32 | req.body | tst2.js:42:25:42:46 | req.bod ... rameter | | tst2.js:42:25:42:46 | req.bod ... rameter | tst2.js:42:9:42:46 | bodyParameter | | tst2.js:51:9:51:46 | bodyParameter | tst2.js:52:28:52:40 | bodyParameter | -| tst2.js:51:9:51:46 | bodyParameter | tst2.js:52:28:52:40 | bodyParameter | -| tst2.js:51:25:51:32 | req.body | tst2.js:51:25:51:46 | req.bod ... rameter | | tst2.js:51:25:51:32 | req.body | tst2.js:51:25:51:46 | req.bod ... rameter | | tst2.js:51:25:51:46 | req.bod ... rameter | tst2.js:51:9:51:46 | bodyParameter | | tst.js:7:9:7:46 | bodyParameter | tst.js:10:28:10:40 | bodyParameter | -| tst.js:7:9:7:46 | bodyParameter | tst.js:10:28:10:40 | bodyParameter | -| tst.js:7:25:7:32 | req.body | tst.js:7:25:7:46 | req.bod ... rameter | | tst.js:7:25:7:32 | req.body | tst.js:7:25:7:46 | req.bod ... rameter | | tst.js:7:25:7:46 | req.bod ... rameter | tst.js:7:9:7:46 | bodyParameter | | tst.js:8:9:8:49 | queryParameter | tst.js:11:28:11:41 | queryParameter | -| tst.js:8:9:8:49 | queryParameter | tst.js:11:28:11:41 | queryParameter | -| tst.js:8:9:8:49 | queryParameter | tst.js:20:19:20:32 | queryParameter | | tst.js:8:9:8:49 | queryParameter | tst.js:20:19:20:32 | queryParameter | | tst.js:8:26:8:49 | req.que ... rameter | tst.js:8:9:8:49 | queryParameter | -| tst.js:8:26:8:49 | req.que ... rameter | tst.js:8:9:8:49 | queryParameter | -| tst.js:8:26:8:49 | req.que ... rameter | tst.js:8:9:8:49 | queryParameter | -| tst.js:8:26:8:49 | req.que ... rameter | tst.js:8:9:8:49 | queryParameter | | tst.js:20:19:20:32 | queryParameter | tst.js:23:24:23:26 | obj | -| tst.js:20:19:20:32 | queryParameter | tst.js:23:24:23:26 | obj | -| tst.js:23:24:23:26 | obj | tst.js:24:28:24:30 | obj | | tst.js:23:24:23:26 | obj | tst.js:24:28:24:30 | obj | | tst.js:23:24:23:26 | obj | tst.js:26:17:26:19 | obj | | tst.js:26:11:26:24 | str | tst.js:29:39:29:41 | str | | tst.js:26:17:26:19 | obj | tst.js:26:17:26:24 | obj + "" | | tst.js:26:17:26:24 | obj + "" | tst.js:26:11:26:24 | str | | tst.js:29:39:29:41 | str | tst.js:29:28:29:42 | JSON.parse(str) | -| tst.js:29:39:29:41 | str | tst.js:29:28:29:42 | JSON.parse(str) | +subpaths #select | routes.js:2:23:2:30 | req.body | routes.js:2:23:2:30 | req.body | routes.js:2:23:2:30 | req.body | Template object depends on a $@. | routes.js:2:23:2:30 | req.body | user-provided value | | tst2.js:7:28:7:40 | bodyParameter | tst2.js:6:25:6:32 | req.body | tst2.js:7:28:7:40 | bodyParameter | Template object depends on a $@. | tst2.js:6:25:6:32 | req.body | user-provided value |