From e52dca0a35f3204fe5e82e4664c157f0204969cf Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 8 Feb 2022 11:19:28 +0100 Subject: [PATCH 01/22] python: move tests --- .../query-tests/Security/CWE-643/XpathInjection.expected | 0 .../query-tests/Security/CWE-643/XpathInjection.qlref | 0 .../test/{experimental => }/query-tests/Security/CWE-643/xpath.py | 0 .../{experimental => }/query-tests/Security/CWE-643/xpathBad.py | 0 .../{experimental => }/query-tests/Security/CWE-643/xpathFlow.py | 0 .../{experimental => }/query-tests/Security/CWE-643/xpathGood.py | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename python/ql/test/{experimental => }/query-tests/Security/CWE-643/XpathInjection.expected (100%) rename python/ql/test/{experimental => }/query-tests/Security/CWE-643/XpathInjection.qlref (100%) rename python/ql/test/{experimental => }/query-tests/Security/CWE-643/xpath.py (100%) rename python/ql/test/{experimental => }/query-tests/Security/CWE-643/xpathBad.py (100%) rename python/ql/test/{experimental => }/query-tests/Security/CWE-643/xpathFlow.py (100%) rename python/ql/test/{experimental => }/query-tests/Security/CWE-643/xpathGood.py (100%) diff --git a/python/ql/test/experimental/query-tests/Security/CWE-643/XpathInjection.expected b/python/ql/test/query-tests/Security/CWE-643/XpathInjection.expected similarity index 100% rename from python/ql/test/experimental/query-tests/Security/CWE-643/XpathInjection.expected rename to python/ql/test/query-tests/Security/CWE-643/XpathInjection.expected diff --git a/python/ql/test/experimental/query-tests/Security/CWE-643/XpathInjection.qlref b/python/ql/test/query-tests/Security/CWE-643/XpathInjection.qlref similarity index 100% rename from python/ql/test/experimental/query-tests/Security/CWE-643/XpathInjection.qlref rename to python/ql/test/query-tests/Security/CWE-643/XpathInjection.qlref diff --git a/python/ql/test/experimental/query-tests/Security/CWE-643/xpath.py b/python/ql/test/query-tests/Security/CWE-643/xpath.py similarity index 100% rename from python/ql/test/experimental/query-tests/Security/CWE-643/xpath.py rename to python/ql/test/query-tests/Security/CWE-643/xpath.py diff --git a/python/ql/test/experimental/query-tests/Security/CWE-643/xpathBad.py b/python/ql/test/query-tests/Security/CWE-643/xpathBad.py similarity index 100% rename from python/ql/test/experimental/query-tests/Security/CWE-643/xpathBad.py rename to python/ql/test/query-tests/Security/CWE-643/xpathBad.py diff --git a/python/ql/test/experimental/query-tests/Security/CWE-643/xpathFlow.py b/python/ql/test/query-tests/Security/CWE-643/xpathFlow.py similarity index 100% rename from python/ql/test/experimental/query-tests/Security/CWE-643/xpathFlow.py rename to python/ql/test/query-tests/Security/CWE-643/xpathFlow.py diff --git a/python/ql/test/experimental/query-tests/Security/CWE-643/xpathGood.py b/python/ql/test/query-tests/Security/CWE-643/xpathGood.py similarity index 100% rename from python/ql/test/experimental/query-tests/Security/CWE-643/xpathGood.py rename to python/ql/test/query-tests/Security/CWE-643/xpathGood.py From e51ba6f42102183282b54c0f310e8921dda3e544 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 8 Feb 2022 11:20:10 +0100 Subject: [PATCH 02/22] python: rename test directory --- .../{CWE-643 => CWE-643-XPathInjection}/XpathInjection.expected | 0 .../{CWE-643 => CWE-643-XPathInjection}/XpathInjection.qlref | 0 .../Security/{CWE-643 => CWE-643-XPathInjection}/xpath.py | 0 .../Security/{CWE-643 => CWE-643-XPathInjection}/xpathBad.py | 0 .../Security/{CWE-643 => CWE-643-XPathInjection}/xpathFlow.py | 0 .../Security/{CWE-643 => CWE-643-XPathInjection}/xpathGood.py | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename python/ql/test/query-tests/Security/{CWE-643 => CWE-643-XPathInjection}/XpathInjection.expected (100%) rename python/ql/test/query-tests/Security/{CWE-643 => CWE-643-XPathInjection}/XpathInjection.qlref (100%) rename python/ql/test/query-tests/Security/{CWE-643 => CWE-643-XPathInjection}/xpath.py (100%) rename python/ql/test/query-tests/Security/{CWE-643 => CWE-643-XPathInjection}/xpathBad.py (100%) rename python/ql/test/query-tests/Security/{CWE-643 => CWE-643-XPathInjection}/xpathFlow.py (100%) rename python/ql/test/query-tests/Security/{CWE-643 => CWE-643-XPathInjection}/xpathGood.py (100%) diff --git a/python/ql/test/query-tests/Security/CWE-643/XpathInjection.expected b/python/ql/test/query-tests/Security/CWE-643-XPathInjection/XpathInjection.expected similarity index 100% rename from python/ql/test/query-tests/Security/CWE-643/XpathInjection.expected rename to python/ql/test/query-tests/Security/CWE-643-XPathInjection/XpathInjection.expected diff --git a/python/ql/test/query-tests/Security/CWE-643/XpathInjection.qlref b/python/ql/test/query-tests/Security/CWE-643-XPathInjection/XpathInjection.qlref similarity index 100% rename from python/ql/test/query-tests/Security/CWE-643/XpathInjection.qlref rename to python/ql/test/query-tests/Security/CWE-643-XPathInjection/XpathInjection.qlref diff --git a/python/ql/test/query-tests/Security/CWE-643/xpath.py b/python/ql/test/query-tests/Security/CWE-643-XPathInjection/xpath.py similarity index 100% rename from python/ql/test/query-tests/Security/CWE-643/xpath.py rename to python/ql/test/query-tests/Security/CWE-643-XPathInjection/xpath.py diff --git a/python/ql/test/query-tests/Security/CWE-643/xpathBad.py b/python/ql/test/query-tests/Security/CWE-643-XPathInjection/xpathBad.py similarity index 100% rename from python/ql/test/query-tests/Security/CWE-643/xpathBad.py rename to python/ql/test/query-tests/Security/CWE-643-XPathInjection/xpathBad.py diff --git a/python/ql/test/query-tests/Security/CWE-643/xpathFlow.py b/python/ql/test/query-tests/Security/CWE-643-XPathInjection/xpathFlow.py similarity index 100% rename from python/ql/test/query-tests/Security/CWE-643/xpathFlow.py rename to python/ql/test/query-tests/Security/CWE-643-XPathInjection/xpathFlow.py diff --git a/python/ql/test/query-tests/Security/CWE-643/xpathGood.py b/python/ql/test/query-tests/Security/CWE-643-XPathInjection/xpathGood.py similarity index 100% rename from python/ql/test/query-tests/Security/CWE-643/xpathGood.py rename to python/ql/test/query-tests/Security/CWE-643-XPathInjection/xpathGood.py From 88efcff8180ecdc43ddd083897cdad1ef6de45d7 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 8 Feb 2022 11:24:09 +0100 Subject: [PATCH 03/22] python: move query and update reference in query test --- .../{experimental => }/Security/CWE-643/XpathInjection.qhelp | 0 .../src/{experimental => }/Security/CWE-643/XpathInjection.ql | 0 .../src/{experimental => }/Security/CWE-643/XpathInjection.qll | 0 .../Security/CWE-643/XpathInjectionCustomizations.qll | 0 python/ql/src/{experimental => }/Security/CWE-643/xpathBad.py | 0 python/ql/src/{experimental => }/Security/CWE-643/xpathGood.py | 0 .../Security/CWE-643-XPathInjection/XpathInjection.qlref | 2 +- 7 files changed, 1 insertion(+), 1 deletion(-) rename python/ql/src/{experimental => }/Security/CWE-643/XpathInjection.qhelp (100%) rename python/ql/src/{experimental => }/Security/CWE-643/XpathInjection.ql (100%) rename python/ql/src/{experimental => }/Security/CWE-643/XpathInjection.qll (100%) rename python/ql/src/{experimental => }/Security/CWE-643/XpathInjectionCustomizations.qll (100%) rename python/ql/src/{experimental => }/Security/CWE-643/xpathBad.py (100%) rename python/ql/src/{experimental => }/Security/CWE-643/xpathGood.py (100%) diff --git a/python/ql/src/experimental/Security/CWE-643/XpathInjection.qhelp b/python/ql/src/Security/CWE-643/XpathInjection.qhelp similarity index 100% rename from python/ql/src/experimental/Security/CWE-643/XpathInjection.qhelp rename to python/ql/src/Security/CWE-643/XpathInjection.qhelp diff --git a/python/ql/src/experimental/Security/CWE-643/XpathInjection.ql b/python/ql/src/Security/CWE-643/XpathInjection.ql similarity index 100% rename from python/ql/src/experimental/Security/CWE-643/XpathInjection.ql rename to python/ql/src/Security/CWE-643/XpathInjection.ql diff --git a/python/ql/src/experimental/Security/CWE-643/XpathInjection.qll b/python/ql/src/Security/CWE-643/XpathInjection.qll similarity index 100% rename from python/ql/src/experimental/Security/CWE-643/XpathInjection.qll rename to python/ql/src/Security/CWE-643/XpathInjection.qll diff --git a/python/ql/src/experimental/Security/CWE-643/XpathInjectionCustomizations.qll b/python/ql/src/Security/CWE-643/XpathInjectionCustomizations.qll similarity index 100% rename from python/ql/src/experimental/Security/CWE-643/XpathInjectionCustomizations.qll rename to python/ql/src/Security/CWE-643/XpathInjectionCustomizations.qll diff --git a/python/ql/src/experimental/Security/CWE-643/xpathBad.py b/python/ql/src/Security/CWE-643/xpathBad.py similarity index 100% rename from python/ql/src/experimental/Security/CWE-643/xpathBad.py rename to python/ql/src/Security/CWE-643/xpathBad.py diff --git a/python/ql/src/experimental/Security/CWE-643/xpathGood.py b/python/ql/src/Security/CWE-643/xpathGood.py similarity index 100% rename from python/ql/src/experimental/Security/CWE-643/xpathGood.py rename to python/ql/src/Security/CWE-643/xpathGood.py diff --git a/python/ql/test/query-tests/Security/CWE-643-XPathInjection/XpathInjection.qlref b/python/ql/test/query-tests/Security/CWE-643-XPathInjection/XpathInjection.qlref index 2c4f25a5b9a..a61523e1767 100644 --- a/python/ql/test/query-tests/Security/CWE-643-XPathInjection/XpathInjection.qlref +++ b/python/ql/test/query-tests/Security/CWE-643-XPathInjection/XpathInjection.qlref @@ -1 +1 @@ -experimental/Security/CWE-643/XpathInjection.ql +Security/CWE-643/XpathInjection.ql From a9cfc60ea1d9cae7e0d90f00fe7c0aa8981a3829 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 8 Feb 2022 11:27:45 +0100 Subject: [PATCH 04/22] python: move supporting libraries and update reference in query --- .../semmle/python/security/dataflow}/XpathInjection.qll | 0 .../python/security/dataflow}/XpathInjectionCustomizations.qll | 0 python/ql/src/Security/CWE-643/XpathInjection.ql | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename python/ql/{src/Security/CWE-643 => lib/semmle/python/security/dataflow}/XpathInjection.qll (100%) rename python/ql/{src/Security/CWE-643 => lib/semmle/python/security/dataflow}/XpathInjectionCustomizations.qll (100%) diff --git a/python/ql/src/Security/CWE-643/XpathInjection.qll b/python/ql/lib/semmle/python/security/dataflow/XpathInjection.qll similarity index 100% rename from python/ql/src/Security/CWE-643/XpathInjection.qll rename to python/ql/lib/semmle/python/security/dataflow/XpathInjection.qll diff --git a/python/ql/src/Security/CWE-643/XpathInjectionCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/XpathInjectionCustomizations.qll similarity index 100% rename from python/ql/src/Security/CWE-643/XpathInjectionCustomizations.qll rename to python/ql/lib/semmle/python/security/dataflow/XpathInjectionCustomizations.qll diff --git a/python/ql/src/Security/CWE-643/XpathInjection.ql b/python/ql/src/Security/CWE-643/XpathInjection.ql index 67b4741f610..2c4c9983634 100644 --- a/python/ql/src/Security/CWE-643/XpathInjection.ql +++ b/python/ql/src/Security/CWE-643/XpathInjection.ql @@ -17,7 +17,7 @@ private import semmle.python.Concepts private import semmle.python.ApiGraphs private import semmle.python.dataflow.new.RemoteFlowSources private import semmle.python.dataflow.new.BarrierGuards -import XpathInjection::XpathInjection +import semmle.python.security.dataflow.XpathInjection::XpathInjection import DataFlow::PathGraph class XpathInjectionConfiguration extends TaintTracking::Configuration { From 103b5761f3f2548d4c4bb1c6ba7bc0aee796068c Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 8 Feb 2022 11:34:11 +0100 Subject: [PATCH 05/22] python: remove superfluous configuration this also removes duplicated nodes and edges in the path results --- .../ql/src/Security/CWE-643/XpathInjection.ql | 20 ++---------- .../XpathInjection.expected | 32 ------------------- 2 files changed, 3 insertions(+), 49 deletions(-) diff --git a/python/ql/src/Security/CWE-643/XpathInjection.ql b/python/ql/src/Security/CWE-643/XpathInjection.ql index 2c4c9983634..16979a81a54 100644 --- a/python/ql/src/Security/CWE-643/XpathInjection.ql +++ b/python/ql/src/Security/CWE-643/XpathInjection.ql @@ -10,24 +10,10 @@ * external/cwe/cwe-643 */ -private import python -private import semmle.python.Concepts -private import semmle.python.dataflow.new.TaintTracking -private import semmle.python.Concepts -private import semmle.python.ApiGraphs -private import semmle.python.dataflow.new.RemoteFlowSources -private import semmle.python.dataflow.new.BarrierGuards -import semmle.python.security.dataflow.XpathInjection::XpathInjection +import python +import semmle.python.security.dataflow.XpathInjection import DataFlow::PathGraph -class XpathInjectionConfiguration extends TaintTracking::Configuration { - XpathInjectionConfiguration() { this = "PathNotNormalizedConfiguration" } - - override predicate isSource(DataFlow::Node source) { source instanceof Source } - - override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } -} - -from XpathInjectionConfiguration config, DataFlow::PathNode source, DataFlow::PathNode sink +from XpathInjection::Configuration config, DataFlow::PathNode source, DataFlow::PathNode sink where config.hasFlowPath(source, sink) select sink, source, sink, "This Xpath query depends on $@.", source, "a user-provided value" diff --git a/python/ql/test/query-tests/Security/CWE-643-XPathInjection/XpathInjection.expected b/python/ql/test/query-tests/Security/CWE-643-XPathInjection/XpathInjection.expected index 68147452822..9a10b21d56d 100644 --- a/python/ql/test/query-tests/Security/CWE-643-XPathInjection/XpathInjection.expected +++ b/python/ql/test/query-tests/Security/CWE-643-XPathInjection/XpathInjection.expected @@ -1,68 +1,36 @@ edges | xpathBad.py:9:7:9:13 | ControlFlowNode for request | xpathBad.py:10:13:10:23 | ControlFlowNode for Attribute | -| xpathBad.py:9:7:9:13 | ControlFlowNode for request | xpathBad.py:10:13:10:23 | ControlFlowNode for Attribute | -| xpathBad.py:10:13:10:23 | ControlFlowNode for Attribute | xpathBad.py:10:13:10:32 | ControlFlowNode for Subscript | | xpathBad.py:10:13:10:23 | ControlFlowNode for Attribute | xpathBad.py:10:13:10:32 | ControlFlowNode for Subscript | | xpathBad.py:10:13:10:32 | ControlFlowNode for Subscript | xpathBad.py:13:20:13:43 | ControlFlowNode for BinaryExpr | -| xpathBad.py:10:13:10:32 | ControlFlowNode for Subscript | xpathBad.py:13:20:13:43 | ControlFlowNode for BinaryExpr | -| xpathFlow.py:11:18:11:24 | ControlFlowNode for request | xpathFlow.py:11:18:11:29 | ControlFlowNode for Attribute | | xpathFlow.py:11:18:11:24 | ControlFlowNode for request | xpathFlow.py:11:18:11:29 | ControlFlowNode for Attribute | | xpathFlow.py:11:18:11:29 | ControlFlowNode for Attribute | xpathFlow.py:14:20:14:29 | ControlFlowNode for xpathQuery | -| xpathFlow.py:11:18:11:29 | ControlFlowNode for Attribute | xpathFlow.py:14:20:14:29 | ControlFlowNode for xpathQuery | -| xpathFlow.py:20:18:20:24 | ControlFlowNode for request | xpathFlow.py:20:18:20:29 | ControlFlowNode for Attribute | | xpathFlow.py:20:18:20:24 | ControlFlowNode for request | xpathFlow.py:20:18:20:29 | ControlFlowNode for Attribute | | xpathFlow.py:20:18:20:29 | ControlFlowNode for Attribute | xpathFlow.py:23:29:23:38 | ControlFlowNode for xpathQuery | -| xpathFlow.py:20:18:20:29 | ControlFlowNode for Attribute | xpathFlow.py:23:29:23:38 | ControlFlowNode for xpathQuery | -| xpathFlow.py:30:18:30:24 | ControlFlowNode for request | xpathFlow.py:30:18:30:29 | ControlFlowNode for Attribute | | xpathFlow.py:30:18:30:24 | ControlFlowNode for request | xpathFlow.py:30:18:30:29 | ControlFlowNode for Attribute | | xpathFlow.py:30:18:30:29 | ControlFlowNode for Attribute | xpathFlow.py:32:29:32:38 | ControlFlowNode for xpathQuery | -| xpathFlow.py:30:18:30:29 | ControlFlowNode for Attribute | xpathFlow.py:32:29:32:38 | ControlFlowNode for xpathQuery | -| xpathFlow.py:39:18:39:24 | ControlFlowNode for request | xpathFlow.py:39:18:39:29 | ControlFlowNode for Attribute | | xpathFlow.py:39:18:39:24 | ControlFlowNode for request | xpathFlow.py:39:18:39:29 | ControlFlowNode for Attribute | | xpathFlow.py:39:18:39:29 | ControlFlowNode for Attribute | xpathFlow.py:41:31:41:40 | ControlFlowNode for xpathQuery | -| xpathFlow.py:39:18:39:29 | ControlFlowNode for Attribute | xpathFlow.py:41:31:41:40 | ControlFlowNode for xpathQuery | | xpathFlow.py:47:18:47:24 | ControlFlowNode for request | xpathFlow.py:47:18:47:29 | ControlFlowNode for Attribute | -| xpathFlow.py:47:18:47:24 | ControlFlowNode for request | xpathFlow.py:47:18:47:29 | ControlFlowNode for Attribute | -| xpathFlow.py:47:18:47:29 | ControlFlowNode for Attribute | xpathFlow.py:49:29:49:38 | ControlFlowNode for xpathQuery | | xpathFlow.py:47:18:47:29 | ControlFlowNode for Attribute | xpathFlow.py:49:29:49:38 | ControlFlowNode for xpathQuery | nodes | xpathBad.py:9:7:9:13 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| xpathBad.py:9:7:9:13 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| xpathBad.py:10:13:10:23 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | | xpathBad.py:10:13:10:23 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | | xpathBad.py:10:13:10:32 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| xpathBad.py:10:13:10:32 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| xpathBad.py:13:20:13:43 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | | xpathBad.py:13:20:13:43 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | | xpathFlow.py:11:18:11:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| xpathFlow.py:11:18:11:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| xpathFlow.py:11:18:11:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | | xpathFlow.py:11:18:11:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | | xpathFlow.py:14:20:14:29 | ControlFlowNode for xpathQuery | semmle.label | ControlFlowNode for xpathQuery | -| xpathFlow.py:14:20:14:29 | ControlFlowNode for xpathQuery | semmle.label | ControlFlowNode for xpathQuery | -| xpathFlow.py:20:18:20:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | xpathFlow.py:20:18:20:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | xpathFlow.py:20:18:20:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| xpathFlow.py:20:18:20:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| xpathFlow.py:23:29:23:38 | ControlFlowNode for xpathQuery | semmle.label | ControlFlowNode for xpathQuery | | xpathFlow.py:23:29:23:38 | ControlFlowNode for xpathQuery | semmle.label | ControlFlowNode for xpathQuery | | xpathFlow.py:30:18:30:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| xpathFlow.py:30:18:30:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| xpathFlow.py:30:18:30:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | | xpathFlow.py:30:18:30:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | | xpathFlow.py:32:29:32:38 | ControlFlowNode for xpathQuery | semmle.label | ControlFlowNode for xpathQuery | -| xpathFlow.py:32:29:32:38 | ControlFlowNode for xpathQuery | semmle.label | ControlFlowNode for xpathQuery | -| xpathFlow.py:39:18:39:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | xpathFlow.py:39:18:39:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | xpathFlow.py:39:18:39:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| xpathFlow.py:39:18:39:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| xpathFlow.py:41:31:41:40 | ControlFlowNode for xpathQuery | semmle.label | ControlFlowNode for xpathQuery | | xpathFlow.py:41:31:41:40 | ControlFlowNode for xpathQuery | semmle.label | ControlFlowNode for xpathQuery | | xpathFlow.py:47:18:47:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| xpathFlow.py:47:18:47:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | xpathFlow.py:47:18:47:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| xpathFlow.py:47:18:47:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| xpathFlow.py:49:29:49:38 | ControlFlowNode for xpathQuery | semmle.label | ControlFlowNode for xpathQuery | | xpathFlow.py:49:29:49:38 | ControlFlowNode for xpathQuery | semmle.label | ControlFlowNode for xpathQuery | subpaths #select From 7d287f169846a6f71379fa620030ef308b0357aa Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 8 Feb 2022 11:46:28 +0100 Subject: [PATCH 06/22] python: add concept for xpath execution --- python/ql/lib/semmle/python/Concepts.qll | 47 ++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/python/ql/lib/semmle/python/Concepts.qll b/python/ql/lib/semmle/python/Concepts.qll index 73c6b8ba4b4..772c5667138 100644 --- a/python/ql/lib/semmle/python/Concepts.qll +++ b/python/ql/lib/semmle/python/Concepts.qll @@ -449,6 +449,53 @@ module RegexExecution { } } +/** + * A data-flow node that executes a xpath expression. + * + * Extend this class to refine existing API models. If you want to model new APIs, + * extend `XPathExecution::Range` instead. + */ +class XPathExecution extends DataFlow::Node { + XPathExecution::Range range; + + XPathExecution() { this = range } + + /** Gets the data flow node for the xpath expression being executed by this node. */ + DataFlow::Node getXPath() { result = range.getXPath() } + + /** Gets a dataflow node for the tree in which the xpath is being evaluated. */ + DataFlow::Node getTree() { result = range.getTree() } + + /** + * Gets the name of this xpath expression execution, typically the name of an executing method. + * This is used for nice alert messages and should include the module if possible. + */ + string getName() { result = range.getName() } +} + +/** Provides classes for modeling new regular-expression execution APIs. */ +module XPathExecution { + /** + * A data-flow node that executes a xpath expression. + * + * Extend this class to model new APIs. If you want to refine existing API models, + * extend `XPathExecution` instead. + */ + abstract class Range extends DataFlow::Node { + /** Gets the data flow node for the xpath expression being executed by this node. */ + abstract DataFlow::Node getXPath(); + + /** Gets a dataflow node for the tree in which the xpath is being evaluated. */ + abstract DataFlow::Node getTree(); + + /** + * Gets the name of this xpath expression execution, typically the name of an executing method. + * This is used for nice alert messages and should include the module if possible. + */ + abstract string getName(); + } +} + /** * A data-flow node that escapes meta-characters, which could be used to prevent * injection attacks. From 8665fe48175b5166d4c12f0c678528d525534967 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 8 Feb 2022 12:31:37 +0100 Subject: [PATCH 07/22] python: add concept for XPath construction also small fixup in `SqlConstruction` --- python/ql/lib/semmle/python/Concepts.qll | 61 +++++++++++++++++++++--- 1 file changed, 54 insertions(+), 7 deletions(-) diff --git a/python/ql/lib/semmle/python/Concepts.qll b/python/ql/lib/semmle/python/Concepts.qll index 772c5667138..facce965fde 100644 --- a/python/ql/lib/semmle/python/Concepts.qll +++ b/python/ql/lib/semmle/python/Concepts.qll @@ -334,6 +334,7 @@ module CodeExecution { /** * A data-flow node that constructs an SQL statement. + * * Often, it is worthy of an alert if an SQL statement is constructed such that * executing it would be a security risk. * @@ -355,11 +356,14 @@ class SqlConstruction extends DataFlow::Node { module SqlConstruction { /** * A data-flow node that constructs an SQL statement. + * * Often, it is worthy of an alert if an SQL statement is constructed such that * executing it would be a security risk. * + * If it is important that the SQL statement is indeed executed, then use `SQLExecution`. + * * Extend this class to model new APIs. If you want to refine existing API models, - * extend `SqlExecution` instead. + * extend `SqlConstruction` instead. */ abstract class Range extends DataFlow::Node { /** Gets the argument that specifies the SQL statements to be constructed. */ @@ -449,9 +453,49 @@ module RegexExecution { } } +/** + * A data-flow node that constructs an XPath expression. + * + * Often, it is worthy of an alert if an XPath expression is constructed such that + * executing it would be a security risk. + * + * If it is important that the XPath expression is indeed executed, then use `XPathExecution`. + * + * Extend this class to refine existing API models. If you want to model new APIs, + * extend `XPathConstruction::Range` instead. + */ +class XPathConstruction extends DataFlow::Node { + XPathConstruction::Range range; + + XPathConstruction() { this = range } + + /** Gets the argument that specifies the XPath expressions to be constructed. */ + DataFlow::Node getXPath() { result = range.getXPath() } +} + +/** Provides a class for modeling new XPath construction APIs. */ +module XPathConstruction { + /** + * A data-flow node that constructs an XPath expression. + * + * Often, it is worthy of an alert if an XPath expression is constructed such that + * executing it would be a security risk. + * + * Extend this class to model new APIs. If you want to refine existing API models, + * extend `XPathConstruction` instead. + */ + abstract class Range extends DataFlow::Node { + /** Gets the argument that specifies the XPath expressions to be constructed. */ + abstract DataFlow::Node getXPath(); + } +} + /** * A data-flow node that executes a xpath expression. * + * If the context of interest is such that merely constructing an XPath expression + * would be valuabe to report, then consider using `XPathConstruction`. + * * Extend this class to refine existing API models. If you want to model new APIs, * extend `XPathExecution::Range` instead. */ @@ -460,14 +504,14 @@ class XPathExecution extends DataFlow::Node { XPathExecution() { this = range } - /** Gets the data flow node for the xpath expression being executed by this node. */ + /** Gets the data flow node for the XPath expression being executed by this node. */ DataFlow::Node getXPath() { result = range.getXPath() } - /** Gets a dataflow node for the tree in which the xpath is being evaluated. */ + /** Gets a dataflow node for the tree in which the XPath expression is being evaluated. */ DataFlow::Node getTree() { result = range.getTree() } /** - * Gets the name of this xpath expression execution, typically the name of an executing method. + * Gets the name of this XPath expression execution, typically the name of an executing method. * This is used for nice alert messages and should include the module if possible. */ string getName() { result = range.getName() } @@ -476,16 +520,19 @@ class XPathExecution extends DataFlow::Node { /** Provides classes for modeling new regular-expression execution APIs. */ module XPathExecution { /** - * A data-flow node that executes a xpath expression. + * A data-flow node that executes a XPath expression. + * + * If the context of interest is such that merely constructing an XPath expression + * would be valuabe to report, then consider using `XPathConstruction`. * * Extend this class to model new APIs. If you want to refine existing API models, * extend `XPathExecution` instead. */ abstract class Range extends DataFlow::Node { - /** Gets the data flow node for the xpath expression being executed by this node. */ + /** Gets the data flow node for the XPath expression being executed by this node. */ abstract DataFlow::Node getXPath(); - /** Gets a dataflow node for the tree in which the xpath is being evaluated. */ + /** Gets a dataflow node for the tree in which the XPath expression is being evaluated. */ abstract DataFlow::Node getTree(); /** From 3f36ccba921abe8e260b286ea30f4249d5ed8c77 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 8 Feb 2022 12:40:13 +0100 Subject: [PATCH 08/22] python: add name to concept --- python/ql/lib/semmle/python/Concepts.qll | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/python/ql/lib/semmle/python/Concepts.qll b/python/ql/lib/semmle/python/Concepts.qll index facce965fde..a022b637169 100644 --- a/python/ql/lib/semmle/python/Concepts.qll +++ b/python/ql/lib/semmle/python/Concepts.qll @@ -471,6 +471,12 @@ class XPathConstruction extends DataFlow::Node { /** Gets the argument that specifies the XPath expressions to be constructed. */ DataFlow::Node getXPath() { result = range.getXPath() } + + /** + * Gets the name of this XPath expression construction, typically the name of an executing method. + * This is used for nice alert messages and should include the module if possible. + */ + string getName() { result = range.getName() } } /** Provides a class for modeling new XPath construction APIs. */ @@ -487,6 +493,12 @@ module XPathConstruction { abstract class Range extends DataFlow::Node { /** Gets the argument that specifies the XPath expressions to be constructed. */ abstract DataFlow::Node getXPath(); + + /** + * Gets the name of this XPath expression construction, typically the name of an executing method. + * This is used for nice alert messages and should include the module if possible. + */ + abstract string getName(); } } From e8649d8947ef1e632c61bcfbe563f5ab5c645b6a Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Wed, 9 Feb 2022 14:15:17 +0100 Subject: [PATCH 09/22] python: model (etree from) lxml --- docs/codeql/support/reusables/frameworks.rst | 1 + python/ql/lib/semmle/python/Frameworks.qll | 1 + .../ql/lib/semmle/python/frameworks/Lxml.qll | 77 +++++++++++++++++++ 3 files changed, 79 insertions(+) create mode 100644 python/ql/lib/semmle/python/frameworks/Lxml.qll diff --git a/docs/codeql/support/reusables/frameworks.rst b/docs/codeql/support/reusables/frameworks.rst index 5aa1eea4cfc..3be57b44860 100644 --- a/docs/codeql/support/reusables/frameworks.rst +++ b/docs/codeql/support/reusables/frameworks.rst @@ -204,3 +204,4 @@ Python built-in support pycryptodomex, Cryptography library rsa, Cryptography library MarkupSafe, Escaping Library + lxml, XML processing library diff --git a/python/ql/lib/semmle/python/Frameworks.qll b/python/ql/lib/semmle/python/Frameworks.qll index 74369461939..8e901f6a7fa 100644 --- a/python/ql/lib/semmle/python/Frameworks.qll +++ b/python/ql/lib/semmle/python/Frameworks.qll @@ -22,6 +22,7 @@ private import semmle.python.frameworks.FlaskSqlAlchemy private import semmle.python.frameworks.Idna private import semmle.python.frameworks.Invoke private import semmle.python.frameworks.Jmespath +private import semmle.python.frameworks.Lxml private import semmle.python.frameworks.MarkupSafe private import semmle.python.frameworks.Multidict private import semmle.python.frameworks.Mysql diff --git a/python/ql/lib/semmle/python/frameworks/Lxml.qll b/python/ql/lib/semmle/python/frameworks/Lxml.qll new file mode 100644 index 00000000000..13e55d6279e --- /dev/null +++ b/python/ql/lib/semmle/python/frameworks/Lxml.qll @@ -0,0 +1,77 @@ +/** + * Provides classes modeling security-relevant aspects of the `lxml` PyPI package. + * + * See + * - https://pypi.org/project/lxml/ + * - https://lxml.de/tutorial.html + */ + +private import python +private import semmle.python.dataflow.new.DataFlow +private import semmle.python.Concepts +private import semmle.python.ApiGraphs + +/** + * Provides classes modeling security-relevant aspects of the `lxml` PyPI package + * + * See + * - https://pypi.org/project/lxml/ + * - https://lxml.de/tutorial.html + */ +private module Lxml { + /** + * A class constructor compiling an XPath expression. + * + * from lxml import etree + * root = etree.XML("") + * find_text = etree.XPath("`sink`") + * find_text = etree.ETXPath("`sink`") + * + * See + * - https://lxml.de/apidoc/lxml.etree.html#lxml.etree.XPath + * - https://lxml.de/apidoc/lxml.etree.html#lxml.etree.ETXPath + */ + private class XPathClassCall extends XPathConstruction::Range, DataFlow::CallCfgNode { + XPathClassCall() { + this = API::moduleImport("lxml").getMember("etree").getMember(["XPath", "ETXPath"]).getACall() + } + + override DataFlow::Node getXPath() { result in [this.getArg(0), this.getArgByName("path")] } + + override string getName() { result = "Lxml.etree" } + } + + /** + * A call to the `xpath` method of a parsed document. + * + * from lxml import etree + * root = etree.fromstring(file(XML_DB).read(), XMLParser()) + * find_text = root.xpath("`sink`") + * + * See https://lxml.de/apidoc/lxml.etree.html#lxml.etree._ElementTree.xpath + * as well as + * - https://lxml.de/apidoc/lxml.etree.html#lxml.etree.parse + * - https://lxml.de/apidoc/lxml.etree.html#lxml.etree.fromstring + * - https://lxml.de/apidoc/lxml.etree.html#lxml.etree.fromstringlist + * - https://lxml.de/apidoc/lxml.etree.html#lxml.etree.HTML + * - https://lxml.de/apidoc/lxml.etree.html#lxml.etree.XML + */ + class XPathCall extends XPathExecution::Range, DataFlow::CallCfgNode { + XPathCall() { + this = + API::moduleImport("lxml") + .getMember("etree") + .getMember(["parse", "fromstring", "fromstringlist", "HTML", "XML"]) + .getReturn() + .getMember("xpath") + .getACall() + } + + override DataFlow::Node getXPath() { result in [this.getArg(0), this.getArgByName("_path")] } + + // TODO: implement when we get call nodes + override DataFlow::Node getTree() { none() } + + override string getName() { result = "Lxml.etree" } + } +} From 17aa2898f9fccb1d623b727217ea9e99534a3be8 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Wed, 9 Feb 2022 14:25:43 +0100 Subject: [PATCH 10/22] python: model (xpathEval from) libxml2 --- docs/codeql/support/reusables/frameworks.rst | 1 + python/ql/lib/semmle/python/Frameworks.qll | 1 + .../lib/semmle/python/frameworks/Libxml2.qll | 48 +++++++++++++++++++ 3 files changed, 50 insertions(+) create mode 100644 python/ql/lib/semmle/python/frameworks/Libxml2.qll diff --git a/docs/codeql/support/reusables/frameworks.rst b/docs/codeql/support/reusables/frameworks.rst index 3be57b44860..33826b6e233 100644 --- a/docs/codeql/support/reusables/frameworks.rst +++ b/docs/codeql/support/reusables/frameworks.rst @@ -204,4 +204,5 @@ Python built-in support pycryptodomex, Cryptography library rsa, Cryptography library MarkupSafe, Escaping Library + libxml2, XML processing library lxml, XML processing library diff --git a/python/ql/lib/semmle/python/Frameworks.qll b/python/ql/lib/semmle/python/Frameworks.qll index 8e901f6a7fa..38456f7e890 100644 --- a/python/ql/lib/semmle/python/Frameworks.qll +++ b/python/ql/lib/semmle/python/Frameworks.qll @@ -22,6 +22,7 @@ private import semmle.python.frameworks.FlaskSqlAlchemy private import semmle.python.frameworks.Idna private import semmle.python.frameworks.Invoke private import semmle.python.frameworks.Jmespath +private import semmle.python.frameworks.Libxml2 private import semmle.python.frameworks.Lxml private import semmle.python.frameworks.MarkupSafe private import semmle.python.frameworks.Multidict diff --git a/python/ql/lib/semmle/python/frameworks/Libxml2.qll b/python/ql/lib/semmle/python/frameworks/Libxml2.qll new file mode 100644 index 00000000000..19b566e05aa --- /dev/null +++ b/python/ql/lib/semmle/python/frameworks/Libxml2.qll @@ -0,0 +1,48 @@ +/** + * Provides classes modeling security-relevant aspects of the `libxml2` PyPI package. + * + * See + * - https://pypi.org/project/libxml2-python3/ + * - http://xmlsoft.org/python.html + */ + +private import python +private import semmle.python.dataflow.new.DataFlow +private import semmle.python.Concepts +private import semmle.python.ApiGraphs + +/** + * Provides classes modeling security-relevant aspects of the `libxml2` PyPI package + * + * See + * - https://pypi.org/project/libxml2-python3/ + * - http://xmlsoft.org/python.html + */ +private module Libxml2 { + /** + * A call to the `xpathEval` method of a parsed document. + * + * import libxml2 + * tree = libxml2.parseFile("file.xml") + * r = tree.xpathEval('`sink`') + * + * See http://xmlsoft.org/python.html + */ + class XpathEvalCall extends XPathExecution::Range, DataFlow::CallCfgNode { + XpathEvalCall() { + this = + API::moduleImport("libxml2") + .getMember("parseFile") + .getReturn() + .getMember("xpathEval") + .getACall() + } + + override DataFlow::Node getXPath() { result = this.getArg(0) } + + // TODO: implement when we get call nodes + override DataFlow::Node getTree() { none() } + + override string getName() { result = "libxml2" } + } +} From 313f9f056c604d9a61cc465243b5332d4079343a Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Wed, 9 Feb 2022 14:36:48 +0100 Subject: [PATCH 11/22] python: switch to using concepts --- .../dataflow/XpathInjectionCustomizations.qll | 62 ++----------------- 1 file changed, 6 insertions(+), 56 deletions(-) diff --git a/python/ql/lib/semmle/python/security/dataflow/XpathInjectionCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/XpathInjectionCustomizations.qll index 4a939253636..00407a39748 100644 --- a/python/ql/lib/semmle/python/security/dataflow/XpathInjectionCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/XpathInjectionCustomizations.qll @@ -6,7 +6,6 @@ */ private import python -private import semmle.python.Concepts private import semmle.python.dataflow.new.TaintTracking private import semmle.python.Concepts private import semmle.python.ApiGraphs @@ -40,66 +39,17 @@ module XpathInjection { */ class RemoteFlowSourceAsSource extends Source, RemoteFlowSource { } - /** Returns an API node referring to `lxml.etree` */ - API::Node etree() { result = API::moduleImport("lxml").getMember("etree") } - - /** Returns an API node referring to `lxml.etree` */ - API::Node etreeFromString() { result = etree().getMember("fromstring") } - - /** Returns an API node referring to `lxml.etree.parse` */ - API::Node etreeParse() { result = etree().getMember("parse") } - - /** Returns an API node referring to `lxml.etree.parse` */ - API::Node libxml2parseFile() { result = API::moduleImport("libxml2").getMember("parseFile") } - /** - * A Sink representing an argument to `etree.XPath` or `etree.ETXPath` call. - * - * from lxml import etree - * root = etree.XML("") - * find_text = etree.XPath("`sink`") - * find_text = etree.ETXPath("`sink`") + * A construction of an XPath expression, considered as a sink. */ - private class EtreeXpathArgument extends Sink { - EtreeXpathArgument() { this = etree().getMember(["XPath", "ETXPath"]).getACall().getArg(0) } + class XPathConstructionArg extends Sink { + XPathConstructionArg() { this = any(XPathConstruction c).getXPath() } } /** - * A Sink representing an argument to the `etree.XPath` call. - * - * from lxml import etree - * root = etree.fromstring(file(XML_DB).read(), XMLParser()) - * find_text = root.xpath("`sink`") + * An execution of an XPath expression, considered as a sink. */ - private class EtreeFromstringXpathArgument extends Sink { - EtreeFromstringXpathArgument() { - this = etreeFromString().getReturn().getMember("xpath").getACall().getArg(0) - } - } - - /** - * A Sink representing an argument to the `xpath` call to a parsed xml document. - * - * from lxml import etree - * from io import StringIO - * f = StringIO('') - * tree = etree.parse(f) - * r = tree.xpath('`sink`') - */ - private class ParseXpathArgument extends Sink { - ParseXpathArgument() { this = etreeParse().getReturn().getMember("xpath").getACall().getArg(0) } - } - - /** - * A Sink representing an argument to the `xpathEval` call to a parsed libxml2 document. - * - * import libxml2 - * tree = libxml2.parseFile("file.xml") - * r = tree.xpathEval('`sink`') - */ - private class ParseFileXpathEvalArgument extends Sink { - ParseFileXpathEvalArgument() { - this = libxml2parseFile().getReturn().getMember("xpathEval").getACall().getArg(0) - } + class XPathExecutionArg extends Sink { + XPathExecutionArg() { this = any(XPathExecution e).getXPath() } } } From 75a2f92ce4b559fd2bef18fb6debb1414f39aba6 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Wed, 9 Feb 2022 15:23:36 +0100 Subject: [PATCH 12/22] pthon: add change note --- .../ql/src/change-notes/2022-02-09-promote-xpath-injection.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 python/ql/src/change-notes/2022-02-09-promote-xpath-injection.md diff --git a/python/ql/src/change-notes/2022-02-09-promote-xpath-injection.md b/python/ql/src/change-notes/2022-02-09-promote-xpath-injection.md new file mode 100644 index 00000000000..0ce3dc623db --- /dev/null +++ b/python/ql/src/change-notes/2022-02-09-promote-xpath-injection.md @@ -0,0 +1,4 @@ +--- +category: newQuery +--- +* The query "XPath query built from user-controlled sources" (`py/xpath-injection`) has been promoted from experimental to the main query pack. Its results will now appear by default. This query was originally [submitted as an experimental query by @porcupineyhairs](https://github.com/github/codeql/pull/6331). From aa010e420b1d8275ed49386e0b9c222e844b887e Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Wed, 9 Feb 2022 15:27:39 +0100 Subject: [PATCH 13/22] python: update qhelp --- .../ql/src/Security/CWE-643/XpathInjection.qhelp | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/python/ql/src/Security/CWE-643/XpathInjection.qhelp b/python/ql/src/Security/CWE-643/XpathInjection.qhelp index c16eafc6bec..42de855920e 100644 --- a/python/ql/src/Security/CWE-643/XpathInjection.qhelp +++ b/python/ql/src/Security/CWE-643/XpathInjection.qhelp @@ -2,20 +2,14 @@

- Using user-supplied information to construct an XPath query for XML data can - result in an XPath injection flaw. By sending intentionally malformed information, - an attacker can access data that he may not normally have access to. - He/She may even be able to elevate his privileges on the web site if the XML data - is being used for authentication (such as an XML based user file). + If an XPath expression is built using string concatenation, and the components of the concatenation + include user input, it makes it very easy for a user to create a malicious XPath expression.

- XPath injection can be prevented using parameterized XPath interface or escaping the user input to make it safe to include in a dynamically constructed query. - If you are using quotes to terminate untrusted input in a dynamically constructed XPath query, then you need to escape that quote in the untrusted input to ensure the untrusted data can’t try to break out of that quoted context. -

-

- Another better mitigation option is to use a precompiled XPath query. Precompiled XPath queries are already preset before the program executes, rather than created on the fly after the user’s input has been added to the string. This is a better route because you don’t have to worry about missing a character that should have been escaped. + If user input must be included in an XPath expression, either sanitize the data or use variable + references to safely embed it without altering the structure of the expression.

From 853857bd7ee63fd16c4946be47a0dbb035915777 Mon Sep 17 00:00:00 2001 From: yoff Date: Tue, 1 Mar 2022 10:26:29 +0100 Subject: [PATCH 14/22] Apply suggestions from code review Co-authored-by: Rasmus Wriedt Larsen --- python/ql/lib/semmle/python/frameworks/Lxml.qll | 5 ++--- python/ql/src/Security/CWE-643/XpathInjection.ql | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/python/ql/lib/semmle/python/frameworks/Lxml.qll b/python/ql/lib/semmle/python/frameworks/Lxml.qll index 13e55d6279e..f2736a132b4 100644 --- a/python/ql/lib/semmle/python/frameworks/Lxml.qll +++ b/python/ql/lib/semmle/python/frameworks/Lxml.qll @@ -23,7 +23,6 @@ private module Lxml { * A class constructor compiling an XPath expression. * * from lxml import etree - * root = etree.XML("") * find_text = etree.XPath("`sink`") * find_text = etree.ETXPath("`sink`") * @@ -38,7 +37,7 @@ private module Lxml { override DataFlow::Node getXPath() { result in [this.getArg(0), this.getArgByName("path")] } - override string getName() { result = "Lxml.etree" } + override string getName() { result = "lxml.etree" } } /** @@ -72,6 +71,6 @@ private module Lxml { // TODO: implement when we get call nodes override DataFlow::Node getTree() { none() } - override string getName() { result = "Lxml.etree" } + override string getName() { result = "lxml.etree" } } } diff --git a/python/ql/src/Security/CWE-643/XpathInjection.ql b/python/ql/src/Security/CWE-643/XpathInjection.ql index 16979a81a54..22ae1f3679f 100644 --- a/python/ql/src/Security/CWE-643/XpathInjection.ql +++ b/python/ql/src/Security/CWE-643/XpathInjection.ql @@ -4,6 +4,7 @@ * malicious Xpath code by the user. * @kind path-problem * @problem.severity error + * @security-severity 9.8 * @precision high * @id py/xpath-injection * @tags security From ce3ee65f47472c663a88ec489115e5e9cc1c7fb9 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 1 Mar 2022 10:49:21 +0100 Subject: [PATCH 15/22] python: remove getTree for now --- python/ql/lib/semmle/python/Concepts.qll | 6 ------ python/ql/lib/semmle/python/frameworks/Libxml2.qll | 3 --- python/ql/lib/semmle/python/frameworks/Lxml.qll | 3 --- 3 files changed, 12 deletions(-) diff --git a/python/ql/lib/semmle/python/Concepts.qll b/python/ql/lib/semmle/python/Concepts.qll index a022b637169..c0bd746df70 100644 --- a/python/ql/lib/semmle/python/Concepts.qll +++ b/python/ql/lib/semmle/python/Concepts.qll @@ -519,9 +519,6 @@ class XPathExecution extends DataFlow::Node { /** Gets the data flow node for the XPath expression being executed by this node. */ DataFlow::Node getXPath() { result = range.getXPath() } - /** Gets a dataflow node for the tree in which the XPath expression is being evaluated. */ - DataFlow::Node getTree() { result = range.getTree() } - /** * Gets the name of this XPath expression execution, typically the name of an executing method. * This is used for nice alert messages and should include the module if possible. @@ -544,9 +541,6 @@ module XPathExecution { /** Gets the data flow node for the XPath expression being executed by this node. */ abstract DataFlow::Node getXPath(); - /** Gets a dataflow node for the tree in which the XPath expression is being evaluated. */ - abstract DataFlow::Node getTree(); - /** * Gets the name of this xpath expression execution, typically the name of an executing method. * This is used for nice alert messages and should include the module if possible. diff --git a/python/ql/lib/semmle/python/frameworks/Libxml2.qll b/python/ql/lib/semmle/python/frameworks/Libxml2.qll index 19b566e05aa..5494a548898 100644 --- a/python/ql/lib/semmle/python/frameworks/Libxml2.qll +++ b/python/ql/lib/semmle/python/frameworks/Libxml2.qll @@ -40,9 +40,6 @@ private module Libxml2 { override DataFlow::Node getXPath() { result = this.getArg(0) } - // TODO: implement when we get call nodes - override DataFlow::Node getTree() { none() } - override string getName() { result = "libxml2" } } } diff --git a/python/ql/lib/semmle/python/frameworks/Lxml.qll b/python/ql/lib/semmle/python/frameworks/Lxml.qll index f2736a132b4..161fb4bd71a 100644 --- a/python/ql/lib/semmle/python/frameworks/Lxml.qll +++ b/python/ql/lib/semmle/python/frameworks/Lxml.qll @@ -68,9 +68,6 @@ private module Lxml { override DataFlow::Node getXPath() { result in [this.getArg(0), this.getArgByName("_path")] } - // TODO: implement when we get call nodes - override DataFlow::Node getTree() { none() } - override string getName() { result = "lxml.etree" } } } From 3bb17be389ce653c7dda962126a158e511156c59 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 1 Mar 2022 14:39:28 +0100 Subject: [PATCH 16/22] python: add concept and library tests --- .../test/experimental/meta/ConceptsTest.qll | 36 +++++++++++++++++++ .../frameworks/lxml/ConceptsTest.expected | 0 .../frameworks/lxml/ConceptsTest.ql | 2 ++ .../library-tests/frameworks/lxml/test.py | 21 +++++++++++ 4 files changed, 59 insertions(+) create mode 100644 python/ql/test/library-tests/frameworks/lxml/ConceptsTest.expected create mode 100644 python/ql/test/library-tests/frameworks/lxml/ConceptsTest.ql create mode 100644 python/ql/test/library-tests/frameworks/lxml/test.py diff --git a/python/ql/test/experimental/meta/ConceptsTest.qll b/python/ql/test/experimental/meta/ConceptsTest.qll index 517f3a50bf7..0ad19e76db5 100644 --- a/python/ql/test/experimental/meta/ConceptsTest.qll +++ b/python/ql/test/experimental/meta/ConceptsTest.qll @@ -164,6 +164,42 @@ class SqlExecutionTest extends InlineExpectationsTest { } } +class XPathConstructionTest extends InlineExpectationsTest { + XPathConstructionTest() { this = "XPathConstructionTest" } + + override string getARelevantTag() { result = "constructedXPath" } + + override predicate hasActualResult(Location location, string element, string tag, string value) { + exists(location.getFile().getRelativePath()) and + exists(XPathConstruction e, DataFlow::Node xpath | + exists(location.getFile().getRelativePath()) and + xpath = e.getXPath() and + location = e.getLocation() and + element = xpath.toString() and + value = prettyNodeForInlineTest(xpath) and + tag = "constructedXPath" + ) + } +} + +class XPathExecutionTest extends InlineExpectationsTest { + XPathExecutionTest() { this = "XPathExecutionTest" } + + override string getARelevantTag() { result = "getXPath" } + + override predicate hasActualResult(Location location, string element, string tag, string value) { + exists(location.getFile().getRelativePath()) and + exists(XPathExecution e, DataFlow::Node xpath | + exists(location.getFile().getRelativePath()) and + xpath = e.getXPath() and + location = e.getLocation() and + element = xpath.toString() and + value = prettyNodeForInlineTest(xpath) and + tag = "getXPath" + ) + } +} + class EscapingTest extends InlineExpectationsTest { EscapingTest() { this = "EscapingTest" } diff --git a/python/ql/test/library-tests/frameworks/lxml/ConceptsTest.expected b/python/ql/test/library-tests/frameworks/lxml/ConceptsTest.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/library-tests/frameworks/lxml/ConceptsTest.ql b/python/ql/test/library-tests/frameworks/lxml/ConceptsTest.ql new file mode 100644 index 00000000000..b557a0bccb6 --- /dev/null +++ b/python/ql/test/library-tests/frameworks/lxml/ConceptsTest.ql @@ -0,0 +1,2 @@ +import python +import experimental.meta.ConceptsTest diff --git a/python/ql/test/library-tests/frameworks/lxml/test.py b/python/ql/test/library-tests/frameworks/lxml/test.py new file mode 100644 index 00000000000..7cc571d9095 --- /dev/null +++ b/python/ql/test/library-tests/frameworks/lxml/test.py @@ -0,0 +1,21 @@ +from lxml import etree +from io import StringIO + +def test_parse(): + tree = etree.parse(StringIO('')) + r = tree.xpath('/foo/bar') # $ getXPath='/foo/bar' + +def test_XPath_class(): + root = etree.XML("TEXT") + find_text = etree.XPath("path") # $ constructedXPath="path" + text = find_text(root)[0] + +def test_ETXpath_class(): + root = etree.XML("TEXT") + find_text = etree.ETXPath("path") # $ constructedXPath="path" + text = find_text(root)[0] + +def test_XPathEvaluator_class(): + root = etree.XML("TEXT") + search_root = etree.XPathEvaluator(root) + text = search_root("path")[0] # $ MISSING: getXPath="path" From f55d7d627e13b365eb5e60eb8fe4b14109c71602 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 1 Mar 2022 14:40:13 +0100 Subject: [PATCH 17/22] python: model XPathEvaluator --- python/ql/lib/semmle/python/frameworks/Lxml.qll | 15 +++++++++++++++ .../ql/test/library-tests/frameworks/lxml/test.py | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/python/ql/lib/semmle/python/frameworks/Lxml.qll b/python/ql/lib/semmle/python/frameworks/Lxml.qll index 161fb4bd71a..9afbc448a02 100644 --- a/python/ql/lib/semmle/python/frameworks/Lxml.qll +++ b/python/ql/lib/semmle/python/frameworks/Lxml.qll @@ -70,4 +70,19 @@ private module Lxml { override string getName() { result = "lxml.etree" } } + + class XPathEvaluatorCall extends XPathExecution::Range, DataFlow::CallCfgNode { + XPathEvaluatorCall() { + this = + API::moduleImport("lxml") + .getMember("etree") + .getMember("XPathEvaluator") + .getReturn() + .getACall() + } + + override DataFlow::Node getXPath() { result = this.getArg(0) } + + override string getName() { result = "lxml.etree" } + } } diff --git a/python/ql/test/library-tests/frameworks/lxml/test.py b/python/ql/test/library-tests/frameworks/lxml/test.py index 7cc571d9095..e8ce583503a 100644 --- a/python/ql/test/library-tests/frameworks/lxml/test.py +++ b/python/ql/test/library-tests/frameworks/lxml/test.py @@ -18,4 +18,4 @@ def test_ETXpath_class(): def test_XPathEvaluator_class(): root = etree.XML("TEXT") search_root = etree.XPathEvaluator(root) - text = search_root("path")[0] # $ MISSING: getXPath="path" + text = search_root("path")[0] # $ getXPath="path" From 06e0f140c517e467445a59be989ba3b9ddd76503 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Wed, 2 Mar 2022 12:58:37 +0100 Subject: [PATCH 18/22] python: add tests for stdlib xpath --- .../frameworks/stdlib/XPathExecution.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 python/ql/test/library-tests/frameworks/stdlib/XPathExecution.py diff --git a/python/ql/test/library-tests/frameworks/stdlib/XPathExecution.py b/python/ql/test/library-tests/frameworks/stdlib/XPathExecution.py new file mode 100644 index 00000000000..d6ca13766d6 --- /dev/null +++ b/python/ql/test/library-tests/frameworks/stdlib/XPathExecution.py @@ -0,0 +1,18 @@ +match = "dc:title" +ns = {'dc': 'http://purl.org/dc/elements/1.1/'} + +import xml.etree.ElementTree as ET +tree = ET.parse('country_data.xml') +root = tree.getroot() + +root.find(match, namespaces=ns) # $ MISSING: getXPath=match +root.findall(match, namespaces=ns) # $ MISSING: getXPath=match +root.findtext(match, default=None, namespaces=ns) # $ MISSING: getXPath=match + +from xml.etree.ElementTree import ElementTree +tree = ElementTree() +tree.parse("index.xhtml") + +tree.find(match, namespaces=ns) # $ MISSING: getXPath=match +tree.findall(match, namespaces=ns) # $ MISSING: getXPath=match +tree.findtext(match, default=None, namespaces=ns) # $ MISSING: getXPath=match From 80be767a7ae7c88f83f6e08fd0832b7d6cfa5538 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Wed, 2 Mar 2022 12:59:34 +0100 Subject: [PATCH 19/22] python: implement stdlib xpath support --- .../lib/semmle/python/frameworks/Stdlib.qll | 64 +++++++++++++++++++ .../frameworks/stdlib/XPathExecution.py | 12 ++-- 2 files changed, 70 insertions(+), 6 deletions(-) diff --git a/python/ql/lib/semmle/python/frameworks/Stdlib.qll b/python/ql/lib/semmle/python/frameworks/Stdlib.qll index a4486f3504f..772f1b7746d 100644 --- a/python/ql/lib/semmle/python/frameworks/Stdlib.qll +++ b/python/ql/lib/semmle/python/frameworks/Stdlib.qll @@ -2809,6 +2809,70 @@ private module StdlibPrivate { override string getKind() { result = Escaping::getRegexKind() } } + // --------------------------------------------------------------------------- + // xml.etree.ElementTree + // --------------------------------------------------------------------------- + /** + * An instance of `xml.etree.ElementTree.ElementTree`. + * + * See https://docs.python.org/3.10/library/xml.etree.elementtree.html#xml.etree.ElementTree.ElementTree + */ + private API::Node elementTreeInstance() { + //parse to a tree + result = + API::moduleImport("xml") + .getMember("etree") + .getMember("ElementTree") + .getMember("parse") + .getReturn() + or + // construct a tree without parsing + result = + API::moduleImport("xml") + .getMember("etree") + .getMember("ElementTree") + .getMember("ElementTree") + .getReturn() + } + + /** + * An instance of `xml.etree.ElementTree.Element`. + * + * See https://docs.python.org/3.10/library/xml.etree.elementtree.html#xml.etree.ElementTree.Element + */ + private API::Node elementInstance() { + // parse or go to the root of a tree + result = elementTreeInstance().getMember(["parse", "getroot"]).getReturn() + or + // parse directly to an element + result = + API::moduleImport("xml") + .getMember("etree") + .getMember("ElementTree") + .getMember(["fromstring", "fromstringlist", "XML"]) + .getReturn() + } + + /** + * A call to a find method on a tree or an element will execute an XPath expression. + */ + private class ElementTreeFindCall extends XPathExecution::Range, DataFlow::CallCfgNode { + string methodName; + + ElementTreeFindCall() { + methodName in ["find", "findall", "findtext"] and + ( + this = elementTreeInstance().getMember(methodName).getACall() + or + this = elementInstance().getMember(methodName).getACall() + ) + } + + override DataFlow::Node getXPath() { result in [this.getArg(0), this.getArgByName("match")] } + + override string getName() { result = "xml.etree" } + } + // --------------------------------------------------------------------------- // urllib // --------------------------------------------------------------------------- diff --git a/python/ql/test/library-tests/frameworks/stdlib/XPathExecution.py b/python/ql/test/library-tests/frameworks/stdlib/XPathExecution.py index d6ca13766d6..107af07b254 100644 --- a/python/ql/test/library-tests/frameworks/stdlib/XPathExecution.py +++ b/python/ql/test/library-tests/frameworks/stdlib/XPathExecution.py @@ -5,14 +5,14 @@ import xml.etree.ElementTree as ET tree = ET.parse('country_data.xml') root = tree.getroot() -root.find(match, namespaces=ns) # $ MISSING: getXPath=match -root.findall(match, namespaces=ns) # $ MISSING: getXPath=match -root.findtext(match, default=None, namespaces=ns) # $ MISSING: getXPath=match +root.find(match, namespaces=ns) # $ getXPath=match +root.findall(match, namespaces=ns) # $ getXPath=match +root.findtext(match, default=None, namespaces=ns) # $ getXPath=match from xml.etree.ElementTree import ElementTree tree = ElementTree() tree.parse("index.xhtml") -tree.find(match, namespaces=ns) # $ MISSING: getXPath=match -tree.findall(match, namespaces=ns) # $ MISSING: getXPath=match -tree.findtext(match, default=None, namespaces=ns) # $ MISSING: getXPath=match +tree.find(match, namespaces=ns) # $ getXPath=match +tree.findall(match, namespaces=ns) # $ getXPath=match +tree.findtext(match, default=None, namespaces=ns) # $ getXPath=match From ee45e799481356e0a59164f42ac8e4558aa09e61 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Wed, 2 Mar 2022 13:10:23 +0100 Subject: [PATCH 20/22] python: Create XML modulein Concepts to prepare for XXE and other XML related modelling --- python/ql/lib/semmle/python/Concepts.qll | 133 +++++++++--------- .../lib/semmle/python/frameworks/Libxml2.qll | 2 +- .../ql/lib/semmle/python/frameworks/Lxml.qll | 6 +- .../lib/semmle/python/frameworks/Stdlib.qll | 2 +- .../test/experimental/meta/ConceptsTest.qll | 4 +- 5 files changed, 75 insertions(+), 72 deletions(-) diff --git a/python/ql/lib/semmle/python/Concepts.qll b/python/ql/lib/semmle/python/Concepts.qll index c0bd746df70..c03d5277e0c 100644 --- a/python/ql/lib/semmle/python/Concepts.qll +++ b/python/ql/lib/semmle/python/Concepts.qll @@ -453,99 +453,102 @@ module RegexExecution { } } -/** - * A data-flow node that constructs an XPath expression. - * - * Often, it is worthy of an alert if an XPath expression is constructed such that - * executing it would be a security risk. - * - * If it is important that the XPath expression is indeed executed, then use `XPathExecution`. - * - * Extend this class to refine existing API models. If you want to model new APIs, - * extend `XPathConstruction::Range` instead. - */ -class XPathConstruction extends DataFlow::Node { - XPathConstruction::Range range; - - XPathConstruction() { this = range } - - /** Gets the argument that specifies the XPath expressions to be constructed. */ - DataFlow::Node getXPath() { result = range.getXPath() } - - /** - * Gets the name of this XPath expression construction, typically the name of an executing method. - * This is used for nice alert messages and should include the module if possible. - */ - string getName() { result = range.getName() } -} - -/** Provides a class for modeling new XPath construction APIs. */ -module XPathConstruction { +/** Provides classes for modeling XML-related APIs. */ +module XML { /** * A data-flow node that constructs an XPath expression. * * Often, it is worthy of an alert if an XPath expression is constructed such that * executing it would be a security risk. * - * Extend this class to model new APIs. If you want to refine existing API models, - * extend `XPathConstruction` instead. + * If it is important that the XPath expression is indeed executed, then use `XPathExecution`. + * + * Extend this class to refine existing API models. If you want to model new APIs, + * extend `XPathConstruction::Range` instead. */ - abstract class Range extends DataFlow::Node { + class XPathConstruction extends DataFlow::Node { + XPathConstruction::Range range; + + XPathConstruction() { this = range } + /** Gets the argument that specifies the XPath expressions to be constructed. */ - abstract DataFlow::Node getXPath(); + DataFlow::Node getXPath() { result = range.getXPath() } /** * Gets the name of this XPath expression construction, typically the name of an executing method. * This is used for nice alert messages and should include the module if possible. */ - abstract string getName(); + string getName() { result = range.getName() } } -} -/** - * A data-flow node that executes a xpath expression. - * - * If the context of interest is such that merely constructing an XPath expression - * would be valuabe to report, then consider using `XPathConstruction`. - * - * Extend this class to refine existing API models. If you want to model new APIs, - * extend `XPathExecution::Range` instead. - */ -class XPathExecution extends DataFlow::Node { - XPathExecution::Range range; + /** Provides a class for modeling new XPath construction APIs. */ + module XPathConstruction { + /** + * A data-flow node that constructs an XPath expression. + * + * Often, it is worthy of an alert if an XPath expression is constructed such that + * executing it would be a security risk. + * + * Extend this class to model new APIs. If you want to refine existing API models, + * extend `XPathConstruction` instead. + */ + abstract class Range extends DataFlow::Node { + /** Gets the argument that specifies the XPath expressions to be constructed. */ + abstract DataFlow::Node getXPath(); - XPathExecution() { this = range } - - /** Gets the data flow node for the XPath expression being executed by this node. */ - DataFlow::Node getXPath() { result = range.getXPath() } + /** + * Gets the name of this XPath expression construction, typically the name of an executing method. + * This is used for nice alert messages and should include the module if possible. + */ + abstract string getName(); + } + } /** - * Gets the name of this XPath expression execution, typically the name of an executing method. - * This is used for nice alert messages and should include the module if possible. - */ - string getName() { result = range.getName() } -} - -/** Provides classes for modeling new regular-expression execution APIs. */ -module XPathExecution { - /** - * A data-flow node that executes a XPath expression. + * A data-flow node that executes a xpath expression. * * If the context of interest is such that merely constructing an XPath expression * would be valuabe to report, then consider using `XPathConstruction`. * - * Extend this class to model new APIs. If you want to refine existing API models, - * extend `XPathExecution` instead. + * Extend this class to refine existing API models. If you want to model new APIs, + * extend `XPathExecution::Range` instead. */ - abstract class Range extends DataFlow::Node { + class XPathExecution extends DataFlow::Node { + XPathExecution::Range range; + + XPathExecution() { this = range } + /** Gets the data flow node for the XPath expression being executed by this node. */ - abstract DataFlow::Node getXPath(); + DataFlow::Node getXPath() { result = range.getXPath() } /** - * Gets the name of this xpath expression execution, typically the name of an executing method. + * Gets the name of this XPath expression execution, typically the name of an executing method. * This is used for nice alert messages and should include the module if possible. */ - abstract string getName(); + string getName() { result = range.getName() } + } + + /** Provides classes for modeling new regular-expression execution APIs. */ + module XPathExecution { + /** + * A data-flow node that executes a XPath expression. + * + * If the context of interest is such that merely constructing an XPath expression + * would be valuabe to report, then consider using `XPathConstruction`. + * + * Extend this class to model new APIs. If you want to refine existing API models, + * extend `XPathExecution` instead. + */ + abstract class Range extends DataFlow::Node { + /** Gets the data flow node for the XPath expression being executed by this node. */ + abstract DataFlow::Node getXPath(); + + /** + * Gets the name of this xpath expression execution, typically the name of an executing method. + * This is used for nice alert messages and should include the module if possible. + */ + abstract string getName(); + } } } diff --git a/python/ql/lib/semmle/python/frameworks/Libxml2.qll b/python/ql/lib/semmle/python/frameworks/Libxml2.qll index 5494a548898..19b1da970b2 100644 --- a/python/ql/lib/semmle/python/frameworks/Libxml2.qll +++ b/python/ql/lib/semmle/python/frameworks/Libxml2.qll @@ -28,7 +28,7 @@ private module Libxml2 { * * See http://xmlsoft.org/python.html */ - class XpathEvalCall extends XPathExecution::Range, DataFlow::CallCfgNode { + class XpathEvalCall extends XML::XPathExecution::Range, DataFlow::CallCfgNode { XpathEvalCall() { this = API::moduleImport("libxml2") diff --git a/python/ql/lib/semmle/python/frameworks/Lxml.qll b/python/ql/lib/semmle/python/frameworks/Lxml.qll index 9afbc448a02..9259668a5c8 100644 --- a/python/ql/lib/semmle/python/frameworks/Lxml.qll +++ b/python/ql/lib/semmle/python/frameworks/Lxml.qll @@ -30,7 +30,7 @@ private module Lxml { * - https://lxml.de/apidoc/lxml.etree.html#lxml.etree.XPath * - https://lxml.de/apidoc/lxml.etree.html#lxml.etree.ETXPath */ - private class XPathClassCall extends XPathConstruction::Range, DataFlow::CallCfgNode { + private class XPathClassCall extends XML::XPathConstruction::Range, DataFlow::CallCfgNode { XPathClassCall() { this = API::moduleImport("lxml").getMember("etree").getMember(["XPath", "ETXPath"]).getACall() } @@ -55,7 +55,7 @@ private module Lxml { * - https://lxml.de/apidoc/lxml.etree.html#lxml.etree.HTML * - https://lxml.de/apidoc/lxml.etree.html#lxml.etree.XML */ - class XPathCall extends XPathExecution::Range, DataFlow::CallCfgNode { + class XPathCall extends XML::XPathExecution::Range, DataFlow::CallCfgNode { XPathCall() { this = API::moduleImport("lxml") @@ -71,7 +71,7 @@ private module Lxml { override string getName() { result = "lxml.etree" } } - class XPathEvaluatorCall extends XPathExecution::Range, DataFlow::CallCfgNode { + class XPathEvaluatorCall extends XML::XPathExecution::Range, DataFlow::CallCfgNode { XPathEvaluatorCall() { this = API::moduleImport("lxml") diff --git a/python/ql/lib/semmle/python/frameworks/Stdlib.qll b/python/ql/lib/semmle/python/frameworks/Stdlib.qll index 772f1b7746d..fb2d701ce79 100644 --- a/python/ql/lib/semmle/python/frameworks/Stdlib.qll +++ b/python/ql/lib/semmle/python/frameworks/Stdlib.qll @@ -2856,7 +2856,7 @@ private module StdlibPrivate { /** * A call to a find method on a tree or an element will execute an XPath expression. */ - private class ElementTreeFindCall extends XPathExecution::Range, DataFlow::CallCfgNode { + private class ElementTreeFindCall extends XML::XPathExecution::Range, DataFlow::CallCfgNode { string methodName; ElementTreeFindCall() { diff --git a/python/ql/test/experimental/meta/ConceptsTest.qll b/python/ql/test/experimental/meta/ConceptsTest.qll index 0ad19e76db5..8f9435f633f 100644 --- a/python/ql/test/experimental/meta/ConceptsTest.qll +++ b/python/ql/test/experimental/meta/ConceptsTest.qll @@ -171,7 +171,7 @@ class XPathConstructionTest extends InlineExpectationsTest { override predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and - exists(XPathConstruction e, DataFlow::Node xpath | + exists(XML::XPathConstruction e, DataFlow::Node xpath | exists(location.getFile().getRelativePath()) and xpath = e.getXPath() and location = e.getLocation() and @@ -189,7 +189,7 @@ class XPathExecutionTest extends InlineExpectationsTest { override predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and - exists(XPathExecution e, DataFlow::Node xpath | + exists(XML::XPathExecution e, DataFlow::Node xpath | exists(location.getFile().getRelativePath()) and xpath = e.getXPath() and location = e.getLocation() and From 6946ae931a7aa07e541c44c02da3aa482a052085 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Wed, 2 Mar 2022 17:12:48 +0100 Subject: [PATCH 21/22] python: missed a spot.. --- .../python/security/dataflow/XpathInjectionCustomizations.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/lib/semmle/python/security/dataflow/XpathInjectionCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/XpathInjectionCustomizations.qll index 00407a39748..8b8a839819a 100644 --- a/python/ql/lib/semmle/python/security/dataflow/XpathInjectionCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/XpathInjectionCustomizations.qll @@ -43,13 +43,13 @@ module XpathInjection { * A construction of an XPath expression, considered as a sink. */ class XPathConstructionArg extends Sink { - XPathConstructionArg() { this = any(XPathConstruction c).getXPath() } + XPathConstructionArg() { this = any(XML::XPathConstruction c).getXPath() } } /** * An execution of an XPath expression, considered as a sink. */ class XPathExecutionArg extends Sink { - XPathExecutionArg() { this = any(XPathExecution e).getXPath() } + XPathExecutionArg() { this = any(XML::XPathExecution e).getXPath() } } } From d0a393e8d181f6bf7aed6f4087021e52cb3f06b2 Mon Sep 17 00:00:00 2001 From: yoff Date: Fri, 4 Mar 2022 10:56:53 +0100 Subject: [PATCH 22/22] Update python/ql/test/library-tests/frameworks/stdlib/XPathExecution.py Co-authored-by: Rasmus Wriedt Larsen --- .../ql/test/library-tests/frameworks/stdlib/XPathExecution.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/python/ql/test/library-tests/frameworks/stdlib/XPathExecution.py b/python/ql/test/library-tests/frameworks/stdlib/XPathExecution.py index 107af07b254..98bdaefac27 100644 --- a/python/ql/test/library-tests/frameworks/stdlib/XPathExecution.py +++ b/python/ql/test/library-tests/frameworks/stdlib/XPathExecution.py @@ -9,8 +9,7 @@ root.find(match, namespaces=ns) # $ getXPath=match root.findall(match, namespaces=ns) # $ getXPath=match root.findtext(match, default=None, namespaces=ns) # $ getXPath=match -from xml.etree.ElementTree import ElementTree -tree = ElementTree() +tree = ET.ElementTree() tree.parse("index.xhtml") tree.find(match, namespaces=ns) # $ getXPath=match