Merge pull request #12681 from egregius313/egregius313/java/move-configurations-to-libraries

Java: Move dataflow configurations in queries to `*Query.qll` libraries (part 1)
This commit is contained in:
Edward Minnix III
2023-03-30 14:33:21 -04:00
committed by GitHub
17 changed files with 331 additions and 282 deletions

View File

@@ -0,0 +1,10 @@
---
category: minorAnalysis
---
* Added the `TaintedPathQuery.qll` library to provide the `TaintedPathFlow` and `TaintedPathLocalFlow` taint-tracking modules to reason about tainted path vulnerabilities.
* Added the `ZipSlipQuery.qll` library to provide the `ZipSlipFlow` taint-tracking module to reason about zip-slip vulnerabilities.
* Added the `InsecureBeanValidationQuery.qll` library to provide the `BeanValidationFlow` taint-tracking module to reason about bean validation vulnerabilities.
* Added the `XssQuery.qll` library to provide the `XssFlow` taint-tracking module to reason about cross site scripting vulnerabilities.
* Added the `LdapInjectionQuery.qll` library to provide the `LdapInjectionFlow` taint-tracking module to reason about LDAP injection vulnerabilities.
* Added the `ResponseSplittingQuery.qll` library to provide the `ResponseSplittingFlow` taint-tracking module to reason about response splitting vulnerabilities.
* Added the `ExternallyControlledFormatStringQuery.qll` library to provide the `ExternallyControlledFormatStringFlow` taint-tracking module to reason about externally controlled format string vulnerabilities.

View File

@@ -0,0 +1,26 @@
/** Provides a taint-tracking configuration to reason about externally controlled format string vulnerabilities. */
import java
private import semmle.code.java.dataflow.FlowSources
private import semmle.code.java.StringFormat
/**
* A taint-tracking configuration for externally controlled format string vulnerabilities.
*/
module ExternallyControlledFormatStringConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
predicate isSink(DataFlow::Node sink) {
sink.asExpr() = any(StringFormat formatCall).getFormatArgument()
}
predicate isBarrier(DataFlow::Node node) {
node.getType() instanceof NumericType or node.getType() instanceof BooleanType
}
}
/**
* Taint-tracking flow for externally controlled format string vulnerabilities.
*/
module ExternallyControlledFormatStringFlow =
TaintTracking::Global<ExternallyControlledFormatStringConfig>;

View File

@@ -0,0 +1,63 @@
/** Provides classes and a taint tracking configuration to reason about insecure bean validation. */
import java
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.dataflow.FlowSources
private import semmle.code.java.dataflow.ExternalFlow
/**
* A message interpolator Type that perform Expression Language (EL) evaluations.
*/
private class ELMessageInterpolatorType extends RefType {
ELMessageInterpolatorType() {
this.getASourceSupertype*()
.hasQualifiedName("org.hibernate.validator.messageinterpolation",
["ResourceBundleMessageInterpolator", "ValueFormatterMessageInterpolator"])
}
}
/**
* A method call that sets the application's default message interpolator.
*/
class SetMessageInterpolatorCall extends MethodAccess {
SetMessageInterpolatorCall() {
exists(Method m, RefType t |
this.getMethod() = m and
m.getDeclaringType().getASourceSupertype*() = t and
(
t.hasQualifiedName("javax.validation", ["Configuration", "ValidatorContext"]) and
m.getName() = "messageInterpolator"
or
t.hasQualifiedName("org.springframework.validation.beanvalidation",
["CustomValidatorBean", "LocalValidatorFactoryBean"]) and
m.getName() = "setMessageInterpolator"
)
)
}
/**
* Holds if the message interpolator is likely to be safe, because it does not process Java Expression Language expressions.
*/
predicate isSafe() { not this.getAnArgument().getType() instanceof ELMessageInterpolatorType }
}
/**
* Taint tracking BeanValidationConfiguration describing the flow of data from user input
* to the argument of a method that builds constraint error messages.
*/
module BeanValidationConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
predicate isSink(DataFlow::Node sink) { sink instanceof BeanValidationSink }
}
/** Tracks flow from user input to the argument of a method that builds constraint error messages. */
module BeanValidationFlow = TaintTracking::Global<BeanValidationConfig>;
/**
* A bean validation sink, such as method `buildConstraintViolationWithTemplate`
* declared on a subtype of `javax.validation.ConstraintValidatorContext`.
*/
private class BeanValidationSink extends DataFlow::Node {
BeanValidationSink() { sinkNode(this, "bean-validation") }
}

View File

@@ -1,3 +1,5 @@
/** Provides a taint tracking configuration to reason about unvalidated user input that is used to construct LDAP queries. */
import java
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.security.LdapInjection
@@ -17,4 +19,5 @@ module LdapInjectionFlowConfig implements DataFlow::ConfigSig {
}
}
/** Tracks flow from remote sources to LDAP injection vulnerabilities. */
module LdapInjectionFlow = TaintTracking::Global<LdapInjectionFlowConfig>;

View File

@@ -0,0 +1,40 @@
/** Provides a taint tracking configuration to reason about response splitting vulnerabilities. */
import java
private import semmle.code.java.dataflow.FlowSources
import semmle.code.java.security.ResponseSplitting
/**
* A taint-tracking configuration for response splitting vulnerabilities.
*/
module ResponseSplittingConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source instanceof RemoteFlowSource and
not source instanceof SafeHeaderSplittingSource
}
predicate isSink(DataFlow::Node sink) { sink instanceof HeaderSplittingSink }
predicate isBarrier(DataFlow::Node node) {
node.getType() instanceof PrimitiveType
or
node.getType() instanceof BoxedType
or
exists(MethodAccess ma, string methodName, CompileTimeConstantExpr target |
node.asExpr() = ma and
ma.getMethod().hasQualifiedName("java.lang", "String", methodName) and
target = ma.getArgument(0) and
(
methodName = "replace" and target.getIntValue() = [10, 13] // 10 == "\n", 13 == "\r"
or
methodName = "replaceAll" and
target.getStringValue().regexpMatch(".*([\n\r]|\\[\\^[^\\]\r\n]*\\]).*")
)
)
}
}
/**
* Tracks flow from remote sources to response splitting vulnerabilities.
*/
module ResponseSplittingFlow = TaintTracking::Global<ResponseSplittingConfig>;

View File

@@ -0,0 +1,104 @@
/** Provides dataflow configurations for tainted path queries. */
import java
import semmle.code.java.frameworks.Networking
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.FlowSources
private import semmle.code.java.dataflow.ExternalFlow
import semmle.code.java.security.PathCreation
import semmle.code.java.security.PathSanitizer
/**
* A unit class for adding additional taint steps.
*
* Extend this class to add additional taint steps that should apply to tainted path flow configurations.
*/
class TaintedPathAdditionalTaintStep extends Unit {
abstract predicate step(DataFlow::Node n1, DataFlow::Node n2);
}
private class DefaultTaintedPathAdditionalTaintStep extends TaintedPathAdditionalTaintStep {
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
exists(Argument a |
a = n1.asExpr() and
a.getCall() = n2.asExpr() and
a = any(TaintPreservingUriCtorParam tpp).getAnArgument()
)
}
}
private class TaintPreservingUriCtorParam extends Parameter {
TaintPreservingUriCtorParam() {
exists(Constructor ctor, int idx, int nParams |
ctor.getDeclaringType() instanceof TypeUri and
this = ctor.getParameter(idx) and
nParams = ctor.getNumberOfParameters()
|
// URI(String scheme, String ssp, String fragment)
idx = 1 and nParams = 3
or
// URI(String scheme, String host, String path, String fragment)
idx = [1, 2] and nParams = 4
or
// URI(String scheme, String authority, String path, String query, String fragment)
idx = 2 and nParams = 5
or
// URI(String scheme, String userInfo, String host, int port, String path, String query, String fragment)
idx = 4 and nParams = 7
)
}
}
/**
* A taint-tracking configuration for tracking flow from remote sources to the creation of a path.
*/
module TaintedPathConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
predicate isSink(DataFlow::Node sink) {
sink.asExpr() = any(PathCreation p).getAnInput()
or
sinkNode(sink, ["create-file", "read-file"])
}
predicate isBarrier(DataFlow::Node sanitizer) {
sanitizer.getType() instanceof BoxedType or
sanitizer.getType() instanceof PrimitiveType or
sanitizer.getType() instanceof NumberType or
sanitizer instanceof PathInjectionSanitizer
}
predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
any(TaintedPathAdditionalTaintStep s).step(n1, n2)
}
}
/** Tracks flow from remote sources to the creation of a path. */
module TaintedPathFlow = TaintTracking::Global<TaintedPathConfig>;
/**
* A taint-tracking configuration for tracking flow from local user input to the creation of a path.
*/
module TaintedPathLocalConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof LocalUserInput }
predicate isSink(DataFlow::Node sink) {
sink.asExpr() = any(PathCreation p).getAnInput()
or
sinkNode(sink, "create-file")
}
predicate isBarrier(DataFlow::Node sanitizer) {
sanitizer.getType() instanceof BoxedType or
sanitizer.getType() instanceof PrimitiveType or
sanitizer.getType() instanceof NumberType or
sanitizer instanceof PathInjectionSanitizer
}
predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
any(TaintedPathAdditionalTaintStep s).step(n1, n2)
}
}
/** Tracks flow from local user input to the creation of a path. */
module TaintedPathLocalFlow = TaintTracking::Global<TaintedPathLocalConfig>;

View File

@@ -0,0 +1,26 @@
/** Provides a taint tracking configuration to track cross site scripting. */
import java
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.security.XSS
/**
* A taint-tracking configuration for cross site scripting vulnerabilities.
*/
module XssConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
predicate isSink(DataFlow::Node sink) { sink instanceof XssSink }
predicate isBarrier(DataFlow::Node node) { node instanceof XssSanitizer }
predicate isBarrierOut(DataFlow::Node node) { node instanceof XssSinkBarrier }
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
any(XssAdditionalTaintStep s).step(node1, node2)
}
}
/** Tracks flow from remote sources to cross site scripting vulnerabilities. */
module XssFlow = TaintTracking::Global<XssConfig>;

View File

@@ -0,0 +1,44 @@
/** Provides dataflow configurations to be used in ZipSlip queries. */
import java
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.security.PathSanitizer
private import semmle.code.java.dataflow.ExternalFlow
/**
* A method that returns the name of an archive entry.
*/
private class ArchiveEntryNameMethod extends Method {
ArchiveEntryNameMethod() {
exists(RefType archiveEntry |
archiveEntry.hasQualifiedName("java.util.zip", "ZipEntry") or
archiveEntry.hasQualifiedName("org.apache.commons.compress.archivers", "ArchiveEntry")
|
this.getDeclaringType().getAnAncestor() = archiveEntry and
this.hasName("getName")
)
}
}
/**
* A taint-tracking configuration for reasoning about unsafe zip file extraction.
*/
module ZipSlipConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source.asExpr().(MethodAccess).getMethod() instanceof ArchiveEntryNameMethod
}
predicate isSink(DataFlow::Node sink) { sink instanceof FileCreationSink }
predicate isBarrier(DataFlow::Node node) { node instanceof PathInjectionSanitizer }
}
/** Tracks flow from archive entries to file creation. */
module ZipSlipFlow = TaintTracking::Global<ZipSlipConfig>;
/**
* A sink that represents a file creation, such as a file write, copy or move operation.
*/
private class FileCreationSink extends DataFlow::Node {
FileCreationSink() { sinkNode(this, "create-file") }
}

View File

@@ -14,36 +14,8 @@
*/
import java
import semmle.code.java.dataflow.FlowSources
private import semmle.code.java.dataflow.ExternalFlow
import semmle.code.java.security.PathCreation
import semmle.code.java.security.PathSanitizer
import TaintedPathCommon
module TaintedPathConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
predicate isSink(DataFlow::Node sink) {
sink.asExpr() = any(PathCreation p).getAnInput()
or
sinkNode(sink, ["create-file", "read-file"])
}
predicate isBarrier(DataFlow::Node sanitizer) {
sanitizer.getType() instanceof BoxedType or
sanitizer.getType() instanceof PrimitiveType or
sanitizer.getType() instanceof NumberType or
sanitizer instanceof PathInjectionSanitizer
}
predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
any(TaintedPathAdditionalTaintStep s).step(n1, n2)
}
}
module TaintedPath = TaintTracking::Global<TaintedPathConfig>;
import TaintedPath::PathGraph
import semmle.code.java.security.TaintedPathQuery
import TaintedPathFlow::PathGraph
/**
* Gets the data-flow node at which to report a path ending at `sink`.
@@ -53,13 +25,13 @@ import TaintedPath::PathGraph
* continue to report there; otherwise we report directly at `sink`.
*/
DataFlow::Node getReportingNode(DataFlow::Node sink) {
TaintedPath::flowTo(sink) and
TaintedPathFlow::flowTo(sink) and
if exists(PathCreation pc | pc.getAnInput() = sink.asExpr())
then result.asExpr() = any(PathCreation pc | pc.getAnInput() = sink.asExpr())
else result = sink
}
from TaintedPath::PathNode source, TaintedPath::PathNode sink
where TaintedPath::flowPath(source, sink)
from TaintedPathFlow::PathNode source, TaintedPathFlow::PathNode sink
where TaintedPathFlow::flowPath(source, sink)
select getReportingNode(sink.getNode()), source, sink, "This path depends on a $@.",
source.getNode(), "user-provided value"

View File

@@ -1,48 +0,0 @@
/**
* Models a very basic guard for the tainted path queries.
*/
import java
import semmle.code.java.frameworks.Networking
import semmle.code.java.dataflow.DataFlow
/**
* A unit class for adding additional taint steps.
*
* Extend this class to add additional taint steps that should apply to tainted path flow configurations.
*/
class TaintedPathAdditionalTaintStep extends Unit {
abstract predicate step(DataFlow::Node n1, DataFlow::Node n2);
}
private class DefaultTaintedPathAdditionalTaintStep extends TaintedPathAdditionalTaintStep {
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
exists(Argument a |
a = n1.asExpr() and
a.getCall() = n2.asExpr() and
a = any(TaintPreservingUriCtorParam tpp).getAnArgument()
)
}
}
private class TaintPreservingUriCtorParam extends Parameter {
TaintPreservingUriCtorParam() {
exists(Constructor ctor, int idx, int nParams |
ctor.getDeclaringType() instanceof TypeUri and
this = ctor.getParameter(idx) and
nParams = ctor.getNumberOfParameters()
|
// URI(String scheme, String ssp, String fragment)
idx = 1 and nParams = 3
or
// URI(String scheme, String host, String path, String fragment)
idx = [1, 2] and nParams = 4
or
// URI(String scheme, String authority, String path, String query, String fragment)
idx = 2 and nParams = 5
or
// URI(String scheme, String userInfo, String host, int port, String path, String query, String fragment)
idx = 4 and nParams = 7
)
}
}

View File

@@ -14,35 +14,7 @@
*/
import java
import semmle.code.java.dataflow.FlowSources
private import semmle.code.java.dataflow.ExternalFlow
import semmle.code.java.security.PathCreation
import semmle.code.java.security.PathSanitizer
import TaintedPathCommon
module TaintedPathLocalConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof LocalUserInput }
predicate isSink(DataFlow::Node sink) {
sink.asExpr() = any(PathCreation p).getAnInput()
or
sinkNode(sink, "create-file")
}
predicate isBarrier(DataFlow::Node sanitizer) {
sanitizer.getType() instanceof BoxedType or
sanitizer.getType() instanceof PrimitiveType or
sanitizer.getType() instanceof NumberType or
sanitizer instanceof PathInjectionSanitizer
}
predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
any(TaintedPathAdditionalTaintStep s).step(n1, n2)
}
}
module TaintedPathLocalFlow = TaintTracking::Global<TaintedPathLocalConfig>;
import semmle.code.java.security.TaintedPathQuery
import TaintedPathLocalFlow::PathGraph
/**

View File

@@ -13,48 +13,9 @@
*/
import java
import semmle.code.java.controlflow.Guards
import semmle.code.java.dataflow.SSA
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.security.PathSanitizer
private import semmle.code.java.dataflow.ExternalFlow
/**
* A method that returns the name of an archive entry.
*/
class ArchiveEntryNameMethod extends Method {
ArchiveEntryNameMethod() {
exists(RefType archiveEntry |
archiveEntry.hasQualifiedName("java.util.zip", "ZipEntry") or
archiveEntry.hasQualifiedName("org.apache.commons.compress.archivers", "ArchiveEntry")
|
this.getDeclaringType().getAnAncestor() = archiveEntry and
this.hasName("getName")
)
}
}
module ZipSlipConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source.asExpr().(MethodAccess).getMethod() instanceof ArchiveEntryNameMethod
}
predicate isSink(DataFlow::Node sink) { sink instanceof FileCreationSink }
predicate isBarrier(DataFlow::Node node) { node instanceof PathInjectionSanitizer }
}
module ZipSlipFlow = TaintTracking::Global<ZipSlipConfig>;
import semmle.code.java.security.ZipSlipQuery
import ZipSlipFlow::PathGraph
/**
* A sink that represents a file creation, such as a file write, copy or move operation.
*/
private class FileCreationSink extends DataFlow::Node {
FileCreationSink() { sinkNode(this, "create-file") }
}
from ZipSlipFlow::PathNode source, ZipSlipFlow::PathNode sink
where ZipSlipFlow::flowPath(source, sink)
select source.getNode(), source, sink,

View File

@@ -12,25 +12,7 @@
*/
import java
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.security.XSS
module XssConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
predicate isSink(DataFlow::Node sink) { sink instanceof XssSink }
predicate isBarrier(DataFlow::Node node) { node instanceof XssSanitizer }
predicate isBarrierOut(DataFlow::Node node) { node instanceof XssSinkBarrier }
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
any(XssAdditionalTaintStep s).step(node1, node2)
}
}
module XssFlow = TaintTracking::Global<XssConfig>;
import semmle.code.java.security.XssQuery
import XssFlow::PathGraph
from XssFlow::PathNode source, XssFlow::PathNode sink

View File

@@ -13,7 +13,7 @@
import java
import semmle.code.java.dataflow.FlowSources
import LdapInjectionLib
import semmle.code.java.security.LdapInjectionQuery
import LdapInjectionFlow::PathGraph
from LdapInjectionFlow::PathNode source, LdapInjectionFlow::PathNode sink

View File

@@ -11,68 +11,9 @@
*/
import java
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.dataflow.FlowSources
private import semmle.code.java.dataflow.ExternalFlow
/**
* A message interpolator Type that perform Expression Language (EL) evaluations
*/
class ELMessageInterpolatorType extends RefType {
ELMessageInterpolatorType() {
this.getASourceSupertype*()
.hasQualifiedName("org.hibernate.validator.messageinterpolation",
["ResourceBundleMessageInterpolator", "ValueFormatterMessageInterpolator"])
}
}
/**
* A method call that sets the application's default message interpolator.
*/
class SetMessageInterpolatorCall extends MethodAccess {
SetMessageInterpolatorCall() {
exists(Method m, RefType t |
this.getMethod() = m and
m.getDeclaringType().getASourceSupertype*() = t and
(
t.hasQualifiedName("javax.validation", ["Configuration", "ValidatorContext"]) and
m.getName() = "messageInterpolator"
or
t.hasQualifiedName("org.springframework.validation.beanvalidation",
["CustomValidatorBean", "LocalValidatorFactoryBean"]) and
m.getName() = "setMessageInterpolator"
)
)
}
/**
* The message interpolator is likely to be safe, because it does not process Java Expression Language expressions.
*/
predicate isSafe() { not this.getAnArgument().getType() instanceof ELMessageInterpolatorType }
}
/**
* Taint tracking BeanValidationConfiguration describing the flow of data from user input
* to the argument of a method that builds constraint error messages.
*/
module BeanValidationConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
predicate isSink(DataFlow::Node sink) { sink instanceof BeanValidationSink }
}
module BeanValidationFlow = TaintTracking::Global<BeanValidationConfig>;
import semmle.code.java.security.InsecureBeanValidationQuery
import BeanValidationFlow::PathGraph
/**
* A bean validation sink, such as method `buildConstraintViolationWithTemplate`
* declared on a subtype of `javax.validation.ConstraintValidatorContext`.
*/
private class BeanValidationSink extends DataFlow::Node {
BeanValidationSink() { sinkNode(this, "bean-validation") }
}
from BeanValidationFlow::PathNode source, BeanValidationFlow::PathNode sink
where
(

View File

@@ -12,42 +12,11 @@
*/
import java
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.security.ResponseSplitting
import semmle.code.java.security.ResponseSplittingQuery
import ResponseSplittingFlow::PathGraph
module ResponseSplittingConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source instanceof RemoteFlowSource and
not source instanceof SafeHeaderSplittingSource
}
predicate isSink(DataFlow::Node sink) { sink instanceof HeaderSplittingSink }
predicate isBarrier(DataFlow::Node node) {
node.getType() instanceof PrimitiveType
or
node.getType() instanceof BoxedType
or
exists(MethodAccess ma, string methodName, CompileTimeConstantExpr target |
node.asExpr() = ma and
ma.getMethod().hasQualifiedName("java.lang", "String", methodName) and
target = ma.getArgument(0) and
(
methodName = "replace" and target.getIntValue() = [10, 13] // 10 == "\n", 13 == "\r"
or
methodName = "replaceAll" and
target.getStringValue().regexpMatch(".*([\n\r]|\\[\\^[^\\]\r\n]*\\]).*")
)
)
}
}
module ResponseSplitting = TaintTracking::Global<ResponseSplittingConfig>;
import ResponseSplitting::PathGraph
from ResponseSplitting::PathNode source, ResponseSplitting::PathNode sink
where ResponseSplitting::flowPath(source, sink)
from ResponseSplittingFlow::PathNode source, ResponseSplittingFlow::PathNode sink
where ResponseSplittingFlow::flowPath(source, sink)
select sink.getNode(), source, sink,
"This header depends on a $@, which may cause a response-splitting vulnerability.",
source.getNode(), "user-provided value"

View File

@@ -11,24 +11,8 @@
*/
import java
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.security.ExternallyControlledFormatStringQuery
import semmle.code.java.StringFormat
module ExternallyControlledFormatStringConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
predicate isSink(DataFlow::Node sink) {
sink.asExpr() = any(StringFormat formatCall).getFormatArgument()
}
predicate isBarrier(DataFlow::Node node) {
node.getType() instanceof NumericType or node.getType() instanceof BooleanType
}
}
module ExternallyControlledFormatStringFlow =
TaintTracking::Global<ExternallyControlledFormatStringConfig>;
import ExternallyControlledFormatStringFlow::PathGraph
from