diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/ExternalAPIsQuery.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/ExternalAPIsQuery.qll index 1fde874cc93..235897f0742 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/ExternalAPIsQuery.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/ExternalAPIsQuery.qll @@ -90,8 +90,12 @@ class ExternalApiDataNode extends DataFlow::Node { /** DEPRECATED: Alias for ExternalApiDataNode */ deprecated class ExternalAPIDataNode = ExternalApiDataNode; -/** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalApiDataNode`s. */ -class UntrustedDataToExternalApiConfig extends TaintTracking::Configuration { +/** + * DEPRECATED: Use `RemoteSourceToExternalApi` instead. + * + * A configuration for tracking flow from `RemoteFlowSource`s to `ExternalApiDataNode`s. + */ +deprecated class UntrustedDataToExternalApiConfig extends TaintTracking::Configuration { UntrustedDataToExternalApiConfig() { this = "UntrustedDataToExternalAPIConfig" } override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } @@ -99,17 +103,25 @@ class UntrustedDataToExternalApiConfig extends TaintTracking::Configuration { override predicate isSink(DataFlow::Node sink) { sink instanceof ExternalApiDataNode } } +/** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalApiDataNode`s. */ +private module RemoteSourceToExternalApiConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } + + predicate isSink(DataFlow::Node sink) { sink instanceof ExternalApiDataNode } +} + +/** A module for tracking flow from `RemoteFlowSource`s to `ExternalApiDataNode`s. */ +module RemoteSourceToExternalApi = TaintTracking::Global; + /** DEPRECATED: Alias for UntrustedDataToExternalApiConfig */ deprecated class UntrustedDataToExternalAPIConfig = UntrustedDataToExternalApiConfig; /** A node representing untrusted data being passed to an external API. */ class UntrustedExternalApiDataNode extends ExternalApiDataNode { - private UntrustedDataToExternalApiConfig c; - - UntrustedExternalApiDataNode() { c.hasFlow(_, this) } + UntrustedExternalApiDataNode() { RemoteSourceToExternalApi::flow(_, this) } /** Gets a source of untrusted data which is passed to this external API data node. */ - DataFlow::Node getAnUntrustedSource() { c.hasFlow(result, this) } + DataFlow::Node getAnUntrustedSource() { RemoteSourceToExternalApi::flow(result, this) } } /** DEPRECATED: Alias for UntrustedExternalApiDataNode */ diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/HardcodedCredentialsQuery.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/HardcodedCredentialsQuery.qll index 68e6a8a6fb0..a5875fe001c 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/HardcodedCredentialsQuery.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/HardcodedCredentialsQuery.qll @@ -38,9 +38,11 @@ abstract class Sink extends DataFlow::ExprNode { abstract class Sanitizer extends DataFlow::ExprNode { } /** + * DEPRECATED: Use `HardcodedCredentials` instead. + * * A taint-tracking configuration for hard coded credentials. */ -class TaintTrackingConfiguration extends TaintTracking::Configuration { +deprecated class TaintTrackingConfiguration extends TaintTracking::Configuration { TaintTrackingConfiguration() { this = "HardcodedCredentials" } override predicate isSource(DataFlow::Node source) { source instanceof Source } @@ -75,6 +77,56 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration { override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer } } +/** + * A taint-tracking configuration for hard coded credentials. + */ +private module HardcodedCredentialsConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source instanceof Source } + + predicate isSink(DataFlow::Node sink) { + sink instanceof Sink and + // Ignore values that are ultimately returned by mocks, as they don't represent "real" + // credentials. + not any(ReturnedByMockObject mock).getAMemberInitializationValue() = sink.asExpr() and + not any(ReturnedByMockObject mock).getAnArgument() = sink.asExpr() + } + + predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer } +} + +/** + * A taint-tracking module for hard coded credentials. + */ +module HardcodedCredentials { + import TaintTracking::Global as Super + import Super + + /** + * Holds if data can flow from `source` to `sink`. + * + * The corresponding paths are generated from the end-points and the graph + * included in the module `PathGraph`. + */ + predicate flowPath(HardcodedCredentials::PathNode source, HardcodedCredentials::PathNode sink) { + Super::flowPath(source, sink) and + // Exclude hard-coded credentials in tests if they only flow to calls to methods with a name + // like "Add*" "Create*" or "Update*". The rationale is that hard-coded credentials within + // tests that are only used for creating or setting values within tests are unlikely to + // represent credentials to some accessible system. + not ( + source.getNode().asExpr().getFile() instanceof TestFile and + exists(MethodCall createOrAddCall, string createOrAddMethodName | + createOrAddMethodName.matches("Update%") or + createOrAddMethodName.matches("Create%") or + createOrAddMethodName.matches("Add%") + | + createOrAddCall.getTarget().hasName(createOrAddMethodName) and + createOrAddCall.getAnArgument() = sink.getNode().asExpr() + ) + ) + } +} + /** * A string literal that is not empty. */ diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/LDAPInjectionQuery.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/LDAPInjectionQuery.qll index fb94273ccd7..9171bae41b4 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/LDAPInjectionQuery.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/LDAPInjectionQuery.qll @@ -25,9 +25,11 @@ abstract class Sink extends DataFlow::ExprNode { } abstract class Sanitizer extends DataFlow::ExprNode { } /** + * DEPRECATED: Use `LdapInjection` instead. + * * A taint-tracking configuration for unvalidated user input that is used to construct LDAP queries. */ -class TaintTrackingConfiguration extends TaintTracking::Configuration { +deprecated class TaintTrackingConfiguration extends TaintTracking::Configuration { TaintTrackingConfiguration() { this = "LDAPInjection" } override predicate isSource(DataFlow::Node source) { source instanceof Source } @@ -37,6 +39,32 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration { override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer } } +/** + * A taint-tracking configuration for unvalidated user input that is used to construct LDAP queries. + */ +module LdapInjectionConfig implements DataFlow::ConfigSig { + /** + * Holds if `source` is a relevant data flow source. + */ + predicate isSource(DataFlow::Node source) { source instanceof Source } + + /** + * Holds if `sink` is a relevant data flow sink. + */ + predicate isSink(DataFlow::Node sink) { sink instanceof Sink } + + /** + * Holds if data flow through `node` is prohibited. This completely removes + * `node` from the data flow graph. + */ + predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer } +} + +/** + * A taint-tracking configuration for unvalidated user input that is used to construct LDAP queries. + */ +module LdapInjection = TaintTracking::Global; + /** A source of remote user input. */ class RemoteSource extends Source instanceof RemoteFlowSource { } diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/LogForgingQuery.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/LogForgingQuery.qll index 8764ebfd1d0..f145b18dfeb 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/LogForgingQuery.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/LogForgingQuery.qll @@ -25,9 +25,11 @@ abstract class Sink extends DataFlow::ExprNode { } abstract class Sanitizer extends DataFlow::ExprNode { } /** + * DEPRECATED: Use `LogForging` instead. + * * A taint-tracking configuration for untrusted user input used in log entries. */ -class TaintTrackingConfiguration extends TaintTracking::Configuration { +deprecated class TaintTrackingConfiguration extends TaintTracking::Configuration { TaintTrackingConfiguration() { this = "LogForging" } override predicate isSource(DataFlow::Node source) { source instanceof Source } @@ -37,6 +39,22 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration { override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer } } +/** + * A taint-tracking configuration for untrusted user input used in log entries. + */ +private module LogForgingConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source instanceof Source } + + predicate isSink(DataFlow::Node sink) { sink instanceof Sink } + + predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer } +} + +/** + * A taint-tracking module for untrusted user input used in log entries. + */ +module LogForging = TaintTracking::Global; + /** A source of remote user input. */ private class RemoteSource extends Source instanceof RemoteFlowSource { } diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/MissingXMLValidationQuery.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/MissingXMLValidationQuery.qll index 47de109168d..676b77b8446 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/MissingXMLValidationQuery.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/MissingXMLValidationQuery.qll @@ -29,10 +29,12 @@ abstract class Sink extends DataFlow::ExprNode { abstract class Sanitizer extends DataFlow::ExprNode { } /** + * DEPRECATED: Use `MissingXxmlValidation` instead. + * * A taint-tracking configuration for untrusted user input processed as XML without validation against a * known schema. */ -class TaintTrackingConfiguration extends TaintTracking::Configuration { +deprecated class TaintTrackingConfiguration extends TaintTracking::Configuration { TaintTrackingConfiguration() { this = "MissingXMLValidation" } override predicate isSource(DataFlow::Node source) { source instanceof Source } @@ -42,6 +44,24 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration { override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer } } +/** + * A taint-tracking configuration for untrusted user input processed as XML without validation against a + * known schema. + */ +private module MissingXmlValidationConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source instanceof Source } + + predicate isSink(DataFlow::Node sink) { sink instanceof Sink } + + predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer } +} + +/** + * A taint-tracking module for untrusted user input processed as XML without validation against a + * known schema. + */ +module MissingXmlValidation = TaintTracking::Global; + /** A source of remote user input. */ class RemoteSource extends Source instanceof RemoteFlowSource { } diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/ReDoSQuery.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/ReDoSQuery.qll index c3450946eb2..3fab0bd2d4e 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/ReDoSQuery.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/ReDoSQuery.qll @@ -25,9 +25,11 @@ abstract class Sink extends DataFlow::ExprNode { } abstract class Sanitizer extends DataFlow::ExprNode { } /** + * DEPRECATED: Use `ReDoS` instead. + * * A taint-tracking configuration for untrusted user input used in dangerous regular expression operations. */ -class TaintTrackingConfiguration extends TaintTracking::Configuration { +deprecated class TaintTrackingConfiguration extends TaintTracking::Configuration { TaintTrackingConfiguration() { this = "ReDoS" } override predicate isSource(DataFlow::Node source) { source instanceof Source } @@ -37,6 +39,22 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration { override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer } } +/** + * A taint-tracking configuration for untrusted user input used in dangerous regular expression operations. + */ +private module ReDoSConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source instanceof Source } + + predicate isSink(DataFlow::Node sink) { sink instanceof Sink } + + predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer } +} + +/** + * A taint-tracking module for untrusted user input used in dangerous regular expression operations. + */ +module ReDoS = TaintTracking::Global; + /** A source of remote user input. */ class RemoteSource extends Source instanceof RemoteFlowSource { } diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/RegexInjectionQuery.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/RegexInjectionQuery.qll index bfd0bcb5aea..89baeda92b6 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/RegexInjectionQuery.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/RegexInjectionQuery.qll @@ -24,9 +24,11 @@ abstract class Sink extends DataFlow::ExprNode { } abstract class Sanitizer extends DataFlow::ExprNode { } /** + * DEPRECATED: Use `RegexInjection` instead. + * * A taint-tracking configuration for untrusted user input used to construct regular expressions. */ -class TaintTrackingConfiguration extends TaintTracking::Configuration { +deprecated class TaintTrackingConfiguration extends TaintTracking::Configuration { TaintTrackingConfiguration() { this = "RegexInjection" } override predicate isSource(DataFlow::Node source) { source instanceof Source } @@ -36,6 +38,22 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration { override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer } } +/** + * A taint-tracking configuration for untrusted user input used to construct regular expressions. + */ +private module RegexInjectionConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source instanceof Source } + + predicate isSink(DataFlow::Node sink) { sink instanceof Sink } + + predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer } +} + +/** + * A taint-tracking module for untrusted user input used to construct regular expressions. + */ +module RegexInjection = TaintTracking::Global; + /** A source of remote user input. */ class RemoteSource extends Source instanceof RemoteFlowSource { } diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/ResourceInjectionQuery.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/ResourceInjectionQuery.qll index fee371359fd..336ca17ca75 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/ResourceInjectionQuery.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/ResourceInjectionQuery.qll @@ -24,9 +24,11 @@ abstract class Sink extends DataFlow::ExprNode { } abstract class Sanitizer extends DataFlow::ExprNode { } /** + * DEPRECATED: Use `ResourceInjection` instead. + * * A taint-tracking configuration for untrusted user input used in resource descriptors. */ -class TaintTrackingConfiguration extends TaintTracking::Configuration { +deprecated class TaintTrackingConfiguration extends TaintTracking::Configuration { TaintTrackingConfiguration() { this = "ResourceInjection" } override predicate isSource(DataFlow::Node source) { source instanceof Source } @@ -36,6 +38,22 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration { override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer } } +/** + * A taint-tracking configuration for untrusted user input used in resource descriptors. + */ +private module ResourceInjectionConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source instanceof Source } + + predicate isSink(DataFlow::Node sink) { sink instanceof Sink } + + predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer } +} + +/** + * A taint-tracking module for untrusted user input used in resource descriptors. + */ +module ResourceInjection = TaintTracking::Global; + /** A source of remote user input. */ class RemoteSource extends Source instanceof RemoteFlowSource { } diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/SqlInjectionQuery.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/SqlInjectionQuery.qll index d19b4739fde..3cac542cb36 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/SqlInjectionQuery.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/SqlInjectionQuery.qll @@ -25,9 +25,11 @@ abstract class Sink extends DataFlow::ExprNode { } abstract class Sanitizer extends DataFlow::ExprNode { } /** + * DEPRECATED: Use `SqlInjection` instead. + * * A taint-tracking configuration for SQL injection vulnerabilities. */ -class TaintTrackingConfiguration extends TaintTracking::Configuration { +deprecated class TaintTrackingConfiguration extends TaintTracking::Configuration { TaintTrackingConfiguration() { this = "SqlInjection" } override predicate isSource(DataFlow::Node source) { source instanceof Source } @@ -37,6 +39,32 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration { override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer } } +/** + * A taint-tracking configuration for SQL injection vulnerabilities. + */ +module SqlInjectionConfig implements DataFlow::ConfigSig { + /** + * Holds if `source` is a relevant data flow source. + */ + predicate isSource(DataFlow::Node source) { source instanceof Source } + + /** + * Holds if `sink` is a relevant data flow sink. + */ + predicate isSink(DataFlow::Node sink) { sink instanceof Sink } + + /** + * Holds if data flow through `node` is prohibited. This completely removes + * `node` from the data flow graph. + */ + predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer } +} + +/** + * A taint-tracking module for SQL injection vulnerabilities. + */ +module SqlInjection = TaintTracking::Global; + /** A source of remote user input. */ class RemoteSource extends Source instanceof RemoteFlowSource { } diff --git a/csharp/ql/src/Security Features/CWE-020/UntrustedDataToExternalAPI.ql b/csharp/ql/src/Security Features/CWE-020/UntrustedDataToExternalAPI.ql index 85a7d7ff53a..a71a2705bdd 100644 --- a/csharp/ql/src/Security Features/CWE-020/UntrustedDataToExternalAPI.ql +++ b/csharp/ql/src/Security Features/CWE-020/UntrustedDataToExternalAPI.ql @@ -12,13 +12,13 @@ import csharp import semmle.code.csharp.commons.QualifiedName import semmle.code.csharp.security.dataflow.ExternalAPIsQuery -import DataFlow::PathGraph +import RemoteSourceToExternalApi::PathGraph from - UntrustedDataToExternalApiConfig config, DataFlow::PathNode source, DataFlow::PathNode sink, + RemoteSourceToExternalApi::PathNode source, RemoteSourceToExternalApi::PathNode sink, string qualifier, string name where - config.hasFlowPath(source, sink) and + RemoteSourceToExternalApi::flowPath(source, sink) and sink.getNode().(ExternalApiDataNode).hasQualifiedName(qualifier, name) select sink, source, sink, "Call to " + getQualifiedName(qualifier, name) + " with untrusted data from $@.", source, diff --git a/csharp/ql/src/Security Features/CWE-089/SecondOrderSqlInjection.ql b/csharp/ql/src/Security Features/CWE-089/SecondOrderSqlInjection.ql index 3d363d87310..33c2479147d 100644 --- a/csharp/ql/src/Security Features/CWE-089/SecondOrderSqlInjection.ql +++ b/csharp/ql/src/Security Features/CWE-089/SecondOrderSqlInjection.ql @@ -12,15 +12,21 @@ */ import csharp -import semmle.code.csharp.security.dataflow.SqlInjectionQuery as SqlInjection +import semmle.code.csharp.security.dataflow.SqlInjectionQuery import semmle.code.csharp.security.dataflow.flowsources.Stored -import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph +import StoredSqlInjection::PathGraph -class StoredTaintTrackingConfiguration extends SqlInjection::TaintTrackingConfiguration { - override predicate isSource(DataFlow::Node source) { source instanceof StoredFlowSource } +module StoredSqlInjectionConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source instanceof StoredFlowSource } + + predicate isSink = SqlInjectionConfig::isSink/1; + + predicate isBarrier = SqlInjectionConfig::isBarrier/1; } -from StoredTaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink -where c.hasFlowPath(source, sink) +module StoredSqlInjection = TaintTracking::Global; + +from StoredSqlInjection::PathNode source, StoredSqlInjection::PathNode sink +where StoredSqlInjection::flowPath(source, sink) select sink.getNode(), source, sink, "This SQL query depends on a $@.", source.getNode(), "stored user-provided value" diff --git a/csharp/ql/src/Security Features/CWE-089/SqlInjection.ql b/csharp/ql/src/Security Features/CWE-089/SqlInjection.ql index e4298741ca8..e3fa7f80bd7 100644 --- a/csharp/ql/src/Security Features/CWE-089/SqlInjection.ql +++ b/csharp/ql/src/Security Features/CWE-089/SqlInjection.ql @@ -13,7 +13,7 @@ import csharp import semmle.code.csharp.security.dataflow.SqlInjectionQuery -import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph +import SqlInjection::PathGraph import semmle.code.csharp.security.dataflow.flowsources.Remote import semmle.code.csharp.security.dataflow.flowsources.Local @@ -23,7 +23,7 @@ string getSourceType(DataFlow::Node node) { result = node.(LocalFlowSource).getSourceType() } -from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink -where c.hasFlowPath(source, sink) +from SqlInjection::PathNode source, SqlInjection::PathNode sink +where SqlInjection::flowPath(source, sink) select sink.getNode(), source, sink, "This query depends on $@.", source, ("this " + getSourceType(source.getNode())) diff --git a/csharp/ql/src/Security Features/CWE-090/LDAPInjection.ql b/csharp/ql/src/Security Features/CWE-090/LDAPInjection.ql index f4413eeb17a..7c38f83d34e 100644 --- a/csharp/ql/src/Security Features/CWE-090/LDAPInjection.ql +++ b/csharp/ql/src/Security Features/CWE-090/LDAPInjection.ql @@ -13,9 +13,9 @@ import csharp import semmle.code.csharp.security.dataflow.LDAPInjectionQuery -import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph +import LdapInjection::PathGraph -from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink -where c.hasFlowPath(source, sink) +from LdapInjection::PathNode source, LdapInjection::PathNode sink +where LdapInjection::flowPath(source, sink) select sink.getNode(), source, sink, "This LDAP query depends on a $@.", source.getNode(), "user-provided value" diff --git a/csharp/ql/src/Security Features/CWE-090/StoredLDAPInjection.ql b/csharp/ql/src/Security Features/CWE-090/StoredLDAPInjection.ql index 26a0711037d..e5015892fc4 100644 --- a/csharp/ql/src/Security Features/CWE-090/StoredLDAPInjection.ql +++ b/csharp/ql/src/Security Features/CWE-090/StoredLDAPInjection.ql @@ -14,13 +14,19 @@ import csharp import semmle.code.csharp.security.dataflow.LDAPInjectionQuery import semmle.code.csharp.security.dataflow.flowsources.Stored -import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph +import StoredLdapInjection::PathGraph -class StoredTaintTrackingConfiguration extends TaintTrackingConfiguration { - override predicate isSource(DataFlow::Node source) { source instanceof StoredFlowSource } +module StoredLdapInjectionConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source instanceof StoredFlowSource } + + predicate isSink = LdapInjectionConfig::isSink/1; + + predicate isBarrier = LdapInjectionConfig::isBarrier/1; } -from StoredTaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink -where c.hasFlowPath(source, sink) +module StoredLdapInjection = TaintTracking::Global; + +from StoredLdapInjection::PathNode source, StoredLdapInjection::PathNode sink +where StoredLdapInjection::flowPath(source, sink) select sink.getNode(), source, sink, "This LDAP query depends on a $@.", source.getNode(), "stored (potentially user-provided) value" diff --git a/csharp/ql/src/Security Features/CWE-099/ResourceInjection.ql b/csharp/ql/src/Security Features/CWE-099/ResourceInjection.ql index 23f60cb2368..6cdd8e9aa6f 100644 --- a/csharp/ql/src/Security Features/CWE-099/ResourceInjection.ql +++ b/csharp/ql/src/Security Features/CWE-099/ResourceInjection.ql @@ -13,9 +13,9 @@ import csharp import semmle.code.csharp.security.dataflow.ResourceInjectionQuery -import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph +import ResourceInjection::PathGraph -from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink -where c.hasFlowPath(source, sink) +from ResourceInjection::PathNode source, ResourceInjection::PathNode sink +where ResourceInjection::flowPath(source, sink) select sink.getNode(), source, sink, "This resource descriptor depends on a $@.", source.getNode(), "user-provided value" diff --git a/csharp/ql/src/Security Features/CWE-112/MissingXMLValidation.ql b/csharp/ql/src/Security Features/CWE-112/MissingXMLValidation.ql index 7b6d069b211..42e9aa4c1f3 100644 --- a/csharp/ql/src/Security Features/CWE-112/MissingXMLValidation.ql +++ b/csharp/ql/src/Security Features/CWE-112/MissingXMLValidation.ql @@ -13,10 +13,10 @@ import csharp import semmle.code.csharp.security.dataflow.MissingXMLValidationQuery -import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph +import MissingXmlValidation::PathGraph -from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink -where c.hasFlowPath(source, sink) +from MissingXmlValidation::PathNode source, MissingXmlValidation::PathNode sink +where MissingXmlValidation::flowPath(source, sink) select sink.getNode(), source, sink, "This XML processing depends on a $@ without validation because " + sink.getNode().(Sink).getReason(), source.getNode(), "user-provided value" diff --git a/csharp/ql/src/Security Features/CWE-117/LogForging.ql b/csharp/ql/src/Security Features/CWE-117/LogForging.ql index adbee47ed59..9494af33570 100644 --- a/csharp/ql/src/Security Features/CWE-117/LogForging.ql +++ b/csharp/ql/src/Security Features/CWE-117/LogForging.ql @@ -13,9 +13,9 @@ import csharp import semmle.code.csharp.security.dataflow.LogForgingQuery -import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph +import LogForging::PathGraph -from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink -where c.hasFlowPath(source, sink) +from LogForging::PathNode source, LogForging::PathNode sink +where LogForging::flowPath(source, sink) select sink.getNode(), source, sink, "This log entry depends on a $@.", source.getNode(), "user-provided value" diff --git a/csharp/ql/src/Security Features/CWE-730/ReDoS.ql b/csharp/ql/src/Security Features/CWE-730/ReDoS.ql index 9d74f5b6e6e..931e3f4456f 100644 --- a/csharp/ql/src/Security Features/CWE-730/ReDoS.ql +++ b/csharp/ql/src/Security Features/CWE-730/ReDoS.ql @@ -16,11 +16,11 @@ import csharp import semmle.code.csharp.security.dataflow.ReDoSQuery import semmle.code.csharp.frameworks.system.text.RegularExpressions -import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph +import ReDoS::PathGraph -from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink +from ReDoS::PathNode source, ReDoS::PathNode sink where - c.hasFlowPath(source, sink) and + ReDoS::flowPath(source, sink) and // No global timeout set not exists(RegexGlobalTimeout r) and ( diff --git a/csharp/ql/src/Security Features/CWE-730/RegexInjection.ql b/csharp/ql/src/Security Features/CWE-730/RegexInjection.ql index 396c0859d33..5b6d9553311 100644 --- a/csharp/ql/src/Security Features/CWE-730/RegexInjection.ql +++ b/csharp/ql/src/Security Features/CWE-730/RegexInjection.ql @@ -16,11 +16,11 @@ import csharp import semmle.code.csharp.security.dataflow.RegexInjectionQuery import semmle.code.csharp.frameworks.system.text.RegularExpressions -import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph +import RegexInjection::PathGraph -from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink +from RegexInjection::PathNode source, RegexInjection::PathNode sink where - c.hasFlowPath(source, sink) and + RegexInjection::flowPath(source, sink) and // No global timeout set not exists(RegexGlobalTimeout r) select sink.getNode(), source, sink, "This regular expression is constructed from a $@.", diff --git a/csharp/ql/src/Security Features/CWE-798/HardcodedConnectionString.ql b/csharp/ql/src/Security Features/CWE-798/HardcodedConnectionString.ql index 262949b7b3b..09f4bdca26b 100644 --- a/csharp/ql/src/Security Features/CWE-798/HardcodedConnectionString.ql +++ b/csharp/ql/src/Security Features/CWE-798/HardcodedConnectionString.ql @@ -15,7 +15,7 @@ import csharp import semmle.code.csharp.frameworks.system.Data import semmle.code.csharp.security.dataflow.HardcodedCredentialsQuery -import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph +import ConnectionString::PathGraph /** * A string literal containing a username or password field. @@ -29,24 +29,24 @@ class ConnectionStringPasswordOrUsername extends NonEmptyStringLiteral { /** * A taint-tracking configuration for tracking string literals to a `ConnectionString` property. */ -class ConnectionStringTaintTrackingConfiguration extends TaintTracking::Configuration { - ConnectionStringTaintTrackingConfiguration() { this = "connectionstring" } +module ConnectionStringConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source instanceof ConnectionStringPasswordOrUsername } - override predicate isSource(DataFlow::Node source) { - source instanceof ConnectionStringPasswordOrUsername - } - - override predicate isSink(DataFlow::Node sink) { + predicate isSink(DataFlow::Node sink) { sink.asExpr() = any(SystemDataConnectionClass connection).getConnectionStringProperty().getAnAssignedValue() } - override predicate isSanitizer(DataFlow::Node node) { node instanceof StringFormatSanitizer } + predicate isBarrier(DataFlow::Node node) { node instanceof StringFormatSanitizer } } -from - ConnectionStringTaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink -where c.hasFlowPath(source, sink) +/** + * A taint-tracking module for tracking string literals to a `ConnectionString` property. + */ +module ConnectionString = TaintTracking::Global; + +from ConnectionString::PathNode source, ConnectionString::PathNode sink +where ConnectionString::flowPath(source, sink) select source.getNode(), source, sink, "'ConnectionString' property includes hard-coded credentials set in $@.", any(Call call | call.getAnArgument() = sink.getNode().asExpr()) as call, call.toString() diff --git a/csharp/ql/src/Security Features/CWE-798/HardcodedCredentials.ql b/csharp/ql/src/Security Features/CWE-798/HardcodedCredentials.ql index 740fbfe124f..d4291c90fb2 100644 --- a/csharp/ql/src/Security Features/CWE-798/HardcodedCredentials.ql +++ b/csharp/ql/src/Security Features/CWE-798/HardcodedCredentials.ql @@ -14,15 +14,15 @@ import csharp import semmle.code.csharp.security.dataflow.HardcodedCredentialsQuery -import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph +import HardcodedCredentials::PathGraph from - TaintTrackingConfiguration c, Source source, Sink sink, DataFlow::PathNode sourcePath, - DataFlow::PathNode sinkPath, string value + Source source, Sink sink, HardcodedCredentials::PathNode sourcePath, + HardcodedCredentials::PathNode sinkPath, string value where source = sourcePath.getNode() and sink = sinkPath.getNode() and - c.hasFlowPath(sourcePath, sinkPath) and + HardcodedCredentials::flowPath(sourcePath, sinkPath) and // Print the source value if it's available if exists(source.asExpr().getValue()) then value = "The hard-coded value \"" + source.asExpr().getValue() + "\"" diff --git a/csharp/ql/test/query-tests/Security Features/CWE-798/HardcodedConnectionString.expected b/csharp/ql/test/query-tests/Security Features/CWE-798/HardcodedConnectionString.expected index cc63d14b6dc..1191b40ec28 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-798/HardcodedConnectionString.expected +++ b/csharp/ql/test/query-tests/Security Features/CWE-798/HardcodedConnectionString.expected @@ -1,19 +1,7 @@ edges -| HardcodedCredentials.cs:47:30:47:60 | array creation of type Byte[] : Byte[] | HardcodedCredentials.cs:50:13:50:23 | access to local variable rawCertData | nodes -| HardcodedCredentials.cs:15:25:15:36 | "myPa55word" | semmle.label | "myPa55word" | -| HardcodedCredentials.cs:31:19:31:28 | "username" | semmle.label | "username" | -| HardcodedCredentials.cs:45:39:45:53 | "myNewPa55word" | semmle.label | "myNewPa55word" | -| HardcodedCredentials.cs:47:30:47:60 | array creation of type Byte[] : Byte[] | semmle.label | array creation of type Byte[] : Byte[] | -| HardcodedCredentials.cs:50:13:50:23 | access to local variable rawCertData | semmle.label | access to local variable rawCertData | -| HardcodedCredentials.cs:51:13:51:24 | "myPa55word" | semmle.label | "myPa55word" | | HardcodedCredentials.cs:54:48:54:63 | "Password=12345" | semmle.label | "Password=12345" | | HardcodedCredentials.cs:56:49:56:63 | "User Id=12345" | semmle.label | "User Id=12345" | -| HardcodedCredentials.cs:74:31:74:42 | "myusername" | semmle.label | "myusername" | -| HardcodedCredentials.cs:74:45:74:56 | "mypassword" | semmle.label | "mypassword" | -| TestHardcodedCredentials.cs:21:31:21:42 | "myusername" | semmle.label | "myusername" | -| TestHardcodedCredentials.cs:21:45:21:56 | "mypassword" | semmle.label | "mypassword" | -| TestHardcodedCredentials.cs:26:19:26:28 | "username" | semmle.label | "username" | subpaths #select | HardcodedCredentials.cs:54:48:54:63 | "Password=12345" | HardcodedCredentials.cs:54:48:54:63 | "Password=12345" | HardcodedCredentials.cs:54:48:54:63 | "Password=12345" | 'ConnectionString' property includes hard-coded credentials set in $@. | HardcodedCredentials.cs:54:30:54:64 | object creation of type SqlConnection | object creation of type SqlConnection |