From 55705d4f1b35d2bca0f760d19274ac985db5fd52 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 14 Oct 2026 15:06:05 +0100 Subject: [PATCH 1/3] Use instanceof for threat model sources Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../security/dataflow/CodeInjectionCustomizations.qll | 7 +++---- .../security/dataflow/CommandInjectionCustomizations.qll | 7 +++---- .../security/dataflow/CookieInjectionCustomizations.qll | 7 +++---- .../dataflow/HttpHeaderInjectionCustomizations.qll | 7 +++---- .../security/dataflow/LdapInjectionCustomizations.qll | 7 +++---- .../security/dataflow/LogInjectionCustomizations.qll | 7 +++---- .../security/dataflow/PamAuthorizationCustomizations.qll | 7 +++---- .../security/dataflow/PathInjectionCustomizations.qll | 7 +++---- .../security/dataflow/PolynomialReDoSCustomizations.qll | 7 +++---- .../security/dataflow/ReflectedXSSCustomizations.qll | 7 +++---- .../security/dataflow/RegexInjectionCustomizations.qll | 7 +++---- .../dataflow/ServerSideRequestForgeryCustomizations.qll | 7 +++---- .../security/dataflow/SqlInjectionCustomizations.qll | 7 +++---- .../security/dataflow/TemplateInjectionCustomizations.qll | 7 +++---- .../dataflow/UnsafeDeserializationCustomizations.qll | 7 +++---- .../python/security/dataflow/UrlRedirectCustomizations.qll | 7 +++---- .../security/dataflow/XpathInjectionCustomizations.qll | 7 +++---- .../Security/CWE-091/XsltInjectionCustomizations.qll | 7 +++---- .../security/dataflow/PromptInjectionCustomizations.qll | 7 +++---- 19 files changed, 57 insertions(+), 76 deletions(-) diff --git a/python/ql/lib/semmle/python/security/dataflow/CodeInjectionCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/CodeInjectionCustomizations.qll index 5a7e5882e449..87e95d8a5542 100644 --- a/python/ql/lib/semmle/python/security/dataflow/CodeInjectionCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/CodeInjectionCustomizations.qll @@ -37,10 +37,9 @@ module CodeInjection { */ deprecated class RemoteFlowSourceAsSource = ActiveThreatModelSourceAsSource; - /** - * An active threat-model source, considered as a flow source. - */ - private class ActiveThreatModelSourceAsSource extends Source, ActiveThreatModelSource { } + /** An active threat-model source, considered as a flow source. */ + private class ActiveThreatModelSourceAsSource extends Source instanceof ActiveThreatModelSource { + } /** * A code execution, considered as a flow sink. diff --git a/python/ql/lib/semmle/python/security/dataflow/CommandInjectionCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/CommandInjectionCustomizations.qll index facb422e7285..755a02b0efc2 100644 --- a/python/ql/lib/semmle/python/security/dataflow/CommandInjectionCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/CommandInjectionCustomizations.qll @@ -37,10 +37,9 @@ module CommandInjection { */ deprecated class RemoteFlowSourceAsSource = ActiveThreatModelSourceAsSource; - /** - * An active threat-model source, considered as a flow source. - */ - private class ActiveThreatModelSourceAsSource extends Source, ActiveThreatModelSource { } + /** An active threat-model source, considered as a flow source. */ + private class ActiveThreatModelSourceAsSource extends Source instanceof ActiveThreatModelSource { + } /** * A command execution, considered as a flow sink. diff --git a/python/ql/lib/semmle/python/security/dataflow/CookieInjectionCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/CookieInjectionCustomizations.qll index cee2b7b98e73..ba5499d10ee2 100644 --- a/python/ql/lib/semmle/python/security/dataflow/CookieInjectionCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/CookieInjectionCustomizations.qll @@ -35,10 +35,9 @@ module CookieInjection { */ deprecated class RemoteFlowSourceAsSource = ActiveThreatModelSourceAsSource; - /** - * An active threat-model source, considered as a flow source. - */ - private class ActiveThreatModelSourceAsSource extends Source, ActiveThreatModelSource { } + /** An active threat-model source, considered as a flow source. */ + private class ActiveThreatModelSourceAsSource extends Source instanceof ActiveThreatModelSource { + } /** * A write to a cookie, considered as a sink. diff --git a/python/ql/lib/semmle/python/security/dataflow/HttpHeaderInjectionCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/HttpHeaderInjectionCustomizations.qll index 92cd46a3408a..cd651e0b1a88 100644 --- a/python/ql/lib/semmle/python/security/dataflow/HttpHeaderInjectionCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/HttpHeaderInjectionCustomizations.qll @@ -36,10 +36,9 @@ module HttpHeaderInjection { */ deprecated class RemoteFlowSourceAsSource = ActiveThreatModelSourceAsSource; - /** - * An active threat-model source, considered as a flow source. - */ - private class ActiveThreatModelSourceAsSource extends Source, ActiveThreatModelSource { } + /** An active threat-model source, considered as a flow source. */ + private class ActiveThreatModelSourceAsSource extends Source instanceof ActiveThreatModelSource { + } /** * A HTTP header write, considered as a flow sink. diff --git a/python/ql/lib/semmle/python/security/dataflow/LdapInjectionCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/LdapInjectionCustomizations.qll index e67d02dc67e9..d69fe08308e1 100644 --- a/python/ql/lib/semmle/python/security/dataflow/LdapInjectionCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/LdapInjectionCustomizations.qll @@ -46,10 +46,9 @@ module LdapInjection { */ deprecated class RemoteFlowSourceAsSource = ActiveThreatModelSourceAsSource; - /** - * An active threat-model source, considered as a flow source. - */ - private class ActiveThreatModelSourceAsSource extends Source, ActiveThreatModelSource { } + /** An active threat-model source, considered as a flow source. */ + private class ActiveThreatModelSourceAsSource extends Source instanceof ActiveThreatModelSource { + } /** * A logging operation, considered as a flow sink. diff --git a/python/ql/lib/semmle/python/security/dataflow/LogInjectionCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/LogInjectionCustomizations.qll index 98c767df2894..26a7b4723dfd 100644 --- a/python/ql/lib/semmle/python/security/dataflow/LogInjectionCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/LogInjectionCustomizations.qll @@ -37,10 +37,9 @@ module LogInjection { */ deprecated class RemoteFlowSourceAsSource = ActiveThreatModelSourceAsSource; - /** - * An active threat-model source, considered as a flow source. - */ - private class ActiveThreatModelSourceAsSource extends Source, ActiveThreatModelSource { } + /** An active threat-model source, considered as a flow source. */ + private class ActiveThreatModelSourceAsSource extends Source instanceof ActiveThreatModelSource { + } /** * A logging operation, considered as a flow sink. diff --git a/python/ql/lib/semmle/python/security/dataflow/PamAuthorizationCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/PamAuthorizationCustomizations.qll index eb858be8f95d..0e9dfe390694 100644 --- a/python/ql/lib/semmle/python/security/dataflow/PamAuthorizationCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/PamAuthorizationCustomizations.qll @@ -44,10 +44,9 @@ module PamAuthorizationCustomizations { */ deprecated class RemoteFlowSourceAsSource = ActiveThreatModelSourceAsSource; - /** - * An active threat-model source, considered as a flow source. - */ - private class ActiveThreatModelSourceAsSource extends Source, ActiveThreatModelSource { } + /** An active threat-model source, considered as a flow source. */ + private class ActiveThreatModelSourceAsSource extends Source instanceof ActiveThreatModelSource { + } /** * A vulnerable `pam_authenticate` call considered as a flow sink. diff --git a/python/ql/lib/semmle/python/security/dataflow/PathInjectionCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/PathInjectionCustomizations.qll index 7121faa19ffb..ab43cbd861b6 100644 --- a/python/ql/lib/semmle/python/security/dataflow/PathInjectionCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/PathInjectionCustomizations.qll @@ -47,10 +47,9 @@ module PathInjection { */ deprecated class RemoteFlowSourceAsSource = ActiveThreatModelSourceAsSource; - /** - * An active threat-model source, considered as a flow source. - */ - private class ActiveThreatModelSourceAsSource extends Source, ActiveThreatModelSource { } + /** An active threat-model source, considered as a flow source. */ + private class ActiveThreatModelSourceAsSource extends Source instanceof ActiveThreatModelSource { + } /** * A file system access, considered as a flow sink. diff --git a/python/ql/lib/semmle/python/security/dataflow/PolynomialReDoSCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/PolynomialReDoSCustomizations.qll index 1e9148517bf2..18c50aca6ce9 100644 --- a/python/ql/lib/semmle/python/security/dataflow/PolynomialReDoSCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/PolynomialReDoSCustomizations.qll @@ -56,10 +56,9 @@ module PolynomialReDoS { */ deprecated class RemoteFlowSourceAsSource = ActiveThreatModelSourceAsSource; - /** - * An active threat-model source, considered as a flow source. - */ - private class ActiveThreatModelSourceAsSource extends Source, ActiveThreatModelSource { } + /** An active threat-model source, considered as a flow source. */ + private class ActiveThreatModelSourceAsSource extends Source instanceof ActiveThreatModelSource { + } /** * A regex execution, considered as a flow sink. diff --git a/python/ql/lib/semmle/python/security/dataflow/ReflectedXSSCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/ReflectedXSSCustomizations.qll index 0ef2234a5772..ced98aa4d5aa 100644 --- a/python/ql/lib/semmle/python/security/dataflow/ReflectedXSSCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/ReflectedXSSCustomizations.qll @@ -37,10 +37,9 @@ module ReflectedXss { */ deprecated class RemoteFlowSourceAsSource = ActiveThreatModelSourceAsSource; - /** - * An active threat-model source, considered as a flow source. - */ - private class ActiveThreatModelSourceAsSource extends Source, ActiveThreatModelSource { } + /** An active threat-model source, considered as a flow source. */ + private class ActiveThreatModelSourceAsSource extends Source instanceof ActiveThreatModelSource { + } /** * A data flow sink for "reflected cross-site scripting" vulnerabilities. diff --git a/python/ql/lib/semmle/python/security/dataflow/RegexInjectionCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/RegexInjectionCustomizations.qll index 559b1f66e7e6..32c9430a8656 100644 --- a/python/ql/lib/semmle/python/security/dataflow/RegexInjectionCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/RegexInjectionCustomizations.qll @@ -44,10 +44,9 @@ module RegexInjection { */ deprecated class RemoteFlowSourceAsSource = ActiveThreatModelSourceAsSource; - /** - * An active threat-model source, considered as a flow source. - */ - private class ActiveThreatModelSourceAsSource extends Source, ActiveThreatModelSource { } + /** An active threat-model source, considered as a flow source. */ + private class ActiveThreatModelSourceAsSource extends Source instanceof ActiveThreatModelSource { + } /** * A regex escaping, considered as a sanitizer. diff --git a/python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgeryCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgeryCustomizations.qll index d1b649118cb1..506f7fb6ecd3 100644 --- a/python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgeryCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgeryCustomizations.qll @@ -50,10 +50,9 @@ module ServerSideRequestForgery { */ deprecated class RemoteFlowSourceAsSource = ActiveThreatModelSourceAsSource; - /** - * An active threat-model source, considered as a flow source. - */ - private class ActiveThreatModelSourceAsSource extends Source, ActiveThreatModelSource { } + /** An active threat-model source, considered as a flow source. */ + private class ActiveThreatModelSourceAsSource extends Source instanceof ActiveThreatModelSource { + } /** The URL of an HTTP request, considered as a sink. */ class HttpRequestUrlAsSink extends Sink { diff --git a/python/ql/lib/semmle/python/security/dataflow/SqlInjectionCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/SqlInjectionCustomizations.qll index ee6f17b03d2c..071cbf512ffe 100644 --- a/python/ql/lib/semmle/python/security/dataflow/SqlInjectionCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/SqlInjectionCustomizations.qll @@ -36,10 +36,9 @@ module SqlInjection { */ deprecated class RemoteFlowSourceAsSource = ActiveThreatModelSourceAsSource; - /** - * An active threat-model source, considered as a flow source. - */ - private class ActiveThreatModelSourceAsSource extends Source, ActiveThreatModelSource { } + /** An active threat-model source, considered as a flow source. */ + private class ActiveThreatModelSourceAsSource extends Source instanceof ActiveThreatModelSource { + } /** * A SQL statement of a SQL construction, considered as a flow sink. diff --git a/python/ql/lib/semmle/python/security/dataflow/TemplateInjectionCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/TemplateInjectionCustomizations.qll index e61d55253090..3449eeaf3856 100644 --- a/python/ql/lib/semmle/python/security/dataflow/TemplateInjectionCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/TemplateInjectionCustomizations.qll @@ -31,10 +31,9 @@ module TemplateInjection { */ abstract class Sanitizer extends DataFlow::Node { } - /** - * An active threat-model source, considered as a flow source. - */ - private class ActiveThreatModelSourceAsSource extends Source, ActiveThreatModelSource { } + /** An active threat-model source, considered as a flow source. */ + private class ActiveThreatModelSourceAsSource extends Source instanceof ActiveThreatModelSource { + } /** * A SQL statement of a SQL construction, considered as a flow sink. diff --git a/python/ql/lib/semmle/python/security/dataflow/UnsafeDeserializationCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/UnsafeDeserializationCustomizations.qll index 17450bb82d96..74586e768768 100644 --- a/python/ql/lib/semmle/python/security/dataflow/UnsafeDeserializationCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/UnsafeDeserializationCustomizations.qll @@ -37,10 +37,9 @@ module UnsafeDeserialization { */ deprecated class RemoteFlowSourceAsSource = ActiveThreatModelSourceAsSource; - /** - * An active threat-model source, considered as a flow source. - */ - private class ActiveThreatModelSourceAsSource extends Source, ActiveThreatModelSource { } + /** An active threat-model source, considered as a flow source. */ + private class ActiveThreatModelSourceAsSource extends Source instanceof ActiveThreatModelSource { + } /** * An insecure decoding, considered as a flow sink. diff --git a/python/ql/lib/semmle/python/security/dataflow/UrlRedirectCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/UrlRedirectCustomizations.qll index 75a638fc3a42..471af9756d23 100644 --- a/python/ql/lib/semmle/python/security/dataflow/UrlRedirectCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/UrlRedirectCustomizations.qll @@ -82,10 +82,9 @@ module UrlRedirect { */ deprecated class RemoteFlowSourceAsSource = ActiveThreatModelSourceAsSource; - /** - * An active threat-model source, considered as a flow source. - */ - private class ActiveThreatModelSourceAsSource extends Source, ActiveThreatModelSource { } + /** An active threat-model source, considered as a flow source. */ + private class ActiveThreatModelSourceAsSource extends Source instanceof ActiveThreatModelSource { + } /** * A HTTP redirect response, considered as a flow sink. diff --git a/python/ql/lib/semmle/python/security/dataflow/XpathInjectionCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/XpathInjectionCustomizations.qll index 10b47f174390..992ed49dca98 100644 --- a/python/ql/lib/semmle/python/security/dataflow/XpathInjectionCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/XpathInjectionCustomizations.qll @@ -34,10 +34,9 @@ module XpathInjection { */ deprecated class RemoteFlowSourceAsSource = ActiveThreatModelSourceAsSource; - /** - * An active threat-model source, considered as a flow source. - */ - private class ActiveThreatModelSourceAsSource extends Source, ActiveThreatModelSource { } + /** An active threat-model source, considered as a flow source. */ + private class ActiveThreatModelSourceAsSource extends Source instanceof ActiveThreatModelSource { + } /** * A construction of an XPath expression, considered as a sink. diff --git a/python/ql/src/experimental/Security/CWE-091/XsltInjectionCustomizations.qll b/python/ql/src/experimental/Security/CWE-091/XsltInjectionCustomizations.qll index 6e6abea97f95..ab3ae8e703a3 100644 --- a/python/ql/src/experimental/Security/CWE-091/XsltInjectionCustomizations.qll +++ b/python/ql/src/experimental/Security/CWE-091/XsltInjectionCustomizations.qll @@ -37,10 +37,9 @@ module XsltInjection { */ deprecated class RemoteFlowSourceAsSource = ActiveThreatModelSourceAsSource; - /** - * An active threat-model source, considered as a flow source. - */ - private class ActiveThreatModelSourceAsSource extends Source, ActiveThreatModelSource { } + /** An active threat-model source, considered as a flow source. */ + private class ActiveThreatModelSourceAsSource extends Source instanceof ActiveThreatModelSource { + } /** * An XSLT construction, considered as a flow sink. diff --git a/python/ql/src/experimental/semmle/python/security/dataflow/PromptInjectionCustomizations.qll b/python/ql/src/experimental/semmle/python/security/dataflow/PromptInjectionCustomizations.qll index b214ec87d4fc..95e611cad7d6 100644 --- a/python/ql/src/experimental/semmle/python/security/dataflow/PromptInjectionCustomizations.qll +++ b/python/ql/src/experimental/semmle/python/security/dataflow/PromptInjectionCustomizations.qll @@ -34,10 +34,9 @@ module PromptInjection { */ abstract class Sanitizer extends DataFlow::Node { } - /** - * An active threat-model source, considered as a flow source. - */ - private class ActiveThreatModelSourceAsSource extends Source, ActiveThreatModelSource { } + /** An active threat-model source, considered as a flow source. */ + private class ActiveThreatModelSourceAsSource extends Source instanceof ActiveThreatModelSource { + } /** * A prompt to an AI model, considered as a flow sink. From 9b363ee9cd5bdd040dafcb94db07ef4f27989473 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 14 Oct 2026 16:31:37 +0100 Subject: [PATCH 2/3] Make queries use ActiveThreatModelSource, not RemoteFlowSource This means that these query will respect the threat model that is being used, rather than just using remote flow sources every time. The default threat model is "remote". --- .../dataflow/NoSqlInjectionCustomizations.qll | 11 ++++++++--- .../security/dataflow/XmlBombCustomizations.qll | 11 ++++++++--- .../python/security/dataflow/XxeCustomizations.qll | 11 ++++++++--- .../Security/CWE-020-ExternalAPIs/ExternalAPIs.qll | 6 +++--- .../Security/CWE-176/UnicodeBypassValidationQuery.qll | 3 +-- .../src/experimental/Security/CWE-346/CorsBypass.ql | 3 ++- .../src/experimental/Security/CWE-770/UnicodeDoS.ql | 3 +-- .../src/experimental/Security/UnsafeUnpackQuery.qll | 5 ++--- .../semmle/python/security/DecompressionBomb.qll | 4 ++-- .../semmle/python/security/LdapInsecureAuth.qll | 4 ++-- .../semmle/python/security/RemoteCommandExecution.qll | 4 ++-- .../semmle/python/security/TimingAttack.qll | 6 +++--- .../semmle/python/security/dataflow/EmailXss.qll | 3 +-- .../semmle/python/security/injection/CsvInjection.qll | 4 ++-- 14 files changed, 45 insertions(+), 33 deletions(-) diff --git a/python/ql/lib/semmle/python/security/dataflow/NoSqlInjectionCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/NoSqlInjectionCustomizations.qll index d708081a7f51..abe2d5690b86 100644 --- a/python/ql/lib/semmle/python/security/dataflow/NoSqlInjectionCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/NoSqlInjectionCustomizations.qll @@ -6,7 +6,6 @@ import python import semmle.python.dataflow.new.DataFlow -import semmle.python.dataflow.new.RemoteFlowSources import semmle.python.Concepts /** @@ -63,8 +62,14 @@ module NoSqlInjection { abstract DataFlow::Node getOutput(); } - /** A remote flow source considered a source of user controlled strings. */ - class RemoteFlowSourceAsStringSource extends RemoteFlowSource, StringSource { } + /** + * DEPRECATED: Use `ActiveThreatModelSource` from Concepts instead! + */ + deprecated class RemoteFlowSourceAsStringSource = ActiveThreatModelSourceAsStringSource; + + /** An active threat-model source considered a source of user controlled strings. */ + private class ActiveThreatModelSourceAsStringSource extends StringSource instanceof ActiveThreatModelSource + { } /** A NoSQL query that is vulnerable to user controlled strings. */ class NoSqlExecutionAsStringSink extends StringSink { diff --git a/python/ql/lib/semmle/python/security/dataflow/XmlBombCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/XmlBombCustomizations.qll index 317bee333871..5fb3aee77e3d 100644 --- a/python/ql/lib/semmle/python/security/dataflow/XmlBombCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/XmlBombCustomizations.qll @@ -7,7 +7,6 @@ private import python private import semmle.python.dataflow.new.DataFlow private import semmle.python.Concepts -private import semmle.python.dataflow.new.RemoteFlowSources /** * Provides default sources, sinks and sanitizers for detecting "XML bomb" @@ -29,8 +28,14 @@ module XmlBomb { */ abstract class Sanitizer extends DataFlow::Node { } - /** A source of remote user input, considered as a flow source for XML bomb vulnerabilities. */ - class RemoteFlowSourceAsSource extends Source instanceof RemoteFlowSource { } + /** + * DEPRECATED: Use `ActiveThreatModelSource` from Concepts instead! + */ + deprecated class RemoteFlowSourceAsSource = ActiveThreatModelSourceAsSource; + + /** An active threat-model source, considered as a flow source. */ + private class ActiveThreatModelSourceAsSource extends Source instanceof ActiveThreatModelSource { + } /** * A call to an XML parser that is vulnerable to XML bombs. diff --git a/python/ql/lib/semmle/python/security/dataflow/XxeCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/XxeCustomizations.qll index c98e8153be90..786b6160e3b9 100644 --- a/python/ql/lib/semmle/python/security/dataflow/XxeCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/XxeCustomizations.qll @@ -7,7 +7,6 @@ private import python private import semmle.python.dataflow.new.DataFlow private import semmle.python.Concepts -private import semmle.python.dataflow.new.RemoteFlowSources /** * Provides default sources, sinks and sanitizers for detecting "XML External Entity (XXE)" @@ -29,8 +28,14 @@ module Xxe { */ abstract class Sanitizer extends DataFlow::Node { } - /** A source of remote user input, considered as a flow source for XXE vulnerabilities. */ - class RemoteFlowSourceAsSource extends Source instanceof RemoteFlowSource { } + /** + * DEPRECATED: Use `ActiveThreatModelSource` from Concepts instead! + */ + deprecated class RemoteFlowSourceAsSource = ActiveThreatModelSourceAsSource; + + /** An active threat-model source, considered as a flow source. */ + private class ActiveThreatModelSourceAsSource extends Source instanceof ActiveThreatModelSource { + } /** * A call to an XML parser that is vulnerable to XXE. diff --git a/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll b/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll index 9c12845a0cad..7baec4738b08 100644 --- a/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll +++ b/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll @@ -6,7 +6,7 @@ private import python import semmle.python.dataflow.new.DataFlow private import semmle.python.dataflow.new.TaintTracking -private import semmle.python.dataflow.new.RemoteFlowSources +private import semmle.python.Concepts private import semmle.python.ApiGraphs private import semmle.python.dataflow.new.internal.DataFlowPrivate as DataFlowPrivate private import semmle.python.dataflow.new.internal.TaintTrackingPrivate as TaintTrackingPrivate @@ -168,7 +168,7 @@ class ExternalApiDataNode extends DataFlow::Node { } private module UntrustedDataToExternalApiConfig implements DataFlow::ConfigSig { - predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } + predicate isSource(DataFlow::Node source) { source instanceof ActiveThreatModelSource } predicate isSink(DataFlow::Node sink) { sink instanceof ExternalApiDataNode } @@ -177,7 +177,7 @@ private module UntrustedDataToExternalApiConfig implements DataFlow::ConfigSig { } } -/** Global taint-tracking from `RemoteFlowSource`s to `ExternalApiDataNode`s. */ +/** Global taint-tracking from active threat-model sources to `ExternalApiDataNode`s. */ module UntrustedDataToExternalApiFlow = TaintTracking::Global; /** A node representing untrusted data being passed to an external API. */ diff --git a/python/ql/src/experimental/Security/CWE-176/UnicodeBypassValidationQuery.qll b/python/ql/src/experimental/Security/CWE-176/UnicodeBypassValidationQuery.qll index c0337117cf01..e4604c008051 100644 --- a/python/ql/src/experimental/Security/CWE-176/UnicodeBypassValidationQuery.qll +++ b/python/ql/src/experimental/Security/CWE-176/UnicodeBypassValidationQuery.qll @@ -9,7 +9,6 @@ import semmle.python.Concepts import semmle.python.dataflow.new.internal.DataFlowPublic import semmle.python.dataflow.new.TaintTracking import semmle.python.dataflow.new.internal.TaintTrackingPrivate -import semmle.python.dataflow.new.RemoteFlowSources import UnicodeBypassValidationCustomizations::UnicodeBypassValidation abstract private class ValidationState extends string { @@ -37,7 +36,7 @@ private module UnicodeBypassValidationConfig implements DataFlow::StateConfigSig class FlowState = ValidationState; predicate isSource(DataFlow::Node source, FlowState state) { - source instanceof RemoteFlowSource and state instanceof PreValidation + source instanceof ActiveThreatModelSource and state instanceof PreValidation } predicate isAdditionalFlowStep( diff --git a/python/ql/src/experimental/Security/CWE-346/CorsBypass.ql b/python/ql/src/experimental/Security/CWE-346/CorsBypass.ql index 01e661cb0bbf..ce0b02908c56 100644 --- a/python/ql/src/experimental/Security/CWE-346/CorsBypass.ql +++ b/python/ql/src/experimental/Security/CWE-346/CorsBypass.ql @@ -10,6 +10,7 @@ import python import semmle.python.ApiGraphs +import semmle.python.Concepts import semmle.python.dataflow.new.TaintTracking import semmle.python.Flow import semmle.python.dataflow.new.RemoteFlowSources @@ -62,7 +63,7 @@ class CherryPyRequest extends RemoteFlowSource::Range { } module CorsBypassConfig implements DataFlow::ConfigSig { - predicate isSource(DataFlow::Node node) { node instanceof RemoteFlowSource } + predicate isSource(DataFlow::Node node) { node instanceof ActiveThreatModelSource } predicate isSink(DataFlow::Node node) { exists(StringStartswithCall s | diff --git a/python/ql/src/experimental/Security/CWE-770/UnicodeDoS.ql b/python/ql/src/experimental/Security/CWE-770/UnicodeDoS.ql index 61cdd34920de..80d35bc48d24 100644 --- a/python/ql/src/experimental/Security/CWE-770/UnicodeDoS.ql +++ b/python/ql/src/experimental/Security/CWE-770/UnicodeDoS.ql @@ -15,7 +15,6 @@ import semmle.python.ApiGraphs import semmle.python.Concepts import semmle.python.dataflow.new.TaintTracking import semmle.python.dataflow.new.internal.DataFlowPublic -import semmle.python.dataflow.new.RemoteFlowSources // The Unicode compatibility normalization calls from unicodedata, unidecode, pyunormalize // and textnorm modules. The use of argIdx is to constraint the argument being normalized. @@ -86,7 +85,7 @@ predicate underAValue(DataFlow::GuardNode g, ControlFlowNode node, boolean branc } private module UnicodeDoSConfig implements DataFlow::ConfigSig { - predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } + predicate isSource(DataFlow::Node source) { source instanceof ActiveThreatModelSource } predicate isBarrier(DataFlow::Node sanitizer) { // underAValue is a check to ensure that the length of the user-provided value is limited to a certain amount diff --git a/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll b/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll index 64da6b8d799a..69367c2f43a5 100644 --- a/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll +++ b/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll @@ -8,7 +8,6 @@ import semmle.python.dataflow.new.internal.DataFlowPublic import semmle.python.ApiGraphs import semmle.python.dataflow.new.TaintTracking import semmle.python.frameworks.Stdlib -import semmle.python.dataflow.new.RemoteFlowSources /** * Handle those three cases of Tarfile opens: @@ -41,8 +40,8 @@ class AllTarfileOpens extends API::CallNode { module UnsafeUnpackConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { - // A source coming from a remote location - source instanceof RemoteFlowSource + // A source enabled by the active threat model + source instanceof ActiveThreatModelSource or // A source coming from a CLI argparse module // see argparse: https://docs.python.org/3/library/argparse.html diff --git a/python/ql/src/experimental/semmle/python/security/DecompressionBomb.qll b/python/ql/src/experimental/semmle/python/security/DecompressionBomb.qll index f05e5826420f..a00548e00161 100644 --- a/python/ql/src/experimental/semmle/python/security/DecompressionBomb.qll +++ b/python/ql/src/experimental/semmle/python/security/DecompressionBomb.qll @@ -1,8 +1,8 @@ import python import semmle.python.dataflow.new.TaintTracking import semmle.python.ApiGraphs -import semmle.python.dataflow.new.RemoteFlowSources import semmle.python.dataflow.new.internal.DataFlowPublic +import semmle.python.Concepts import FileAndFormRemoteFlowSource::FileAndFormRemoteFlowSource import codeql.util.Unit @@ -426,7 +426,7 @@ predicate isAdditionalTaintStepTextIOWrapper(DataFlow::Node nodeFrom, DataFlow:: module BombsConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { - source instanceof RemoteFlowSource + source instanceof ActiveThreatModelSource or source instanceof FastApi } diff --git a/python/ql/src/experimental/semmle/python/security/LdapInsecureAuth.qll b/python/ql/src/experimental/semmle/python/security/LdapInsecureAuth.qll index 630543e6f798..f81279a4ec3a 100644 --- a/python/ql/src/experimental/semmle/python/security/LdapInsecureAuth.qll +++ b/python/ql/src/experimental/semmle/python/security/LdapInsecureAuth.qll @@ -5,7 +5,7 @@ import python import semmle.python.dataflow.new.DataFlow import semmle.python.dataflow.new.TaintTracking -import semmle.python.dataflow.new.RemoteFlowSources +import semmle.python.Concepts import experimental.semmle.python.Concepts string getFullHostRegex() { result = "(?i)ldap://.+" } @@ -90,7 +90,7 @@ class LdapStringVar extends BinaryExpr { */ private module LdapInsecureAuthConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { - source instanceof RemoteFlowSource or + source instanceof ActiveThreatModelSource or source.asExpr() instanceof LdapFullHost or source.asExpr() instanceof LdapBothStrings or source.asExpr() instanceof LdapBothVar or diff --git a/python/ql/src/experimental/semmle/python/security/RemoteCommandExecution.qll b/python/ql/src/experimental/semmle/python/security/RemoteCommandExecution.qll index 6f4ea88a7472..01642c1e8a13 100644 --- a/python/ql/src/experimental/semmle/python/security/RemoteCommandExecution.qll +++ b/python/ql/src/experimental/semmle/python/security/RemoteCommandExecution.qll @@ -1,13 +1,13 @@ import python import semmle.python.dataflow.new.TaintTracking -import semmle.python.dataflow.new.RemoteFlowSources import semmle.python.ApiGraphs import semmle.python.dataflow.new.internal.DataFlowPublic +import semmle.python.Concepts import codeql.util.Unit import experimental.semmle.python.Concepts module RemoteCommandExecutionConfig implements DataFlow::ConfigSig { - predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } + predicate isSource(DataFlow::Node source) { source instanceof ActiveThreatModelSource } predicate isSink(DataFlow::Node sink) { sink = any(RemoteCommandExecution rce).getCommand() } diff --git a/python/ql/src/experimental/semmle/python/security/TimingAttack.qll b/python/ql/src/experimental/semmle/python/security/TimingAttack.qll index 6d8cc98f21ce..4d4495df83cb 100644 --- a/python/ql/src/experimental/semmle/python/security/TimingAttack.qll +++ b/python/ql/src/experimental/semmle/python/security/TimingAttack.qll @@ -2,7 +2,7 @@ private import python private import semmle.python.dataflow.new.TaintTracking private import semmle.python.dataflow.new.DataFlow private import semmle.python.ApiGraphs -private import semmle.python.dataflow.new.RemoteFlowSources +private import semmle.python.Concepts private import semmle.python.frameworks.Flask private import semmle.python.frameworks.Django @@ -268,7 +268,7 @@ private string sensitiveheaders() { * A config that tracks data flow from remote user input to Variable that hold sensitive info */ module UserInputSecretConfig implements DataFlow::ConfigSig { - predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } + predicate isSource(DataFlow::Node source) { source instanceof ActiveThreatModelSource } predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof CredentialExpr } } @@ -279,7 +279,7 @@ module UserInputSecretFlow = TaintTracking::Global; * A config that tracks data flow from remote user input to Equality test */ module UserInputInComparisonConfig implements DataFlow::ConfigSig { - predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } + predicate isSource(DataFlow::Node source) { source instanceof ActiveThreatModelSource } predicate isSink(DataFlow::Node sink) { exists(Compare cmp, Expr left, Expr right, Cmpop cmpop | diff --git a/python/ql/src/experimental/semmle/python/security/dataflow/EmailXss.qll b/python/ql/src/experimental/semmle/python/security/dataflow/EmailXss.qll index 8f392a43a8a3..53f8f86d90af 100644 --- a/python/ql/src/experimental/semmle/python/security/dataflow/EmailXss.qll +++ b/python/ql/src/experimental/semmle/python/security/dataflow/EmailXss.qll @@ -5,14 +5,13 @@ import python import semmle.python.dataflow.new.DataFlow import semmle.python.dataflow.new.TaintTracking -import semmle.python.dataflow.new.RemoteFlowSources import semmle.python.dataflow.new.BarrierGuards import experimental.semmle.python.Concepts import semmle.python.Concepts import semmle.python.ApiGraphs private module EmailXssConfig implements DataFlow::ConfigSig { - predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } + predicate isSource(DataFlow::Node source) { source instanceof ActiveThreatModelSource } predicate isSink(DataFlow::Node sink) { sink = any(EmailSender email).getHtmlBody() } diff --git a/python/ql/src/experimental/semmle/python/security/injection/CsvInjection.qll b/python/ql/src/experimental/semmle/python/security/injection/CsvInjection.qll index 859f6d1e5e80..e70e6b8bb60b 100644 --- a/python/ql/src/experimental/semmle/python/security/injection/CsvInjection.qll +++ b/python/ql/src/experimental/semmle/python/security/injection/CsvInjection.qll @@ -1,15 +1,15 @@ import python import experimental.semmle.python.Concepts +import semmle.python.Concepts import semmle.python.dataflow.new.DataFlow import semmle.python.dataflow.new.TaintTracking import semmle.python.dataflow.new.BarrierGuards -import semmle.python.dataflow.new.RemoteFlowSources /** * A taint-tracking configuration for tracking untrusted user input used in file read. */ private module CsvInjectionConfig implements DataFlow::ConfigSig { - predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } + predicate isSource(DataFlow::Node source) { source instanceof ActiveThreatModelSource } predicate isSink(DataFlow::Node sink) { sink = any(CsvWriter cw).getAnInput() } From ce648b38876f4bcecb3541972eb4e99d8e697ce7 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 14 Oct 2026 16:40:37 +0100 Subject: [PATCH 3/3] Add change note --- .../change-notes/2026-10-14-active-threat-model-sources.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 python/ql/lib/change-notes/2026-10-14-active-threat-model-sources.md diff --git a/python/ql/lib/change-notes/2026-10-14-active-threat-model-sources.md b/python/ql/lib/change-notes/2026-10-14-active-threat-model-sources.md new file mode 100644 index 000000000000..d4a0203da244 --- /dev/null +++ b/python/ql/lib/change-notes/2026-10-14-active-threat-model-sources.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Updated the `py/xxe`, `py/xml-bomb`, and `py/nosql-injection` queries to respect the configured threat model when selecting untrusted data sources. The default behavior remains unchanged and uses remote flow sources. As a side effect, these queries now correctly include sources modeled using data extensions.