mirror of
https://github.com/github/codeql.git
synced 2026-04-24 08:15:14 +02:00
Merge pull request #13820 from owen-mc/go/refactor-data-flow-configurations
Go: Make flow configurations use new data flow API
This commit is contained in:
@@ -22,7 +22,6 @@
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll",
|
||||
"go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl1.qll",
|
||||
"go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl2.qll",
|
||||
"go/ql/lib/semmle/go/dataflow/internal/DataFlowImplForStringsNewReplacer.qll",
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl1.qll",
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll",
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll",
|
||||
@@ -572,4 +571,4 @@
|
||||
"python/ql/lib/semmle/python/security/internal/EncryptionKeySizes.qll",
|
||||
"java/ql/lib/semmle/code/java/security/internal/EncryptionKeySizes.qll"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
private import semmle.go.dataflow.DataFlowForStringsNewReplacer
|
||||
|
||||
/** Provides predicates and classes for working with string operations. */
|
||||
module StringOps {
|
||||
@@ -223,20 +222,10 @@ module StringOps {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A configuration for tracking flow from a call to `strings.NewReplacer` to
|
||||
* the receiver of a call to `strings.Replacer.Replace` or
|
||||
* `strings.Replacer.WriteString`.
|
||||
*/
|
||||
private class StringsNewReplacerConfiguration extends DataFlowForStringsNewReplacer::Configuration
|
||||
{
|
||||
StringsNewReplacerConfiguration() { this = "StringsNewReplacerConfiguration" }
|
||||
private module StringsNewReplacerConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof StringsNewReplacerCall }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source instanceof StringsNewReplacerCall
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(DataFlow::MethodCallNode call |
|
||||
sink = call.getReceiver() and
|
||||
call.getTarget().hasQualifiedName("strings", "Replacer", ["Replace", "WriteString"])
|
||||
@@ -244,6 +233,12 @@ module StringOps {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks data flow from a call to `strings.NewReplacer` to the receiver of
|
||||
* a call to `strings.Replacer.Replace` or `strings.Replacer.WriteString`.
|
||||
*/
|
||||
private module StringsNewReplacerFlow = DataFlow::Global<StringsNewReplacerConfig>;
|
||||
|
||||
/**
|
||||
* A call to `strings.Replacer.Replace` or `strings.Replacer.WriteString`.
|
||||
*/
|
||||
@@ -251,11 +246,8 @@ module StringOps {
|
||||
string replacedString;
|
||||
|
||||
StringsReplacerReplaceOrWriteString() {
|
||||
exists(
|
||||
StringsNewReplacerConfiguration config, StringsNewReplacerCall source,
|
||||
DataFlow::Node sink, DataFlow::MethodCallNode call
|
||||
|
|
||||
config.hasFlow(source, sink) and
|
||||
exists(StringsNewReplacerCall source, DataFlow::Node sink, DataFlow::MethodCallNode call |
|
||||
StringsNewReplacerFlow::flow(source, sink) and
|
||||
sink = call.getReceiver() and
|
||||
replacedString = source.getAReplacedArgument().getStringValue() and
|
||||
(
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
/**
|
||||
* Provides a library for local (intra-procedural) and global (inter-procedural)
|
||||
* data flow analysis: deciding whether data can flow from a _source_ to a
|
||||
* _sink_.
|
||||
*
|
||||
* Unless configured otherwise, _flow_ means that the exact value of
|
||||
* the source may reach the sink. We do not track flow across pointer
|
||||
* dereferences or array indexing. To track these types of flow, where the
|
||||
* exact value may not be preserved, import
|
||||
* `semmle.code.go.dataflow.TaintTracking`.
|
||||
*
|
||||
* To use global (interprocedural) data flow, extend the class
|
||||
* `DataFlow::Configuration` as documented on that class. To use local
|
||||
* (intraprocedural) data flow, invoke `DataFlow::localFlow` or
|
||||
* `DataFlow::LocalFlowStep` with arguments of type `DataFlow::Node`.
|
||||
*/
|
||||
|
||||
import go
|
||||
|
||||
/**
|
||||
* Provides a library for local (intra-procedural) and global (inter-procedural)
|
||||
* data flow analysis.
|
||||
*/
|
||||
module DataFlowForStringsNewReplacer {
|
||||
import semmle.go.dataflow.internal.DataFlowImplForStringsNewReplacer
|
||||
import Properties
|
||||
}
|
||||
@@ -1,402 +0,0 @@
|
||||
/**
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* Provides a `Configuration` class backwards-compatible interface to the data
|
||||
* flow library.
|
||||
*/
|
||||
|
||||
private import DataFlowImplCommon
|
||||
private import DataFlowImplSpecific::Private
|
||||
import DataFlowImplSpecific::Public
|
||||
private import DataFlowImpl
|
||||
import DataFlowImplCommonPublic
|
||||
import FlowStateString
|
||||
private import codeql.util.Unit
|
||||
|
||||
/**
|
||||
* A configuration of interprocedural data flow analysis. This defines
|
||||
* sources, sinks, and any other configurable aspect of the analysis. Each
|
||||
* use of the global data flow library must define its own unique extension
|
||||
* of this abstract class. To create a configuration, extend this class with
|
||||
* a subclass whose characteristic predicate is a unique singleton string.
|
||||
* For example, write
|
||||
*
|
||||
* ```ql
|
||||
* class MyAnalysisConfiguration extends DataFlow::Configuration {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
* // Optionally override `isBarrier`.
|
||||
* // Optionally override `isAdditionalFlowStep`.
|
||||
* }
|
||||
* ```
|
||||
* Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and
|
||||
* the edges are those data-flow steps that preserve the value of the node
|
||||
* along with any additional edges defined by `isAdditionalFlowStep`.
|
||||
* Specifying nodes in `isBarrier` will remove those nodes from the graph, and
|
||||
* specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going
|
||||
* and/or out-going edges from those nodes, respectively.
|
||||
*
|
||||
* Then, to query whether there is flow between some `source` and `sink`,
|
||||
* write
|
||||
*
|
||||
* ```ql
|
||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
* ```
|
||||
*
|
||||
* Multiple configurations can coexist, but two classes extending
|
||||
* `DataFlow::Configuration` should never depend on each other. One of them
|
||||
* should instead depend on a `DataFlow2::Configuration`, a
|
||||
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
|
||||
*/
|
||||
abstract class Configuration extends string {
|
||||
bindingset[this]
|
||||
Configuration() { any() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source.
|
||||
*/
|
||||
predicate isSource(Node source) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source with the given initial
|
||||
* `state`.
|
||||
*/
|
||||
predicate isSource(Node source, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink.
|
||||
*/
|
||||
predicate isSink(Node sink) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink accepting `state`.
|
||||
*/
|
||||
predicate isSink(Node sink, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited. This completely removes
|
||||
* `node` from the data flow graph.
|
||||
*/
|
||||
predicate isBarrier(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited when the flow state is
|
||||
* `state`.
|
||||
*/
|
||||
predicate isBarrier(Node node, FlowState state) { none() }
|
||||
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
predicate isBarrierIn(Node node) { none() }
|
||||
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited.
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited when
|
||||
* the flow state is `state`
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
* This can be overridden to a smaller value to improve performance (a
|
||||
* value of 0 disables field flow), or a larger value to get more results.
|
||||
*/
|
||||
int fieldFlowBranchLimit() { result = 2 }
|
||||
|
||||
/**
|
||||
* Gets a data flow configuration feature to add restrictions to the set of
|
||||
* valid flow paths.
|
||||
*
|
||||
* - `FeatureHasSourceCallContext`:
|
||||
* Assume that sources have some existing call context to disallow
|
||||
* conflicting return-flow directly following the source.
|
||||
* - `FeatureHasSinkCallContext`:
|
||||
* Assume that sinks have some existing call context to disallow
|
||||
* conflicting argument-to-parameter flow directly preceding the sink.
|
||||
* - `FeatureEqualSourceSinkCallContext`:
|
||||
* Implies both of the above and additionally ensures that the entire flow
|
||||
* path preserves the call context.
|
||||
*
|
||||
* These features are generally not relevant for typical end-to-end data flow
|
||||
* queries, but should only be used for constructing paths that need to
|
||||
* somehow be pluggable in another path context.
|
||||
*/
|
||||
FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlow(Node source, Node sink) { hasFlow(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `FlowExploration<explorationLimit>` instead.
|
||||
*
|
||||
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
|
||||
* measured in approximate number of interprocedural steps.
|
||||
*/
|
||||
deprecated int explorationLimit() { none() }
|
||||
|
||||
/**
|
||||
* Holds if hidden nodes should be included in the data flow graph.
|
||||
*
|
||||
* This feature should only be used for debugging or when the data flow graph
|
||||
* is not visualized (for example in a `path-problem` query).
|
||||
*/
|
||||
predicate includeHiddenNodes() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* This class exists to prevent mutual recursion between the user-overridden
|
||||
* member predicates of `Configuration` and the rest of the data-flow library.
|
||||
* Good performance cannot be guaranteed in the presence of such recursion, so
|
||||
* it should be replaced by using more than one copy of the data flow library.
|
||||
*/
|
||||
abstract private class ConfigurationRecursionPrevention extends Configuration {
|
||||
bindingset[this]
|
||||
ConfigurationRecursionPrevention() { any() }
|
||||
|
||||
override predicate hasFlow(Node source, Node sink) {
|
||||
strictcount(Node n | this.isSource(n)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSource(n, _)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSink(n)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSink(n, _)) < 0
|
||||
or
|
||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0
|
||||
or
|
||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, _, n2, _)) < 0
|
||||
or
|
||||
super.hasFlow(source, sink)
|
||||
}
|
||||
}
|
||||
|
||||
/** A bridge class to access the deprecated `isBarrierGuard`. */
|
||||
private class BarrierGuardGuardedNodeBridge extends Unit {
|
||||
abstract predicate guardedNode(Node n, Configuration config);
|
||||
|
||||
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
|
||||
}
|
||||
|
||||
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
|
||||
deprecated override predicate guardedNode(Node n, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g, state) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private FlowState relevantState(Configuration config) {
|
||||
config.isSource(_, result) or
|
||||
config.isSink(_, result) or
|
||||
config.isBarrier(_, result) or
|
||||
config.isAdditionalFlowStep(_, result, _, _) or
|
||||
config.isAdditionalFlowStep(_, _, _, result)
|
||||
}
|
||||
|
||||
private newtype TConfigState =
|
||||
TMkConfigState(Configuration config, FlowState state) {
|
||||
state = relevantState(config) or state instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
|
||||
|
||||
private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
|
||||
|
||||
private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
|
||||
|
||||
private module Config implements FullStateConfigSig {
|
||||
class FlowState = TConfigState;
|
||||
|
||||
predicate isSource(Node source, FlowState state) {
|
||||
getConfig(state).isSource(source, getState(state))
|
||||
or
|
||||
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
predicate isSink(Node sink) { none() }
|
||||
|
||||
predicate isSink(Node sink, FlowState state) {
|
||||
getConfig(state).isSink(sink, getState(state))
|
||||
or
|
||||
getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
predicate isBarrier(Node node) { none() }
|
||||
|
||||
predicate isBarrier(Node node, FlowState state) {
|
||||
getConfig(state).isBarrier(node, getState(state)) or
|
||||
getConfig(state).isBarrier(node) or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getState(state), getConfig(state)) or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getConfig(state))
|
||||
}
|
||||
|
||||
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }
|
||||
|
||||
predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) }
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2) {
|
||||
singleConfiguration() and
|
||||
any(Configuration config).isAdditionalFlowStep(node1, node2)
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and
|
||||
getConfig(state2) = getConfig(state1)
|
||||
or
|
||||
not singleConfiguration() and
|
||||
getConfig(state1).isAdditionalFlowStep(node1, node2) and
|
||||
state2 = state1
|
||||
}
|
||||
|
||||
predicate allowImplicitRead(Node node, ContentSet c) {
|
||||
any(Configuration config).allowImplicitRead(node, c)
|
||||
}
|
||||
|
||||
predicate neverSkip(Node node) { none() }
|
||||
|
||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate sourceGrouping(Node source, string sourceGroup) {
|
||||
any(Configuration config).sourceGrouping(source, sourceGroup)
|
||||
}
|
||||
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) {
|
||||
any(Configuration config).sinkGrouping(sink, sinkGroup)
|
||||
}
|
||||
|
||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
|
||||
*/
|
||||
class PathNode instanceof I::PathNode {
|
||||
/** Gets a textual representation of this element. */
|
||||
final string toString() { result = super.toString() }
|
||||
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
final string toStringWithContext() { result = super.toStringWithContext() }
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
final predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
final Node getNode() { result = super.getNode() }
|
||||
|
||||
/** Gets the `FlowState` of this node. */
|
||||
final FlowState getState() { result = getState(super.getState()) }
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
final Configuration getConfiguration() { result = getConfig(super.getState()) }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() { result = super.getASuccessor() }
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
final predicate isSource() { super.isSource() }
|
||||
|
||||
/** Holds if this node is a grouping of source nodes. */
|
||||
final predicate isSourceGroup(string group) { super.isSourceGroup(group) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
module PathGraph = I::PathGraph;
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
source0.getNode() = source and
|
||||
sink0.getNode() = sink
|
||||
)
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
predicate flowsTo = hasFlow/3;
|
||||
@@ -14,9 +14,11 @@ module AllocationSizeOverflow {
|
||||
import AllocationSizeOverflowCustomizations::AllocationSizeOverflow
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use copies of `FindLargeLensConfig` and `FindLargeLensFlow` instead.
|
||||
*
|
||||
* A taint-tracking configuration for identifying `len(...)` calls whose argument may be large.
|
||||
*/
|
||||
class FindLargeLensConfiguration extends TaintTracking2::Configuration {
|
||||
deprecated class FindLargeLensConfiguration extends TaintTracking2::Configuration {
|
||||
FindLargeLensConfiguration() { this = "AllocationSizeOverflow::FindLargeLens" }
|
||||
|
||||
override predicate isSource(DataFlow::Node nd) { nd instanceof Source }
|
||||
@@ -30,16 +32,31 @@ module AllocationSizeOverflow {
|
||||
override predicate isSanitizer(DataFlow::Node nd) { nd instanceof Sanitizer }
|
||||
}
|
||||
|
||||
private module FindLargeLensConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node nd) { nd instanceof Source }
|
||||
|
||||
predicate isSink(DataFlow::Node nd) { nd = Builtin::len().getACall().getArgument(0) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node nd) { nd instanceof Sanitizer }
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks taint flow to find `len(...)` calls whose argument may be large.
|
||||
*/
|
||||
private module FindLargeLensFlow = TaintTracking::Global<FindLargeLensConfig>;
|
||||
|
||||
private DataFlow::CallNode getALargeLenCall() {
|
||||
exists(FindLargeLensConfiguration config, DataFlow::Node lenArg | config.hasFlow(_, lenArg) |
|
||||
exists(DataFlow::Node lenArg | FindLargeLensFlow::flow(_, lenArg) |
|
||||
result.getArgument(0) = lenArg
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Flow` instead.
|
||||
*
|
||||
* A taint-tracking configuration for identifying allocation-size overflows.
|
||||
*/
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
deprecated class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "AllocationSizeOverflow" }
|
||||
|
||||
override predicate isSource(DataFlow::Node nd) { nd instanceof Source }
|
||||
@@ -70,4 +87,33 @@ module AllocationSizeOverflow {
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node nd) { nd instanceof Sanitizer }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `nd` is at a position where overflow might occur, and its result is used to compute
|
||||
* allocation size `allocsz`.
|
||||
*/
|
||||
predicate isSinkWithAllocationSize(DataFlow::Node nd, DataFlow::Node allocsz) {
|
||||
nd.(Sink).getAllocationSize() = allocsz
|
||||
}
|
||||
|
||||
private module Config implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { isSinkWithAllocationSize(sink, _) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node nd) { nd instanceof Sanitizer }
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
additionalStep(pred, succ)
|
||||
or
|
||||
exists(DataFlow::CallNode c |
|
||||
c = getALargeLenCall() and
|
||||
pred = c.getArgument(0) and
|
||||
succ = c
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Tracks taint flow to find allocation-size overflows. */
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ module CleartextLogging {
|
||||
import CleartextLoggingCustomizations::CleartextLogging
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Flow` instead.
|
||||
*
|
||||
* A data-flow tracking configuration for clear-text logging of sensitive information.
|
||||
*
|
||||
* This configuration identifies flows from `Source`s, which are sources of
|
||||
@@ -25,7 +27,7 @@ module CleartextLogging {
|
||||
* added either by extending the relevant class, or by subclassing this configuration itself,
|
||||
* and amending the sources and sinks.
|
||||
*/
|
||||
class Configuration extends DataFlow::Configuration {
|
||||
deprecated class Configuration extends DataFlow::Configuration {
|
||||
Configuration() { this = "CleartextLogging" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
@@ -56,4 +58,43 @@ module CleartextLogging {
|
||||
not any(Protobuf::GetMethod gm).taintStep(src, trg)
|
||||
}
|
||||
}
|
||||
|
||||
private module Config 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 Barrier
|
||||
or
|
||||
exists(DataFlow::CallNode call | node = call.getResult() |
|
||||
call.getTarget() = Builtin::error().getType().getMethod("Error")
|
||||
or
|
||||
call.getTarget().(Method).hasQualifiedName("fmt", "Stringer", "String")
|
||||
)
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node src, DataFlow::Node trg) {
|
||||
// A taint propagating data-flow edge through structs: a tainted write taints the entire struct.
|
||||
exists(Write write |
|
||||
write.writesField(trg.(DataFlow::PostUpdateNode).getPreUpdateNode(), _, src)
|
||||
)
|
||||
or
|
||||
// taint steps that do not include flow through fields. Field reads would produce FPs due to
|
||||
// the additional taint step above that taints whole structs from individual field writes.
|
||||
TaintTracking::localTaintStep(src, trg) and
|
||||
not TaintTracking::fieldReadStep(src, trg) and
|
||||
// Also exclude protobuf field fetches, since they amount to single field reads.
|
||||
not any(Protobuf::GetMethod gm).taintStep(src, trg)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks data flow for reasoning about clear-text logging of sensitive
|
||||
* information, from `Source`s, which are sources of sensitive data, to
|
||||
* `Sink`s, which is an abstract class representing all the places sensitive
|
||||
* data may be stored in cleartext. Additional sources or sinks can be added
|
||||
* by extending the relevant class.
|
||||
*/
|
||||
module Flow = DataFlow::Global<Config>;
|
||||
}
|
||||
|
||||
@@ -17,10 +17,12 @@ module CommandInjection {
|
||||
import CommandInjectionCustomizations::CommandInjection
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Flow` instead.
|
||||
*
|
||||
* A taint-tracking configuration for reasoning about command-injection vulnerabilities
|
||||
* with sinks which are not sanitized by `--`.
|
||||
*/
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
deprecated class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "CommandInjection" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
@@ -39,6 +41,22 @@ module CommandInjection {
|
||||
}
|
||||
}
|
||||
|
||||
private module Config implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(Sink s | sink = s | not s.doubleDashIsSanitizing())
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks taint flow for reasoning about command-injection vulnerabilities
|
||||
* with sinks which are not sanitized by `--`.
|
||||
*/
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
|
||||
private class ArgumentArrayWithDoubleDash extends DataFlow::Node {
|
||||
int doubleDashIndex;
|
||||
|
||||
@@ -79,10 +97,12 @@ module CommandInjection {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `DoubleDashSanitizingFlow` instead.
|
||||
*
|
||||
* A taint-tracking configuration for reasoning about command-injection vulnerabilities
|
||||
* with sinks which are sanitized by `--`.
|
||||
*/
|
||||
class DoubleDashSanitizingConfiguration extends TaintTracking::Configuration {
|
||||
deprecated class DoubleDashSanitizingConfiguration extends TaintTracking::Configuration {
|
||||
DoubleDashSanitizingConfiguration() { this = "CommandInjectionWithDoubleDashSanitizer" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
@@ -101,4 +121,21 @@ module CommandInjection {
|
||||
guard instanceof SanitizerGuard
|
||||
}
|
||||
}
|
||||
|
||||
private module DoubleDashSanitizingConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { exists(Sink s | sink = s | s.doubleDashIsSanitizing()) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node instanceof Sanitizer or
|
||||
node = any(ArgumentArrayWithDoubleDash array).getASanitizedElement()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks taint flow for reasoning about command-injection vulnerabilities
|
||||
* with sinks which are sanitized by `--`.
|
||||
*/
|
||||
module DoubleDashSanitizingFlow = TaintTracking::Global<DoubleDashSanitizingConfig>;
|
||||
}
|
||||
|
||||
@@ -188,8 +188,12 @@ class UnknownExternalApiDataNode extends ExternalApiDataNode {
|
||||
/** DEPRECATED: Alias for UnknownExternalApiDataNode */
|
||||
deprecated class UnknownExternalAPIDataNode = UnknownExternalApiDataNode;
|
||||
|
||||
/** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalApiDataNode`s. */
|
||||
class UntrustedDataToExternalApiConfig extends TaintTracking::Configuration {
|
||||
/**
|
||||
* DEPRECATED: Use `UntrustedDataToExternalApiFlow` 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 UntrustedFlowSource }
|
||||
@@ -197,11 +201,26 @@ class UntrustedDataToExternalApiConfig extends TaintTracking::Configuration {
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof ExternalApiDataNode }
|
||||
}
|
||||
|
||||
private module UntrustedDataConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof ExternalApiDataNode }
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks data flow from `RemoteFlowSource`s to `ExternalApiDataNode`s.
|
||||
*/
|
||||
module UntrustedDataToExternalApiFlow = DataFlow::Global<UntrustedDataConfig>;
|
||||
|
||||
/** DEPRECATED: Alias for UntrustedDataToExternalApiConfig */
|
||||
deprecated class UntrustedDataToExternalAPIConfig = UntrustedDataToExternalApiConfig;
|
||||
|
||||
/** A configuration for tracking flow from `RemoteFlowSource`s to `UnknownExternalApiDataNode`s. */
|
||||
class UntrustedDataToUnknownExternalApiConfig extends TaintTracking::Configuration {
|
||||
/**
|
||||
* DEPRECATED: Use `UntrustedDataToUnknownExternalApiFlow` instead.
|
||||
*
|
||||
* A configuration for tracking flow from `RemoteFlowSource`s to `UnknownExternalApiDataNode`s.
|
||||
*/
|
||||
deprecated class UntrustedDataToUnknownExternalApiConfig extends TaintTracking::Configuration {
|
||||
UntrustedDataToUnknownExternalApiConfig() { this = "UntrustedDataToUnknownExternalAPIConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource }
|
||||
@@ -212,14 +231,24 @@ class UntrustedDataToUnknownExternalApiConfig extends TaintTracking::Configurati
|
||||
/** DEPRECATED: Alias for UntrustedDataToUnknownExternalApiConfig */
|
||||
deprecated class UntrustedDataToUnknownExternalAPIConfig = UntrustedDataToUnknownExternalApiConfig;
|
||||
|
||||
private module UntrustedDataToUnknownExternalApiConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof UnknownExternalApiDataNode }
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks data flow from `RemoteFlowSource`s to `UnknownExternalApiDataNode`s.
|
||||
*/
|
||||
module UntrustedDataToUnknownExternalApiFlow =
|
||||
DataFlow::Global<UntrustedDataToUnknownExternalApiConfig>;
|
||||
|
||||
/** A node representing untrusted data being passed to an external API. */
|
||||
class UntrustedExternalApiDataNode extends ExternalApiDataNode {
|
||||
UntrustedExternalApiDataNode() { any(UntrustedDataToExternalApiConfig c).hasFlow(_, this) }
|
||||
UntrustedExternalApiDataNode() { UntrustedDataToExternalApiFlow::flow(_, this) }
|
||||
|
||||
/** Gets a source of untrusted data which is passed to this external API data node. */
|
||||
DataFlow::Node getAnUntrustedSource() {
|
||||
any(UntrustedDataToExternalApiConfig c).hasFlow(result, this)
|
||||
}
|
||||
DataFlow::Node getAnUntrustedSource() { UntrustedDataToExternalApiFlow::flow(result, this) }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for UntrustedExternalApiDataNode */
|
||||
|
||||
@@ -51,11 +51,13 @@ private predicate isIncorrectIntegerConversion(int sourceBitSize, int sinkBitSiz
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: use `Flow` instead.
|
||||
*
|
||||
* A taint-tracking configuration for reasoning about when an integer
|
||||
* obtained from parsing a string flows to a type conversion to a smaller
|
||||
* integer types, which could cause unexpected values.
|
||||
*/
|
||||
class ConversionWithoutBoundsCheckConfig extends TaintTracking::Configuration {
|
||||
deprecated class ConversionWithoutBoundsCheckConfig extends TaintTracking::Configuration {
|
||||
boolean sinkIsSigned;
|
||||
int sourceBitSize;
|
||||
int sinkBitSize;
|
||||
@@ -148,6 +150,119 @@ class ConversionWithoutBoundsCheckConfig extends TaintTracking::Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
/** Flow state for ConversionWithoutBoundsCheckConfig. */
|
||||
newtype IntegerConversionFlowState =
|
||||
/** Keep track of info about the source and potential sinks. */
|
||||
TFlowstate(boolean sinkIsSigned, int sourceBitSize, int sinkBitSize) {
|
||||
sinkIsSigned in [true, false] and
|
||||
isIncorrectIntegerConversion(sourceBitSize, sinkBitSize)
|
||||
}
|
||||
|
||||
/** Gets the bit size of the source. */
|
||||
int getSourceBitSize(IntegerConversionFlowState state) { state = TFlowstate(_, result, _) }
|
||||
|
||||
private module ConversionWithoutBoundsCheckConfig implements DataFlow::StateConfigSig {
|
||||
class FlowState = IntegerConversionFlowState;
|
||||
|
||||
predicate isSource(DataFlow::Node source, FlowState state) {
|
||||
exists(
|
||||
DataFlow::CallNode c, IntegerParser::Range ip, int apparentBitSize, int effectiveBitSize
|
||||
|
|
||||
c.getTarget() = ip and source = c.getResult(0)
|
||||
|
|
||||
(
|
||||
apparentBitSize = ip.getTargetBitSize()
|
||||
or
|
||||
// If we are reading a variable, check if it is
|
||||
// `strconv.IntSize`, and use 0 if it is.
|
||||
exists(DataFlow::Node rawBitSize | rawBitSize = ip.getTargetBitSizeInput().getNode(c) |
|
||||
if rawBitSize = any(Strconv::IntSize intSize).getARead()
|
||||
then apparentBitSize = 0
|
||||
else apparentBitSize = rawBitSize.getIntValue()
|
||||
)
|
||||
) and
|
||||
(
|
||||
if apparentBitSize = 0
|
||||
then effectiveBitSize = getIntTypeBitSize(source.getFile())
|
||||
else effectiveBitSize = apparentBitSize
|
||||
) and
|
||||
// `effectiveBitSize` could be any value between 0 and 64, but we
|
||||
// can round it up to the nearest size of an integer type without
|
||||
// changing behavior.
|
||||
exists(int sourceBitSize |
|
||||
sourceBitSize = min(int b | b in [0, 8, 16, 32, 64] and b >= effectiveBitSize)
|
||||
|
|
||||
state = TFlowstate(_, sourceBitSize, _)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a typecast to an integer type with size `bitSize` (where
|
||||
* 0 represents architecture-dependent) and the expression being typecast is
|
||||
* not also in a right-shift expression. We allow this case because it is
|
||||
* a common pattern to serialise `byte(v)`, `byte(v >> 8)`, and so on.
|
||||
*/
|
||||
additional predicate isSinkWithBitSize(
|
||||
DataFlow::TypeCastNode sink, boolean sinkIsSigned, int bitSize
|
||||
) {
|
||||
sink.asExpr() instanceof ConversionExpr and
|
||||
exists(IntegerType integerType | sink.getResultType().getUnderlyingType() = integerType |
|
||||
(
|
||||
bitSize = integerType.getSize()
|
||||
or
|
||||
not exists(integerType.getSize()) and
|
||||
bitSize = getIntTypeBitSize(sink.getFile())
|
||||
) and
|
||||
if integerType instanceof SignedIntegerType then sinkIsSigned = true else sinkIsSigned = false
|
||||
) and
|
||||
not exists(ShrExpr shrExpr |
|
||||
shrExpr.getLeftOperand().getGlobalValueNumber() =
|
||||
sink.getOperand().asExpr().getGlobalValueNumber() or
|
||||
shrExpr.getLeftOperand().(AndExpr).getAnOperand().getGlobalValueNumber() =
|
||||
sink.getOperand().asExpr().getGlobalValueNumber()
|
||||
)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink, FlowState state) {
|
||||
// We use the argument of the type conversion as the configuration sink so that we
|
||||
// can sanitize the result of the conversion to prevent flow on to further sinks
|
||||
// without needing to use `isSanitizerOut`, which doesn't work with flow states
|
||||
// (and therefore the legacy `TaintTracking::Configuration` class).
|
||||
exists(boolean sinkIsSigned, int sinkBitSize |
|
||||
state = TFlowstate(sinkIsSigned, _, sinkBitSize)
|
||||
|
|
||||
isSinkWithBitSize(sink.getASuccessor(), sinkIsSigned, sinkBitSize)
|
||||
)
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node node, FlowState state) {
|
||||
exists(boolean sinkIsSigned, int sourceBitSize, int sinkBitSize |
|
||||
state = TFlowstate(sinkIsSigned, sourceBitSize, sinkBitSize)
|
||||
|
|
||||
// To catch flows that only happen on 32-bit architectures we
|
||||
// consider an architecture-dependent sink bit size to be 32.
|
||||
exists(UpperBoundCheckGuard g, int bitSize |
|
||||
if sinkBitSize != 0 then bitSize = sinkBitSize else bitSize = 32
|
||||
|
|
||||
node = DataFlow::BarrierGuard<upperBoundCheckGuard/3>::getABarrierNodeForGuard(g) and
|
||||
g.isBoundFor(bitSize, sinkIsSigned)
|
||||
)
|
||||
or
|
||||
exists(int bitSize |
|
||||
isIncorrectIntegerConversion(sourceBitSize, bitSize) and
|
||||
isSinkWithBitSize(node, sinkIsSigned, bitSize)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks taint flow from an integer obtained from parsing a string that flows
|
||||
* to a type conversion to a smaller integer type, which could cause data loss.
|
||||
*/
|
||||
module Flow = TaintTracking::GlobalWithState<ConversionWithoutBoundsCheckConfig>;
|
||||
|
||||
private predicate upperBoundCheckGuard(DataFlow::Node g, Expr e, boolean branch) {
|
||||
g.(UpperBoundCheckGuard).checks(e, branch)
|
||||
}
|
||||
|
||||
@@ -17,10 +17,12 @@ module InsecureRandomness {
|
||||
import InsecureRandomnessCustomizations::InsecureRandomness
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Flow` instead.
|
||||
*
|
||||
* A taint-tracking configuration for reasoning about random values that are
|
||||
* not cryptographically secure.
|
||||
*/
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
deprecated class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "InsecureRandomness" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
@@ -32,4 +34,21 @@ module InsecureRandomness {
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
|
||||
}
|
||||
|
||||
/** Holds if `sink` is a sink for this configuration with kind `kind`. */
|
||||
predicate isSinkWithKind(Sink sink, string kind) { kind = sink.getKind() }
|
||||
|
||||
private module Config implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { isSinkWithKind(sink, _) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks taint flow from randomly generated values which are not
|
||||
* cryptographically secure to cryptographic applications.
|
||||
*/
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@ module LogInjection {
|
||||
import LogInjectionCustomizations::LogInjection
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Flow` instead.
|
||||
*
|
||||
* A taint-tracking configuration for reasoning about log injection vulnerabilities.
|
||||
*/
|
||||
deprecated class Configuration extends TaintTracking::Configuration {
|
||||
@@ -31,9 +33,7 @@ module LogInjection {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for reasoning about log injection vulnerabilities.
|
||||
*/
|
||||
/** Config for reasoning about log injection vulnerabilities. */
|
||||
module Config implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
@@ -42,5 +42,6 @@ module LogInjection {
|
||||
predicate isBarrier(DataFlow::Node sanitizer) { sanitizer instanceof Sanitizer }
|
||||
}
|
||||
|
||||
/** Tracks taint flow for reasoning about log injection vulnerabilities. */
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
}
|
||||
|
||||
@@ -18,9 +18,11 @@ module OpenUrlRedirect {
|
||||
import OpenUrlRedirectCustomizations::OpenUrlRedirect
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Flow` instead.
|
||||
*
|
||||
* A data-flow configuration for reasoning about unvalidated URL redirections.
|
||||
*/
|
||||
class Configuration extends DataFlow::Configuration {
|
||||
deprecated class Configuration extends DataFlow::Configuration {
|
||||
Configuration() { this = "OpenUrlRedirect" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
@@ -63,4 +65,45 @@ module OpenUrlRedirect {
|
||||
guard instanceof BarrierGuard
|
||||
}
|
||||
}
|
||||
|
||||
private module Config 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 Barrier }
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
// taint steps that do not include flow through fields
|
||||
TaintTracking::localTaintStep(pred, succ) and not TaintTracking::fieldReadStep(pred, succ)
|
||||
or
|
||||
// explicit extra taint steps for this query
|
||||
any(AdditionalStep s).hasTaintStep(pred, succ)
|
||||
or
|
||||
// propagate to a URL when its host is assigned to
|
||||
exists(Write w, Field f, SsaWithFields v | f.hasQualifiedName("net/url", "URL", "Host") |
|
||||
w.writesField(v.getAUse(), f, pred) and succ = v.getAUse()
|
||||
)
|
||||
or
|
||||
// propagate out of most URL fields, but not `ForceQuery` and `Scheme`
|
||||
exists(Field f, string fn |
|
||||
f.hasQualifiedName("net/url", "URL", fn) and
|
||||
not fn in ["ForceQuery", "Scheme"]
|
||||
|
|
||||
succ.(Read).readsField(pred, f)
|
||||
)
|
||||
}
|
||||
|
||||
predicate isBarrierOut(DataFlow::Node node) {
|
||||
// block propagation of this unsafe value when its host is overwritten
|
||||
exists(Write w, Field f | f.hasQualifiedName("net/url", "URL", "Host") |
|
||||
w.writesField(node.getASuccessor(), f, _)
|
||||
)
|
||||
or
|
||||
hostnameSanitizingPrefixEdge(node, _)
|
||||
}
|
||||
}
|
||||
|
||||
/** Tracks taint flow from unvalidated, untrusted data to URL redirections. */
|
||||
module Flow = DataFlow::Global<Config>;
|
||||
}
|
||||
|
||||
@@ -17,9 +17,11 @@ module ReflectedXss {
|
||||
import ReflectedXssCustomizations::ReflectedXss
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Flow` instead.
|
||||
*
|
||||
* A taint-tracking configuration for reasoning about XSS.
|
||||
*/
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
deprecated class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "ReflectedXss" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
@@ -35,4 +37,15 @@ module ReflectedXss {
|
||||
guard instanceof SanitizerGuard
|
||||
}
|
||||
}
|
||||
|
||||
private module Config 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 }
|
||||
}
|
||||
|
||||
/** Tracks taint flow from untrusted data to XSS attack vectors. */
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
}
|
||||
|
||||
@@ -17,9 +17,11 @@ module RequestForgery {
|
||||
import RequestForgeryCustomizations::RequestForgery
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Flow` instead.
|
||||
*
|
||||
* A taint-tracking configuration for reasoning about request forgery.
|
||||
*/
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
deprecated class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "RequestForgery" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
@@ -47,4 +49,24 @@ module RequestForgery {
|
||||
super.isSanitizerGuard(guard) or guard instanceof SanitizerGuard
|
||||
}
|
||||
}
|
||||
|
||||
private module Config 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 }
|
||||
|
||||
predicate isBarrierOut(DataFlow::Node node) { node instanceof SanitizerEdge }
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
// propagate to a URL when its host is assigned to
|
||||
exists(Write w, Field f, SsaWithFields v | f.hasQualifiedName("net/url", "URL", "Host") |
|
||||
w.writesField(v.getAUse(), f, pred) and succ = v.getAUse()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Tracks taint flow from untrusted data to request forgery attack vectors. */
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
}
|
||||
|
||||
@@ -17,9 +17,11 @@ module SafeUrlFlow {
|
||||
import SafeUrlFlowCustomizations::SafeUrlFlow
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Flow` instead.
|
||||
*
|
||||
* A taint-tracking configuration for reasoning about safe URLs.
|
||||
*/
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
deprecated class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "SafeUrlFlow" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
@@ -42,4 +44,29 @@ module SafeUrlFlow {
|
||||
node instanceof SanitizerEdge
|
||||
}
|
||||
}
|
||||
|
||||
private module Config implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
// propagate to a URL when its host is assigned to
|
||||
exists(Write w, Field f, SsaWithFields v | f.hasQualifiedName("net/url", "URL", "Host") |
|
||||
w.writesField(v.getAUse(), f, node1) and node2 = v.getAUse()
|
||||
)
|
||||
}
|
||||
|
||||
predicate isBarrierOut(DataFlow::Node node) {
|
||||
// block propagation of this safe value when its host is overwritten
|
||||
exists(Write w, Field f | f.hasQualifiedName("net/url", "URL", "Host") |
|
||||
w.writesField(node.getASuccessor(), f, _)
|
||||
)
|
||||
or
|
||||
node instanceof SanitizerEdge
|
||||
}
|
||||
}
|
||||
|
||||
/** Tracks taint flow for reasoning about safe URLs. */
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
}
|
||||
|
||||
@@ -14,9 +14,11 @@ module SqlInjection {
|
||||
import SqlInjectionCustomizations::SqlInjection
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Flow` instead.
|
||||
*
|
||||
* A taint-tracking configuration for reasoning about SQL-injection vulnerabilities.
|
||||
*/
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
deprecated class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "SqlInjection" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
@@ -36,4 +38,19 @@ module SqlInjection {
|
||||
guard instanceof SanitizerGuard
|
||||
}
|
||||
}
|
||||
|
||||
private module Config implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
NoSql::isAdditionalMongoTaintStep(pred, succ)
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
|
||||
}
|
||||
|
||||
/** Tracks taint flow for reasoning about SQL-injection vulnerabilities. */
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
}
|
||||
|
||||
@@ -17,9 +17,11 @@ import CommandInjectionCustomizations
|
||||
*/
|
||||
module StoredCommand {
|
||||
/**
|
||||
* DEPRECATED: Use `Flow` instead.
|
||||
*
|
||||
* A taint-tracking configuration for reasoning about command-injection vulnerabilities.
|
||||
*/
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
deprecated class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "StoredCommand" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
@@ -39,4 +41,19 @@ module StoredCommand {
|
||||
guard instanceof CommandInjection::SanitizerGuard
|
||||
}
|
||||
}
|
||||
|
||||
private module Config implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source instanceof StoredXss::Source and
|
||||
// exclude file names, since those are not generally an issue
|
||||
not source instanceof StoredXss::FileNameSource
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof CommandInjection::Sink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) { node instanceof CommandInjection::Sanitizer }
|
||||
}
|
||||
|
||||
/** Tracks taint flow for reasoning about command-injection vulnerabilities. */
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
}
|
||||
|
||||
@@ -17,9 +17,11 @@ module StoredXss {
|
||||
import StoredXssCustomizations::StoredXss
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Flow` instead.
|
||||
*
|
||||
* A taint-tracking configuration for reasoning about XSS.
|
||||
*/
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
deprecated class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "StoredXss" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
@@ -35,4 +37,15 @@ module StoredXss {
|
||||
guard instanceof SanitizerGuard
|
||||
}
|
||||
}
|
||||
|
||||
private module Config 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 }
|
||||
}
|
||||
|
||||
/** Tracks taint flow for reasoning about XSS. */
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
}
|
||||
|
||||
@@ -14,10 +14,12 @@ module StringBreak {
|
||||
import StringBreakCustomizations::StringBreak
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Flow` instead.
|
||||
*
|
||||
* A taint-tracking configuration for reasoning about unsafe-quoting vulnerabilities,
|
||||
* parameterized with the type of quote being tracked.
|
||||
*/
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
deprecated class Configuration extends TaintTracking::Configuration {
|
||||
Quote quote;
|
||||
|
||||
Configuration() { this = "StringBreak" + quote }
|
||||
@@ -31,4 +33,26 @@ module StringBreak {
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node nd) { quote = nd.(Sanitizer).getQuote() }
|
||||
}
|
||||
|
||||
private module Config implements DataFlow::StateConfigSig {
|
||||
/** The flow state that we track is the type of quote used. */
|
||||
class FlowState = Quote;
|
||||
|
||||
predicate isSource(DataFlow::Node source, FlowState state) {
|
||||
source instanceof Source and exists(state)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink, FlowState state) { state = sink.(Sink).getQuote() }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node, FlowState state) {
|
||||
state = node.(Sanitizer).getQuote()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks taint flow from untrusted data which may contain single or double
|
||||
* quotes to uses where those quotes need to be escaped. The type of quote
|
||||
* is accessible through the `Sink`.
|
||||
*/
|
||||
module Flow = TaintTracking::GlobalWithState<Config>;
|
||||
}
|
||||
|
||||
@@ -12,9 +12,11 @@ module TaintedPath {
|
||||
import TaintedPathCustomizations::TaintedPath
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Flow` instead.
|
||||
*
|
||||
* A taint-tracking configuration for reasoning about path-traversal vulnerabilities.
|
||||
*/
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
deprecated class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "TaintedPath" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
@@ -26,4 +28,15 @@ module TaintedPath {
|
||||
node instanceof Sanitizer
|
||||
}
|
||||
}
|
||||
|
||||
private module Config 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 }
|
||||
}
|
||||
|
||||
/** Tracks taint flow for reasoning about path-traversal vulnerabilities. */
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
}
|
||||
|
||||
@@ -14,9 +14,11 @@ module UnsafeUnzipSymlink {
|
||||
import UnsafeUnzipSymlinkCustomizations::UnsafeUnzipSymlink
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use copies of `EvalSymlinksConfig` and `EvalSymlinksFlow` instead.
|
||||
*
|
||||
* A taint-flow configuration tracking archive header fields flowing to a `path/filepath.EvalSymlinks` call.
|
||||
*/
|
||||
class EvalSymlinksConfiguration extends TaintTracking2::Configuration {
|
||||
deprecated class EvalSymlinksConfiguration extends TaintTracking2::Configuration {
|
||||
EvalSymlinksConfiguration() { this = "Archive header field symlinks resolved" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof FilenameWithSymlinks }
|
||||
@@ -33,18 +35,35 @@ module UnsafeUnzipSymlink {
|
||||
}
|
||||
}
|
||||
|
||||
// Archive header field symlinks resolved
|
||||
private module EvalSymlinksConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof FilenameWithSymlinks }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof EvalSymlinksSink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) { node instanceof EvalSymlinksInvalidator }
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks taint flow from archive header fields to
|
||||
* `path/filepath.EvalSymlinks` calls.
|
||||
*/
|
||||
private module EvalSymlinksFlow = TaintTracking::Global<EvalSymlinksConfig>;
|
||||
|
||||
/**
|
||||
* Holds if `node` is an archive header field read that flows to a `path/filepath.EvalSymlinks` call.
|
||||
*/
|
||||
private predicate symlinksEvald(DataFlow::Node node) {
|
||||
exists(EvalSymlinksConfiguration c | c.hasFlow(getASimilarReadNode(node), _))
|
||||
EvalSymlinksFlow::flow(getASimilarReadNode(node), _)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Flow` instead.
|
||||
*
|
||||
* A taint-flow configuration tracking archive header fields flowing to an `os.Symlink` call,
|
||||
* which never flow to a `path/filepath.EvalSymlinks` call.
|
||||
*/
|
||||
class SymlinkConfiguration extends TaintTracking::Configuration {
|
||||
deprecated class SymlinkConfiguration extends TaintTracking::Configuration {
|
||||
SymlinkConfiguration() { this = "Unsafe unzipping of symlinks" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
@@ -63,4 +82,21 @@ module UnsafeUnzipSymlink {
|
||||
guard instanceof SymlinkSanitizerGuard
|
||||
}
|
||||
}
|
||||
|
||||
private module Config implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source instanceof FilenameWithSymlinks and
|
||||
not symlinksEvald(source)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof SymlinkSink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) { node instanceof SymlinkSanitizer }
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks taint flow from archive header fields to an `os.Symlink` call,
|
||||
* which never flow to a `path/filepath.EvalSymlinks` call.
|
||||
*/
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
}
|
||||
|
||||
@@ -14,9 +14,11 @@ module XPathInjection {
|
||||
import XPathInjectionCustomizations::XPathInjection
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Flow` instead.
|
||||
*
|
||||
* A taint-tracking configuration for reasoning about untrusted user input used in an XPath expression.
|
||||
*/
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
deprecated class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "XPathInjection" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
@@ -32,4 +34,18 @@ module XPathInjection {
|
||||
guard instanceof SanitizerGuard
|
||||
}
|
||||
}
|
||||
|
||||
private module Config 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 }
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks taint flow for reasoning about untrusted user input used in an
|
||||
* XPath expression.
|
||||
*/
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
}
|
||||
|
||||
@@ -12,9 +12,11 @@ module ZipSlip {
|
||||
import ZipSlipCustomizations::ZipSlip
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Flow` instead.
|
||||
*
|
||||
* A taint-tracking configuration for reasoning about zip-slip vulnerabilities.
|
||||
*/
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
deprecated class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "ZipSlip" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
@@ -30,4 +32,15 @@ module ZipSlip {
|
||||
guard instanceof SanitizerGuard
|
||||
}
|
||||
}
|
||||
|
||||
private module Config 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 }
|
||||
}
|
||||
|
||||
/** Tracks taint flow for reasoning about zip-slip vulnerabilities. */
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
import DataFlow::PathGraph
|
||||
|
||||
/**
|
||||
* Holds if a `flag` for use with `os.OpenFile` implies that the resulting
|
||||
@@ -124,25 +123,27 @@ predicate isHandledSync(DataFlow::Node sink, DataFlow::CallNode syncCall) {
|
||||
not unhandledCall(syncCall)
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow configuration which traces writable file handles resulting from calls to
|
||||
* `os.OpenFile` to `os.File.Close` calls on them.
|
||||
*/
|
||||
class UnhandledFileCloseDataFlowConfiguration extends DataFlow::Configuration {
|
||||
UnhandledFileCloseDataFlowConfiguration() { this = "UnhandledCloseWritableHandle" }
|
||||
module UnhandledFileCloseConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { isWritableFileHandle(source, _) }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { isWritableFileHandle(source, _) }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { isCloseSink(sink, _) }
|
||||
predicate isSink(DataFlow::Node sink) { isCloseSink(sink, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks data flow for reasoning about which writable file handles resulting from calls to
|
||||
* `os.OpenFile` have `os.File.Close` called on them.
|
||||
*/
|
||||
module UnhandledFileCloseFlow = DataFlow::Global<UnhandledFileCloseConfig>;
|
||||
|
||||
import UnhandledFileCloseFlow::PathGraph
|
||||
|
||||
from
|
||||
UnhandledFileCloseDataFlowConfiguration cfg, DataFlow::PathNode source,
|
||||
DataFlow::CallNode openCall, DataFlow::PathNode sink, DataFlow::CallNode closeCall
|
||||
UnhandledFileCloseFlow::PathNode source, DataFlow::CallNode openCall,
|
||||
UnhandledFileCloseFlow::PathNode sink, DataFlow::CallNode closeCall
|
||||
where
|
||||
// find data flow from an `os.OpenFile` call to an `os.File.Close` call
|
||||
// where the handle is writable
|
||||
cfg.hasFlowPath(source, sink) and
|
||||
UnhandledFileCloseFlow::flowPath(source, sink) and
|
||||
isWritableFileHandle(source.getNode(), openCall) and
|
||||
// get the `CallNode` corresponding to the sink
|
||||
isCloseSink(sink.getNode(), closeCall)
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
import DataFlow::PathGraph
|
||||
|
||||
/**
|
||||
* Holds if `pattern` is a regular expression pattern for URLs with a host matched by `hostPart`,
|
||||
@@ -80,10 +79,8 @@ predicate regexpGuardsError(RegexpPattern regexp) {
|
||||
)
|
||||
}
|
||||
|
||||
class Config extends DataFlow::Configuration {
|
||||
Config() { this = "IncompleteHostNameRegexp::Config" }
|
||||
|
||||
predicate isSourceString(DataFlow::Node source, string hostPart) {
|
||||
module IncompleteHostNameRegexpConfig implements DataFlow::ConfigSig {
|
||||
additional predicate isSourceString(DataFlow::Node source, string hostPart) {
|
||||
exists(Expr e |
|
||||
e = source.asExpr() and
|
||||
isIncompleteHostNameRegexpPattern(e.getStringValue(), hostPart)
|
||||
@@ -95,9 +92,9 @@ class Config extends DataFlow::Configuration {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { this.isSourceString(source, _) }
|
||||
predicate isSource(DataFlow::Node source) { isSourceString(source, _) }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink instanceof RegexpPattern and
|
||||
forall(Http::RequestHandler handler | regexpGuardsHandler(sink, handler) |
|
||||
not handler = getASafeHandler()
|
||||
@@ -106,8 +103,14 @@ class Config extends DataFlow::Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
from Config c, DataFlow::PathNode source, DataFlow::PathNode sink, string hostPart
|
||||
where c.hasFlowPath(source, sink) and c.isSourceString(source.getNode(), hostPart)
|
||||
module Flow = DataFlow::Global<IncompleteHostNameRegexpConfig>;
|
||||
|
||||
import Flow::PathGraph
|
||||
|
||||
from Flow::PathNode source, Flow::PathNode sink, string hostPart
|
||||
where
|
||||
Flow::flowPath(source, sink) and
|
||||
IncompleteHostNameRegexpConfig::isSourceString(source.getNode(), hostPart)
|
||||
select source, source, sink,
|
||||
"This regular expression has an unescaped dot before '" + hostPart + "', " +
|
||||
"so it might match more hosts than expected when $@.", sink, "the regular expression is used"
|
||||
|
||||
@@ -60,10 +60,8 @@ predicate isInterestingUnanchoredRegexpString(string re, string msg) {
|
||||
"hosts may come before or after it."
|
||||
}
|
||||
|
||||
class Config extends DataFlow::Configuration {
|
||||
Config() { this = "MissingRegexpAnchor::Config" }
|
||||
|
||||
predicate isSourceString(DataFlow::Node source, string msg) {
|
||||
module Config implements DataFlow::ConfigSig {
|
||||
additional predicate isSourceString(DataFlow::Node source, string msg) {
|
||||
exists(Expr e | e = source.asExpr() |
|
||||
isInterestingUnanchoredRegexpString(e.getStringValue(), msg)
|
||||
or
|
||||
@@ -71,11 +69,13 @@ class Config extends DataFlow::Configuration {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { this.isSourceString(source, _) }
|
||||
predicate isSource(DataFlow::Node source) { isSourceString(source, _) }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof RegexpPattern }
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof RegexpPattern }
|
||||
}
|
||||
|
||||
from Config c, DataFlow::PathNode source, string msg
|
||||
where c.hasFlowPath(source, _) and c.isSourceString(source.getNode(), msg)
|
||||
select source.getNode(), msg
|
||||
module Flow = DataFlow::Global<Config>;
|
||||
|
||||
from DataFlow::Node source, string msg
|
||||
where Flow::flow(source, _) and Config::isSourceString(source, msg)
|
||||
select source, msg
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
import DataFlow::PathGraph
|
||||
|
||||
/**
|
||||
* Holds if `source` corresponds to a string literal that contains an escaped `character`.
|
||||
@@ -28,11 +27,8 @@ predicate containsEscapedCharacter(DataFlow::Node source, string character) {
|
||||
)
|
||||
}
|
||||
|
||||
/** A dataflow configuration that traces strings containing suspicious escape sequences to a use as a regular expression. */
|
||||
class Config extends DataFlow::Configuration {
|
||||
Config() { this = "SuspiciousRegexpEscape" }
|
||||
|
||||
predicate isSourceString(DataFlow::Node source, string report) {
|
||||
module SuspiciousCharacterInRegexpConfig implements DataFlow::ConfigSig {
|
||||
additional predicate isSourceString(DataFlow::Node source, string report) {
|
||||
containsEscapedCharacter(source, "a") and
|
||||
report =
|
||||
"the bell character \\a; did you mean \\\\a, the Vim alphabetic character class (use [[:alpha:]] instead) or \\\\A, the beginning of text?"
|
||||
@@ -41,12 +37,22 @@ class Config extends DataFlow::Configuration {
|
||||
report = "a literal backspace \\b; did you mean \\\\b, a word boundary?"
|
||||
}
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { this.isSourceString(source, _) }
|
||||
predicate isSource(DataFlow::Node source) { isSourceString(source, _) }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof RegexpPattern }
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof RegexpPattern }
|
||||
}
|
||||
|
||||
from Config c, DataFlow::PathNode source, DataFlow::PathNode sink, string report
|
||||
where c.hasFlowPath(source, sink) and c.isSourceString(source.getNode(), report)
|
||||
/**
|
||||
* Tracks data flow from strings containing suspicious escape sequences to a
|
||||
* use as a regular expression.
|
||||
*/
|
||||
module Flow = DataFlow::Global<SuspiciousCharacterInRegexpConfig>;
|
||||
|
||||
import Flow::PathGraph
|
||||
|
||||
from Flow::PathNode source, Flow::PathNode sink, string report
|
||||
where
|
||||
Flow::flowPath(source, sink) and
|
||||
SuspiciousCharacterInRegexpConfig::isSourceString(source.getNode(), report)
|
||||
select source, source, sink, "This string literal that is $@ contains " + report, sink,
|
||||
"used as a regular expression"
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
|
||||
import go
|
||||
import semmle.go.security.ExternalAPIs
|
||||
import DataFlow::PathGraph
|
||||
import UntrustedDataToExternalApiFlow::PathGraph
|
||||
|
||||
from UntrustedDataToExternalApiConfig config, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where config.hasFlowPath(source, sink)
|
||||
from UntrustedDataToExternalApiFlow::PathNode source, UntrustedDataToExternalApiFlow::PathNode sink
|
||||
where UntrustedDataToExternalApiFlow::flowPath(source, sink)
|
||||
select sink, source, sink,
|
||||
"Call to " + sink.getNode().(ExternalApiDataNode).getFunctionDescription() +
|
||||
" with untrusted data from $@.", source, source.toString()
|
||||
|
||||
@@ -11,11 +11,12 @@
|
||||
|
||||
import go
|
||||
import semmle.go.security.ExternalAPIs
|
||||
import DataFlow::PathGraph
|
||||
import UntrustedDataToUnknownExternalApiFlow::PathGraph
|
||||
|
||||
from
|
||||
UntrustedDataToUnknownExternalApiConfig config, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where config.hasFlowPath(source, sink)
|
||||
UntrustedDataToUnknownExternalApiFlow::PathNode source,
|
||||
UntrustedDataToUnknownExternalApiFlow::PathNode sink
|
||||
where UntrustedDataToUnknownExternalApiFlow::flowPath(source, sink)
|
||||
select sink, source, sink,
|
||||
"Call to " + sink.getNode().(UnknownExternalApiDataNode).getFunctionDescription() +
|
||||
" with untrusted data from $@.", source, source.toString()
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
import semmle.go.security.TaintedPath::TaintedPath
|
||||
import DataFlow::PathGraph
|
||||
import semmle.go.security.TaintedPath
|
||||
import TaintedPath::Flow::PathGraph
|
||||
|
||||
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where cfg.hasFlowPath(source, sink)
|
||||
from TaintedPath::Flow::PathNode source, TaintedPath::Flow::PathNode sink
|
||||
where TaintedPath::Flow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "This path depends on a $@.", source.getNode(),
|
||||
"user-provided value"
|
||||
|
||||
@@ -15,11 +15,11 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
import DataFlow::PathGraph
|
||||
import semmle.go.security.UnsafeUnzipSymlink::UnsafeUnzipSymlink
|
||||
import semmle.go.security.UnsafeUnzipSymlink
|
||||
import UnsafeUnzipSymlink::Flow::PathGraph
|
||||
|
||||
from SymlinkConfiguration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where cfg.hasFlowPath(source, sink)
|
||||
from UnsafeUnzipSymlink::Flow::PathNode source, UnsafeUnzipSymlink::Flow::PathNode sink
|
||||
where UnsafeUnzipSymlink::Flow::flowPath(source, sink)
|
||||
select source.getNode(), source, sink,
|
||||
"Unresolved path from an archive header, which may point outside the archive root, is used in $@.",
|
||||
sink.getNode(), "symlink creation"
|
||||
|
||||
@@ -13,11 +13,11 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
import semmle.go.security.ZipSlip::ZipSlip
|
||||
import DataFlow::PathGraph
|
||||
import semmle.go.security.ZipSlip
|
||||
import ZipSlip::Flow::PathGraph
|
||||
|
||||
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where cfg.hasFlowPath(source, sink)
|
||||
from ZipSlip::Flow::PathNode source, ZipSlip::Flow::PathNode sink
|
||||
where ZipSlip::Flow::flowPath(source, sink)
|
||||
select source.getNode(), source, sink,
|
||||
"Unsanitized archive entry, which may contain '..', is used in a $@.", sink.getNode(),
|
||||
"file system operation"
|
||||
|
||||
@@ -13,11 +13,17 @@
|
||||
|
||||
import go
|
||||
import semmle.go.security.CommandInjection
|
||||
import DataFlow::PathGraph
|
||||
|
||||
from
|
||||
CommandInjection::Configuration cfg, CommandInjection::DoubleDashSanitizingConfiguration cfg2,
|
||||
DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where cfg.hasFlowPath(source, sink) or cfg2.hasFlowPath(source, sink)
|
||||
module Flow =
|
||||
DataFlow::MergePathGraph<CommandInjection::Flow::PathNode,
|
||||
CommandInjection::DoubleDashSanitizingFlow::PathNode, CommandInjection::Flow::PathGraph,
|
||||
CommandInjection::DoubleDashSanitizingFlow::PathGraph>;
|
||||
|
||||
import Flow::PathGraph
|
||||
|
||||
from Flow::PathNode source, Flow::PathNode sink
|
||||
where
|
||||
CommandInjection::Flow::flowPath(source.asPathNode1(), sink.asPathNode1()) or
|
||||
CommandInjection::DoubleDashSanitizingFlow::flowPath(source.asPathNode2(), sink.asPathNode2())
|
||||
select sink.getNode(), source, sink, "This command depends on a $@.", source.getNode(),
|
||||
"user-provided value"
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
|
||||
import go
|
||||
import semmle.go.security.StoredCommand
|
||||
import DataFlow::PathGraph
|
||||
import StoredCommand::Flow::PathGraph
|
||||
|
||||
from StoredCommand::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where cfg.hasFlowPath(source, sink)
|
||||
from StoredCommand::Flow::PathNode source, StoredCommand::Flow::PathNode sink
|
||||
where StoredCommand::Flow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "This command depends on a $@.", source.getNode(),
|
||||
"stored value"
|
||||
|
||||
@@ -13,14 +13,14 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
import semmle.go.security.ReflectedXss::ReflectedXss
|
||||
import DataFlow::PathGraph
|
||||
import semmle.go.security.ReflectedXss
|
||||
import ReflectedXss::Flow::PathGraph
|
||||
|
||||
from
|
||||
Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, string msg, string part,
|
||||
ReflectedXss::Flow::PathNode source, ReflectedXss::Flow::PathNode sink, string msg, string part,
|
||||
Locatable partloc
|
||||
where
|
||||
cfg.hasFlowPath(source, sink) and
|
||||
ReflectedXss::Flow::flowPath(source, sink) and
|
||||
(
|
||||
exists(string kind | kind = sink.getNode().(SharedXss::Sink).getSinkKind() |
|
||||
kind = "rawtemplate" and
|
||||
|
||||
@@ -13,10 +13,10 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
import semmle.go.security.StoredXss::StoredXss
|
||||
import DataFlow::PathGraph
|
||||
import semmle.go.security.StoredXss
|
||||
import StoredXss::Flow::PathGraph
|
||||
|
||||
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where cfg.hasFlowPath(source, sink)
|
||||
from StoredXss::Flow::PathNode source, StoredXss::Flow::PathNode sink
|
||||
where StoredXss::Flow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "Stored cross-site scripting vulnerability due to $@.",
|
||||
source.getNode(), "stored value"
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
|
||||
import go
|
||||
import semmle.go.security.SqlInjection
|
||||
import DataFlow::PathGraph
|
||||
import SqlInjection::Flow::PathGraph
|
||||
|
||||
from SqlInjection::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where cfg.hasFlowPath(source, sink)
|
||||
from SqlInjection::Flow::PathNode source, SqlInjection::Flow::PathNode sink
|
||||
where SqlInjection::Flow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "This query depends on a $@.", source.getNode(),
|
||||
"user-provided value"
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
|
||||
import go
|
||||
import semmle.go.security.StringBreak
|
||||
import DataFlow::PathGraph
|
||||
import StringBreak::Flow::PathGraph
|
||||
|
||||
from StringBreak::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where cfg.hasFlowPath(source, sink)
|
||||
from StringBreak::Flow::PathNode source, StringBreak::Flow::PathNode sink
|
||||
where StringBreak::Flow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink,
|
||||
"If this $@ contains a " + cfg.getQuote().getType() + " quote, it could break out of " +
|
||||
"the enclosing quotes.", source.getNode(), "JSON value"
|
||||
"If this $@ contains a " + sink.getNode().(StringBreak::Sink).getQuote().getType() +
|
||||
" quote, it could break out of " + "the enclosing quotes.", source.getNode(), "JSON value"
|
||||
|
||||
@@ -12,15 +12,15 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
import DataFlow::PathGraph
|
||||
import semmle.go.security.AllocationSizeOverflow
|
||||
import AllocationSizeOverflow::Flow::PathGraph
|
||||
|
||||
from
|
||||
AllocationSizeOverflow::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink,
|
||||
AllocationSizeOverflow::Flow::PathNode source, AllocationSizeOverflow::Flow::PathNode sink,
|
||||
DataFlow::Node allocsz
|
||||
where
|
||||
cfg.hasFlowPath(source, sink) and
|
||||
cfg.isSinkWithAllocationSize(sink.getNode(), allocsz)
|
||||
AllocationSizeOverflow::Flow::flowPath(source, sink) and
|
||||
AllocationSizeOverflow::isSinkWithAllocationSize(sink.getNode(), allocsz)
|
||||
select sink, source, sink,
|
||||
"This operation, which is used in an $@, involves a $@ and might overflow.", allocsz,
|
||||
"allocation", source, "potentially large value"
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
|
||||
import go
|
||||
import semmle.go.security.InsecureFeatureFlag::InsecureFeatureFlag
|
||||
import DataFlow::PathGraph
|
||||
|
||||
/**
|
||||
* A flag indicating the program is in debug or development mode, or that stack
|
||||
@@ -44,22 +43,16 @@ class DebugStackFunction extends Function {
|
||||
DebugStackFunction() { this.hasQualifiedName("runtime/debug", "Stack") }
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration that looks for stack traces being written to
|
||||
* an HTTP response body without an intervening debug- or development-mode conditional.
|
||||
*/
|
||||
class StackTraceExposureConfig extends TaintTracking::Configuration {
|
||||
StackTraceExposureConfig() { this = "StackTraceExposureConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node node) {
|
||||
node.(DataFlow::PostUpdateNode).getPreUpdateNode() =
|
||||
module StackTraceExposureConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source.(DataFlow::PostUpdateNode).getPreUpdateNode() =
|
||||
any(StackFunction f).getACall().getArgument(0) or
|
||||
node = any(DebugStackFunction f).getACall().getResult()
|
||||
source = any(DebugStackFunction f).getACall().getResult()
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node node) { node instanceof Http::ResponseBody }
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof Http::ResponseBody }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
// Sanitise everything controlled by an is-debug-mode check.
|
||||
// Imprecision: I don't try to guess which arm of a branch is intended
|
||||
// to mean debug mode, and which is production mode.
|
||||
@@ -71,8 +64,16 @@ class StackTraceExposureConfig extends TaintTracking::Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
from StackTraceExposureConfig cfg, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where cfg.hasFlowPath(source, sink)
|
||||
/**
|
||||
* Tracks taint flow for reasoning about stack traces being written to an HTTP
|
||||
* response body without an intervening debug- or development-mode conditional.
|
||||
*/
|
||||
module StackTraceExposureFlow = TaintTracking::Global<StackTraceExposureConfig>;
|
||||
|
||||
import StackTraceExposureFlow::PathGraph
|
||||
|
||||
from StackTraceExposureFlow::PathNode source, StackTraceExposureFlow::PathNode sink
|
||||
where StackTraceExposureFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink,
|
||||
"HTTP response depends on $@ and may be exposed to an external user.", source.getNode(),
|
||||
"stack trace information"
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
import semmle.go.security.CleartextLogging::CleartextLogging
|
||||
import DataFlow::PathGraph
|
||||
import semmle.go.security.CleartextLogging
|
||||
import CleartextLogging::Flow::PathGraph
|
||||
|
||||
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where cfg.hasFlowPath(source, sink)
|
||||
from CleartextLogging::Flow::PathNode source, CleartextLogging::Flow::PathNode sink
|
||||
where CleartextLogging::Flow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "$@ flows to a logging call.", source.getNode(),
|
||||
"Sensitive data returned by " + source.getNode().(Source).describe()
|
||||
"Sensitive data returned by " + source.getNode().(CleartextLogging::Source).describe()
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
import DataFlow::PathGraph
|
||||
|
||||
/** The `ssh.InsecureIgnoreHostKey` function, which allows connecting to any host regardless of its host key. */
|
||||
class InsecureIgnoreHostKey extends Function {
|
||||
@@ -55,45 +54,48 @@ class InsecureHostKeyCallbackFunc extends HostKeyCallbackFunc {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A data-flow configuration for identifying `HostKeyCallbackFunc` instances that reach `ClientConfig.HostKeyCallback` fields.
|
||||
*/
|
||||
class HostKeyCallbackAssignmentConfig extends DataFlow::Configuration {
|
||||
HostKeyCallbackAssignmentConfig() { this = "HostKeyCallbackAssignmentConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof HostKeyCallbackFunc }
|
||||
module Config implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof HostKeyCallbackFunc }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a value written by `write` to a field `ClientConfig.HostKeyCallback`.
|
||||
*/
|
||||
predicate writeIsSink(DataFlow::Node sink, Write write) {
|
||||
additional predicate writeIsSink(DataFlow::Node sink, Write write) {
|
||||
exists(Field f |
|
||||
f.hasQualifiedName(CryptoSsh::packagePath(), "ClientConfig", "HostKeyCallback") and
|
||||
write.writesField(_, f, sink)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { this.writeIsSink(sink, _) }
|
||||
predicate isSink(DataFlow::Node sink) { writeIsSink(sink, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks data flow to identify `HostKeyCallbackFunc` instances that reach
|
||||
* `ClientConfig.HostKeyCallback` fields.
|
||||
*/
|
||||
module Flow = DataFlow::Global<Config>;
|
||||
|
||||
import Flow::PathGraph
|
||||
|
||||
/**
|
||||
* Holds if a secure host-check function reaches `sink` or another similar sink.
|
||||
*
|
||||
* A sink is considered similar if it writes to the same variable and field.
|
||||
*/
|
||||
predicate hostCheckReachesSink(DataFlow::PathNode sink) {
|
||||
exists(HostKeyCallbackAssignmentConfig config, DataFlow::PathNode source |
|
||||
predicate hostCheckReachesSink(Flow::PathNode sink) {
|
||||
exists(Flow::PathNode source |
|
||||
not source.getNode() instanceof InsecureHostKeyCallbackFunc and
|
||||
(
|
||||
config.hasFlowPath(source, sink)
|
||||
Flow::flowPath(source, sink)
|
||||
or
|
||||
exists(
|
||||
DataFlow::PathNode otherSink, Write sinkWrite, Write otherSinkWrite,
|
||||
Flow::PathNode otherSink, Write sinkWrite, Write otherSinkWrite,
|
||||
SsaWithFields sinkAccessPath, SsaWithFields otherSinkAccessPath
|
||||
|
|
||||
config.hasFlowPath(source, otherSink) and
|
||||
config.writeIsSink(sink.getNode(), sinkWrite) and
|
||||
config.writeIsSink(otherSink.getNode(), otherSinkWrite) and
|
||||
Flow::flowPath(source, otherSink) and
|
||||
Config::writeIsSink(sink.getNode(), sinkWrite) and
|
||||
Config::writeIsSink(otherSink.getNode(), otherSinkWrite) and
|
||||
sinkWrite.writesField(sinkAccessPath.getAUse(), _, sink.getNode()) and
|
||||
otherSinkWrite.writesField(otherSinkAccessPath.getAUse(), _, otherSink.getNode()) and
|
||||
otherSinkAccessPath = sinkAccessPath.similar()
|
||||
@@ -102,9 +104,9 @@ predicate hostCheckReachesSink(DataFlow::PathNode sink) {
|
||||
)
|
||||
}
|
||||
|
||||
from HostKeyCallbackAssignmentConfig config, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
from Flow::PathNode source, Flow::PathNode sink
|
||||
where
|
||||
config.hasFlowPath(source, sink) and
|
||||
Flow::flowPath(source, sink) and
|
||||
source.getNode() instanceof InsecureHostKeyCallbackFunc and
|
||||
// Exclude cases where a good access-path function reaches the same or a similar sink
|
||||
// (these probably indicate optional host-checking)
|
||||
|
||||
@@ -11,29 +11,30 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
import DataFlow::PathGraph
|
||||
|
||||
/**
|
||||
* A data flow tracking configuration for tracking flow from RSA key length to
|
||||
* calls to RSA key generation functions.
|
||||
*/
|
||||
class RsaKeyTrackingConfiguration extends DataFlow::Configuration {
|
||||
RsaKeyTrackingConfiguration() { this = "RsaKeyTrackingConfiguration" }
|
||||
module Config implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source.getIntValue() < 2048 }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source.getIntValue() < 2048 }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(DataFlow::CallNode c |
|
||||
sink = c.getArgument(1) and
|
||||
c.getTarget().hasQualifiedName("crypto/rsa", "GenerateKey")
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isBarrier(DataFlow::Node node) {
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node = DataFlow::BarrierGuard<comparisonBarrierGuard/3>::getABarrierNode()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks data flow from an RSA key length to a calls to an RSA key generation
|
||||
* function.
|
||||
*/
|
||||
module Flow = DataFlow::Global<Config>;
|
||||
|
||||
import Flow::PathGraph
|
||||
|
||||
/**
|
||||
* Holds if `g` is a comparison which guarantees that `e` is at least 2048 on `branch`,
|
||||
* considered as a barrier guard for key sizes.
|
||||
@@ -50,6 +51,6 @@ predicate comparisonBarrierGuard(DataFlow::Node g, Expr e, boolean branch) {
|
||||
)
|
||||
}
|
||||
|
||||
from RsaKeyTrackingConfiguration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where cfg.hasFlowPath(source, sink)
|
||||
from Flow::PathNode source, Flow::PathNode sink
|
||||
where Flow::flowPath(source, sink)
|
||||
select sink, source, sink, "The size of this RSA key should be at least 2048 bits."
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
import DataFlow::PathGraph
|
||||
import semmle.go.security.InsecureFeatureFlag::InsecureFeatureFlag
|
||||
|
||||
/**
|
||||
@@ -51,17 +50,11 @@ int getASecureTlsVersion() {
|
||||
*/
|
||||
int getATlsVersion() { result = getASecureTlsVersion() or isInsecureTlsVersion(result, _, _) }
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for tracking flow from TLS versions to the
|
||||
* `tls.Config.MinVersion` and `tls.Config.MaxVersion` fields.
|
||||
*/
|
||||
class TlsVersionFlowConfig extends TaintTracking::Configuration {
|
||||
TlsVersionFlowConfig() { this = "TlsVersionFlowConfig" }
|
||||
|
||||
module TlsVersionFlowConfig implements DataFlow::ConfigSig {
|
||||
/**
|
||||
* Holds if `source` is a TLS version source yielding value `val`.
|
||||
*/
|
||||
predicate intIsSource(DataFlow::Node source, int val) {
|
||||
additional predicate intIsSource(DataFlow::Node source, int val) {
|
||||
val = source.getIntValue() and
|
||||
val = getATlsVersion() and
|
||||
not DataFlow::isReturnedWithError(source)
|
||||
@@ -70,25 +63,29 @@ class TlsVersionFlowConfig extends TaintTracking::Configuration {
|
||||
/**
|
||||
* Holds if `fieldWrite` writes `sink` to `base`.`fld`, where `fld` is a TLS version field.
|
||||
*/
|
||||
predicate isSink(DataFlow::Node sink, Field fld, DataFlow::Node base, Write fieldWrite) {
|
||||
additional predicate isSink(DataFlow::Node sink, Field fld, DataFlow::Node base, Write fieldWrite) {
|
||||
fld.hasQualifiedName("crypto/tls", "Config", ["MinVersion", "MaxVersion"]) and
|
||||
fieldWrite.writesField(base, fld, sink)
|
||||
}
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { this.intIsSource(source, _) }
|
||||
predicate isSource(DataFlow::Node source) { intIsSource(source, _) }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { this.isSink(sink, _, _, _) }
|
||||
predicate isSink(DataFlow::Node sink) { isSink(sink, _, _, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks taint flow from TLS versions to the `tls.Config.MinVersion` and
|
||||
* `tls.Config.MaxVersion` fields.
|
||||
*/
|
||||
module TlsVersionFlow = TaintTracking::Global<TlsVersionFlowConfig>;
|
||||
|
||||
/**
|
||||
* Holds if `config` exhibits a secure TLS version flowing from `source` to `sink`, which flows into `fld`.
|
||||
*/
|
||||
predicate secureTlsVersionFlow(
|
||||
TlsVersionFlowConfig config, DataFlow::PathNode source, DataFlow::PathNode sink, Field fld
|
||||
) {
|
||||
predicate secureTlsVersionFlow(DataFlow::Node source, DataFlow::Node sink, Field fld) {
|
||||
exists(int version |
|
||||
config.hasFlowPath(source, sink) and
|
||||
config.intIsSource(source.getNode(), version) and
|
||||
TlsVersionFlow::flow(source, sink) and
|
||||
TlsVersionFlowConfig::intIsSource(source, version) and
|
||||
not isInsecureTlsVersion(version, _, fld.getName())
|
||||
)
|
||||
}
|
||||
@@ -96,17 +93,17 @@ predicate secureTlsVersionFlow(
|
||||
/**
|
||||
* Holds if a secure TLS version reaches `sink`, which flows into `fld`.
|
||||
*/
|
||||
predicate secureTlsVersionFlowsToSink(DataFlow::PathNode sink, Field fld) {
|
||||
secureTlsVersionFlow(_, _, sink, fld)
|
||||
predicate secureTlsVersionFlowsToSink(DataFlow::Node sink, Field fld) {
|
||||
secureTlsVersionFlow(_, sink, fld)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a secure TLS version may reach `accessPath`.`fld`
|
||||
*/
|
||||
predicate secureTlsVersionFlowsToField(SsaWithFields accessPath, Field fld) {
|
||||
exists(TlsVersionFlowConfig config, DataFlow::PathNode sink, DataFlow::Node base |
|
||||
secureTlsVersionFlow(config, _, sink, fld) and
|
||||
config.isSink(sink.getNode(), fld, base, _) and
|
||||
exists(DataFlow::Node sink, DataFlow::Node base |
|
||||
secureTlsVersionFlow(_, sink, fld) and
|
||||
TlsVersionFlowConfig::isSink(sink, fld, base, _) and
|
||||
accessPath.getAUse() = base
|
||||
)
|
||||
}
|
||||
@@ -124,17 +121,18 @@ DataFlow::Node nodeOrDeref(DataFlow::Node node) {
|
||||
* to a field of `base`. `message` describes the specific problem found.
|
||||
*/
|
||||
predicate isInsecureTlsVersionFlow(
|
||||
DataFlow::PathNode source, DataFlow::PathNode sink, string message, DataFlow::Node base
|
||||
TlsVersionFlow::PathNode source, TlsVersionFlow::PathNode sink, string message,
|
||||
DataFlow::Node base
|
||||
) {
|
||||
exists(TlsVersionFlowConfig cfg, int version, Field fld |
|
||||
cfg.hasFlowPath(source, sink) and
|
||||
cfg.intIsSource(source.getNode(), version) and
|
||||
cfg.isSink(sink.getNode(), fld, base, _) and
|
||||
exists(int version, Field fld |
|
||||
TlsVersionFlow::flowPath(source, sink) and
|
||||
TlsVersionFlowConfig::intIsSource(source.getNode(), version) and
|
||||
TlsVersionFlowConfig::isSink(sink.getNode(), fld, base, _) and
|
||||
isInsecureTlsVersion(version, _, fld.getName()) and
|
||||
// Exclude cases where a secure TLS version can also flow to the same
|
||||
// sink, or to different sinks that refer to the same base and field,
|
||||
// which suggests a configurable security mode.
|
||||
not secureTlsVersionFlowsToSink(sink, fld) and
|
||||
not secureTlsVersionFlowsToSink(sink.getNode(), fld) and
|
||||
not exists(SsaWithFields insecureAccessPath, SsaWithFields secureAccessPath |
|
||||
nodeOrDeref(insecureAccessPath.getAUse()) = base and
|
||||
secureAccessPath = insecureAccessPath.similar()
|
||||
@@ -152,17 +150,11 @@ predicate isInsecureTlsVersionFlow(
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for tracking flow from insecure TLS cipher
|
||||
* suites into a `tls.Config` struct, to the `CipherSuites` field.
|
||||
*/
|
||||
class TlsInsecureCipherSuitesFlowConfig extends TaintTracking::Configuration {
|
||||
TlsInsecureCipherSuitesFlowConfig() { this = "TlsInsecureCipherSuitesFlowConfig" }
|
||||
|
||||
module TlsInsecureCipherSuitesFlowConfig implements DataFlow::ConfigSig {
|
||||
/**
|
||||
* Holds if `source` reads an insecure TLS cipher suite named `suiteName`.
|
||||
*/
|
||||
predicate isSourceValueEntity(DataFlow::Node source, string suiteName) {
|
||||
additional predicate isSourceValueEntity(DataFlow::Node source, string suiteName) {
|
||||
exists(DataFlow::ValueEntity val |
|
||||
val.hasQualifiedName("crypto/tls", suiteName) and
|
||||
suiteName =
|
||||
@@ -179,7 +171,7 @@ class TlsInsecureCipherSuitesFlowConfig extends TaintTracking::Configuration {
|
||||
/**
|
||||
* Holds if `source` represents the result of `tls.InsecureCipherSuites()`.
|
||||
*/
|
||||
predicate isSourceInsecureCipherSuites(DataFlow::Node source) {
|
||||
additional predicate isSourceInsecureCipherSuites(DataFlow::Node source) {
|
||||
exists(Function insecureCipherSuites |
|
||||
insecureCipherSuites.hasQualifiedName("crypto/tls", "InsecureCipherSuites")
|
||||
|
|
||||
@@ -187,44 +179,54 @@ class TlsInsecureCipherSuitesFlowConfig extends TaintTracking::Configuration {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
this.isSourceInsecureCipherSuites(source)
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
isSourceInsecureCipherSuites(source)
|
||||
or
|
||||
this.isSourceValueEntity(source, _)
|
||||
isSourceValueEntity(source, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `fieldWrite` writes `sink` to `base`.`fld`, and `fld` is `tls.Config.CipherSuites`.
|
||||
*/
|
||||
predicate isSink(DataFlow::Node sink, Field fld, DataFlow::Node base, Write fieldWrite) {
|
||||
additional predicate isSink(DataFlow::Node sink, Field fld, DataFlow::Node base, Write fieldWrite) {
|
||||
fld.hasQualifiedName("crypto/tls", "Config", "CipherSuites") and
|
||||
fieldWrite.writesField(base, fld, sink)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { this.isSink(sink, _, _, _) }
|
||||
predicate isSink(DataFlow::Node sink) { isSink(sink, _, _, _) }
|
||||
|
||||
/**
|
||||
* Declare sinks as out-sanitizers in order to avoid producing superfluous paths where a cipher
|
||||
* is written to CipherSuites, then the list is further extended with either safe or tainted
|
||||
* suites.
|
||||
*/
|
||||
override predicate isSanitizerOut(DataFlow::Node node) {
|
||||
super.isSanitizerOut(node) or this.isSink(node)
|
||||
}
|
||||
predicate isBarrierOut(DataFlow::Node node) { isSink(node) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks taint flow from insecure TLS cipher suites into the `CipherSuites`
|
||||
* field of a `tls.Config` struct.
|
||||
*/
|
||||
module TlsInsecureCipherSuitesFlow = TaintTracking::Global<TlsInsecureCipherSuitesFlowConfig>;
|
||||
|
||||
/**
|
||||
* Holds if an insecure TLS cipher suite flows from `source` to `sink`, where `sink`
|
||||
* is written to the CipherSuites list of a `tls.Config` instance. `message` describes
|
||||
* the exact problem found.
|
||||
*/
|
||||
predicate isInsecureTlsCipherFlow(DataFlow::PathNode source, DataFlow::PathNode sink, string message) {
|
||||
exists(TlsInsecureCipherSuitesFlowConfig cfg | cfg.hasFlowPath(source, sink) |
|
||||
exists(string name | cfg.isSourceValueEntity(source.getNode(), name) |
|
||||
predicate isInsecureTlsCipherFlow(
|
||||
TlsInsecureCipherSuitesFlow::PathNode source, TlsInsecureCipherSuitesFlow::PathNode sink,
|
||||
string message
|
||||
) {
|
||||
TlsInsecureCipherSuitesFlow::flowPath(source, sink) and
|
||||
(
|
||||
exists(string name |
|
||||
TlsInsecureCipherSuitesFlowConfig::isSourceValueEntity(source.getNode(), name)
|
||||
|
|
||||
message = "Use of an insecure cipher suite: " + name + "."
|
||||
)
|
||||
or
|
||||
cfg.isSourceInsecureCipherSuites(source.getNode()) and
|
||||
TlsInsecureCipherSuitesFlowConfig::isSourceInsecureCipherSuites(source.getNode()) and
|
||||
message = "Use of an insecure cipher suite."
|
||||
)
|
||||
}
|
||||
@@ -260,11 +262,17 @@ FlagKind securityOrTlsVersionFlag() {
|
||||
result = any(LegacyTlsVersionFlag f)
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, string message
|
||||
module Flow =
|
||||
DataFlow::MergePathGraph<TlsVersionFlow::PathNode, TlsInsecureCipherSuitesFlow::PathNode,
|
||||
TlsVersionFlow::PathGraph, TlsInsecureCipherSuitesFlow::PathGraph>;
|
||||
|
||||
import Flow::PathGraph
|
||||
|
||||
from Flow::PathNode source, Flow::PathNode sink, string message
|
||||
where
|
||||
(
|
||||
isInsecureTlsVersionFlow(source, sink, message, _) or
|
||||
isInsecureTlsCipherFlow(source, sink, message)
|
||||
isInsecureTlsVersionFlow(source.asPathNode1(), sink.asPathNode1(), message, _) or
|
||||
isInsecureTlsCipherFlow(source.asPathNode2(), sink.asPathNode2(), message)
|
||||
) and
|
||||
// Exclude sources or sinks guarded by a feature or legacy flag
|
||||
not [getASecurityFeatureFlagCheck(), getALegacyTlsVersionCheck()]
|
||||
|
||||
@@ -11,19 +11,19 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
import semmle.go.security.InsecureRandomness::InsecureRandomness
|
||||
import DataFlow::PathGraph
|
||||
import semmle.go.security.InsecureRandomness
|
||||
import InsecureRandomness::Flow::PathGraph
|
||||
|
||||
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, string kind
|
||||
from InsecureRandomness::Flow::PathNode source, InsecureRandomness::Flow::PathNode sink, string kind
|
||||
where
|
||||
cfg.hasFlowPath(source, sink) and
|
||||
cfg.isSinkWithKind(sink.getNode(), kind) and
|
||||
InsecureRandomness::Flow::flowPath(source, sink) and
|
||||
InsecureRandomness::isSinkWithKind(sink.getNode(), kind) and
|
||||
(
|
||||
kind != "A password-related function"
|
||||
or
|
||||
sink =
|
||||
min(DataFlow::PathNode sink2, int line |
|
||||
cfg.hasFlowPath(_, sink2) and
|
||||
min(InsecureRandomness::Flow::PathNode sink2, int line |
|
||||
InsecureRandomness::Flow::flowPath(_, sink2) and
|
||||
sink2.getNode().getRoot() = sink.getNode().getRoot() and
|
||||
sink2.hasLocationInfo(_, line, _, _, _)
|
||||
|
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
import DataFlow::PathGraph
|
||||
|
||||
/**
|
||||
* A method that creates a new URL that will send the user
|
||||
@@ -24,18 +23,12 @@ class AuthCodeUrl extends Method {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A flow of a constant string value to a call to `AuthCodeURL` as the
|
||||
* `state` parameter.
|
||||
*/
|
||||
class ConstantStateFlowConf extends DataFlow::Configuration {
|
||||
ConstantStateFlowConf() { this = "ConstantStateFlowConf" }
|
||||
|
||||
predicate isSinkCall(DataFlow::Node sink, DataFlow::CallNode call) {
|
||||
module ConstantStateFlowConfig implements DataFlow::ConfigSig {
|
||||
additional predicate isSinkCall(DataFlow::Node sink, DataFlow::CallNode call) {
|
||||
exists(AuthCodeUrl m | call = m.getACall() | sink = call.getArgument(0))
|
||||
}
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source.isConst() and
|
||||
not DataFlow::isReturnedWithError(source) and
|
||||
// Avoid duplicate paths by not considering reads from constants as sources themselves:
|
||||
@@ -46,9 +39,17 @@ class ConstantStateFlowConf extends DataFlow::Configuration {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { this.isSinkCall(sink, _) }
|
||||
predicate isSink(DataFlow::Node sink) { isSinkCall(sink, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks data flow of a constant string value to a call to `AuthCodeURL` as
|
||||
* the `state` parameter.
|
||||
*/
|
||||
module Flow = DataFlow::Global<ConstantStateFlowConfig>;
|
||||
|
||||
import Flow::PathGraph
|
||||
|
||||
/**
|
||||
* Holds if `pred` writes a URL to the `RedirectURL` field of the `succ` `Config` object.
|
||||
*
|
||||
@@ -77,17 +78,8 @@ string getAnOobOauth2Url() {
|
||||
result.matches("%://127.0.0.1%")
|
||||
}
|
||||
|
||||
/**
|
||||
* A flow of a URL indicating the OAuth redirect doesn't point to a publicly
|
||||
* accessible address, to the receiver of an `AuthCodeURL` call.
|
||||
*
|
||||
* Note we accept localhost and 127.0.0.1 on the assumption this is probably a transient
|
||||
* listener; if it actually is a persistent server then that really is vulnerable to CSRF.
|
||||
*/
|
||||
class PrivateUrlFlowsToAuthCodeUrlCall extends DataFlow::Configuration {
|
||||
PrivateUrlFlowsToAuthCodeUrlCall() { this = "PrivateUrlFlowsToConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
module PrivateUrlFlowsToAuthCodeUrlCallConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source.getStringValue() = getAnOobOauth2Url() and
|
||||
// Avoid duplicate paths by excluding constant variable references from
|
||||
// themselves being sources:
|
||||
@@ -98,7 +90,7 @@ class PrivateUrlFlowsToAuthCodeUrlCall extends DataFlow::Configuration {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
// Propagate from a RedirectURL field to a whole Config
|
||||
isUrlTaintingConfigStep(pred, succ)
|
||||
or
|
||||
@@ -113,13 +105,23 @@ class PrivateUrlFlowsToAuthCodeUrlCall extends DataFlow::Configuration {
|
||||
)
|
||||
}
|
||||
|
||||
predicate isSinkCall(DataFlow::Node sink, DataFlow::CallNode call) {
|
||||
additional predicate isSinkCall(DataFlow::Node sink, DataFlow::CallNode call) {
|
||||
exists(AuthCodeUrl m | call = m.getACall() | sink = call.getReceiver())
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { this.isSinkCall(sink, _) }
|
||||
predicate isSink(DataFlow::Node sink) { isSinkCall(sink, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks data flow from a URL indicating the OAuth redirect doesn't point to a publicly
|
||||
* accessible address to the receiver of an `AuthCodeURL` call.
|
||||
*
|
||||
* Note we accept localhost and 127.0.0.1 on the assumption this is probably a transient
|
||||
* listener; if it actually is a persistent server then that really is vulnerable to CSRF.
|
||||
*/
|
||||
module PrivateUrlFlowsToAuthCodeUrlCallFlow =
|
||||
DataFlow::Global<PrivateUrlFlowsToAuthCodeUrlCallConfig>;
|
||||
|
||||
/**
|
||||
* Holds if a URL indicating the OAuth redirect doesn't point to a publicly
|
||||
* accessible address, to the receiver of an `AuthCodeURL` call.
|
||||
@@ -128,33 +130,27 @@ class PrivateUrlFlowsToAuthCodeUrlCall extends DataFlow::Configuration {
|
||||
* listener; if it actually is a persistent server then that really is vulnerable to CSRF.
|
||||
*/
|
||||
predicate privateUrlFlowsToAuthCodeUrlCall(DataFlow::CallNode call) {
|
||||
exists(PrivateUrlFlowsToAuthCodeUrlCall flowConfig, DataFlow::Node receiver |
|
||||
flowConfig.hasFlowTo(receiver) and
|
||||
flowConfig.isSinkCall(receiver, call)
|
||||
exists(DataFlow::Node receiver |
|
||||
PrivateUrlFlowsToAuthCodeUrlCallFlow::flowTo(receiver) and
|
||||
PrivateUrlFlowsToAuthCodeUrlCallConfig::isSinkCall(receiver, call)
|
||||
)
|
||||
}
|
||||
|
||||
/** A flow from `golang.org/x/oauth2.Config.AuthCodeUrl`'s result to a logging function. */
|
||||
class FlowToPrint extends DataFlow::Configuration {
|
||||
FlowToPrint() { this = "FlowToPrint" }
|
||||
|
||||
predicate isSinkCall(DataFlow::Node sink, DataFlow::CallNode call) {
|
||||
module FlowToPrintConfig implements DataFlow::ConfigSig {
|
||||
additional predicate isSinkCall(DataFlow::Node sink, DataFlow::CallNode call) {
|
||||
exists(LoggerCall logCall | call = logCall | sink = logCall.getAMessageComponent())
|
||||
}
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source = any(AuthCodeUrl m).getACall().getResult()
|
||||
}
|
||||
predicate isSource(DataFlow::Node source) { source = any(AuthCodeUrl m).getACall().getResult() }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { this.isSinkCall(sink, _) }
|
||||
predicate isSink(DataFlow::Node sink) { isSinkCall(sink, _) }
|
||||
}
|
||||
|
||||
module FlowToPrintFlow = DataFlow::Global<FlowToPrintConfig>;
|
||||
|
||||
/** Holds if the provided `CallNode`'s result flows to an argument of a printer call. */
|
||||
predicate resultFlowsToPrinter(DataFlow::CallNode authCodeUrlCall) {
|
||||
exists(FlowToPrint cfg, DataFlow::PathNode source |
|
||||
cfg.hasFlowPath(source, _) and
|
||||
authCodeUrlCall.getResult() = source.getNode()
|
||||
)
|
||||
FlowToPrintFlow::flow(authCodeUrlCall.getResult(), _)
|
||||
}
|
||||
|
||||
/** Get a data-flow node that reads the value of `os.Stdin`. */
|
||||
@@ -197,12 +193,10 @@ predicate seemsLikeDoneWithinATerminal(DataFlow::CallNode authCodeUrlCall) {
|
||||
containsCallToStdinScanner(authCodeUrlCall.getRoot())
|
||||
}
|
||||
|
||||
from
|
||||
ConstantStateFlowConf cfg, DataFlow::PathNode source, DataFlow::PathNode sink,
|
||||
DataFlow::CallNode sinkCall
|
||||
from Flow::PathNode source, Flow::PathNode sink, DataFlow::CallNode sinkCall
|
||||
where
|
||||
cfg.hasFlowPath(source, sink) and
|
||||
cfg.isSinkCall(sink.getNode(), sinkCall) and
|
||||
Flow::flowPath(source, sink) and
|
||||
ConstantStateFlowConfig::isSinkCall(sink.getNode(), sinkCall) and
|
||||
// Exclude cases that seem to be oauth flows done from within a terminal:
|
||||
not seemsLikeDoneWithinATerminal(sinkCall) and
|
||||
not privateUrlFlowsToAuthCodeUrlCall(sinkCall)
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
|
||||
import go
|
||||
import semmle.go.security.OpenUrlRedirectCustomizations
|
||||
import DataFlow::PathGraph
|
||||
|
||||
StringOps::HasPrefix checkForLeadingSlash(SsaWithFields v) {
|
||||
exists(DataFlow::Node substr |
|
||||
@@ -91,16 +90,14 @@ predicate urlPath(DataFlow::Node nd) {
|
||||
)
|
||||
}
|
||||
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "BadRedirectCheck" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { this.isCheckedSource(source, _) }
|
||||
module Config implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { isCheckedSource(source, _) }
|
||||
|
||||
/**
|
||||
* Holds if `source` is the first node that flows into a use of a variable that is checked by a
|
||||
* bad redirect check `check`..
|
||||
*/
|
||||
predicate isCheckedSource(DataFlow::Node source, DataFlow::Node check) {
|
||||
additional predicate isCheckedSource(DataFlow::Node source, DataFlow::Node check) {
|
||||
exists(SsaWithFields v |
|
||||
DataFlow::localFlow(source, v.getAUse()) and
|
||||
not exists(source.getAPredecessor()) and
|
||||
@@ -108,12 +105,12 @@ class Configuration extends TaintTracking::Configuration {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
// this is very over-approximate, because most filtering is done by the isSource predicate
|
||||
exists(Write w | w.writesField(succ, _, pred))
|
||||
exists(Write w | w.writesField(node2, _, node1))
|
||||
}
|
||||
|
||||
override predicate isSanitizerOut(DataFlow::Node node) {
|
||||
predicate isBarrierOut(DataFlow::Node node) {
|
||||
// assume this value is safe if something is prepended to it.
|
||||
exists(StringOps::Concatenation conc, int i, int j | i < j |
|
||||
node = conc.getOperand(j) and
|
||||
@@ -125,9 +122,11 @@ class Configuration extends TaintTracking::Configuration {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof OpenUrlRedirect::Sink }
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof OpenUrlRedirect::Sink }
|
||||
}
|
||||
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
|
||||
/**
|
||||
* Holds there is a check `check` that is a bad redirect check, and `v` is either
|
||||
* checked directly by `check` or checked by a function that contains `check`.
|
||||
@@ -168,10 +167,12 @@ predicate isBadRedirectCheckWrapper(DataFlow::Node check, FuncDef f, FunctionInp
|
||||
)
|
||||
}
|
||||
|
||||
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, DataFlow::Node check
|
||||
import Flow::PathGraph
|
||||
|
||||
from Flow::PathNode source, Flow::PathNode sink, DataFlow::Node check
|
||||
where
|
||||
cfg.isCheckedSource(source.getNode(), check) and
|
||||
cfg.hasFlowPath(source, sink)
|
||||
Config::isCheckedSource(source.getNode(), check) and
|
||||
Flow::flowPath(source, sink)
|
||||
select check, source, sink,
|
||||
"This is a check that $@, which flows into a $@, has a leading slash, but not that it does not have '/' or '\\' in its second position.",
|
||||
source.getNode(), "this value", sink.getNode(), "redirect"
|
||||
|
||||
@@ -12,17 +12,15 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
import semmle.go.security.OpenUrlRedirect::OpenUrlRedirect
|
||||
import semmle.go.security.OpenUrlRedirect
|
||||
import semmle.go.security.SafeUrlFlow
|
||||
import DataFlow::PathGraph
|
||||
import OpenUrlRedirect::Flow::PathGraph
|
||||
|
||||
from
|
||||
Configuration cfg, SafeUrlFlow::Configuration scfg, DataFlow::PathNode source,
|
||||
DataFlow::PathNode sink
|
||||
from OpenUrlRedirect::Flow::PathNode source, OpenUrlRedirect::Flow::PathNode sink
|
||||
where
|
||||
cfg.hasFlowPath(source, sink) and
|
||||
OpenUrlRedirect::Flow::flowPath(source, sink) and
|
||||
// this excludes flow from safe parts of request URLs, for example the full URL when the
|
||||
// doing a redirect from `http://<path>` to `https://<path>`
|
||||
not scfg.hasFlow(_, sink.getNode())
|
||||
not SafeUrlFlow::Flow::flow(_, sink.getNode())
|
||||
select sink.getNode(), source, sink, "This path to an untrusted URL redirection depends on a $@.",
|
||||
source.getNode(), "user-provided value"
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
import DataFlow::PathGraph
|
||||
import EmailInjection::EmailInjection
|
||||
import Flow::PathGraph
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, Configuration config
|
||||
where config.hasFlowPath(source, sink)
|
||||
from Flow::PathNode source, Flow::PathNode sink
|
||||
where Flow::flowPath(source, sink)
|
||||
select sink, source, sink, "Email content may contain $@.", source.getNode(), "untrusted input"
|
||||
|
||||
@@ -17,13 +17,24 @@ module EmailInjection {
|
||||
import EmailInjectionCustomizations::EmailInjection
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Flow` instead.
|
||||
*
|
||||
* A taint-tracking configuration for reasoning about email-injection vulnerabilities.
|
||||
*/
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
deprecated class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "Email Injection" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||
}
|
||||
|
||||
private module Config implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||
}
|
||||
|
||||
/** Tracks taint flow for reasoning about email-injection vulnerabilities. */
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
}
|
||||
|
||||
@@ -12,17 +12,17 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
import semmle.go.security.XPathInjection::XPathInjection
|
||||
import DataFlow::PathGraph
|
||||
import semmle.go.security.XPathInjection
|
||||
import XPathInjection::Flow::PathGraph
|
||||
|
||||
/** Holds if `node` is either a string or a byte slice */
|
||||
predicate isStringOrByte(DataFlow::PathNode node) {
|
||||
predicate isStringOrByte(XPathInjection::Flow::PathNode node) {
|
||||
exists(Type t | t = node.getNode().getType().getUnderlyingType() |
|
||||
t instanceof StringType or t instanceof ByteSliceType
|
||||
)
|
||||
}
|
||||
|
||||
from Configuration config, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where config.hasFlowPath(source, sink) and isStringOrByte(sink)
|
||||
from XPathInjection::Flow::PathNode source, XPathInjection::Flow::PathNode sink
|
||||
where XPathInjection::Flow::flowPath(source, sink) and isStringOrByte(sink)
|
||||
select sink.getNode(), source, sink, "XPath expression depends on a $@.", source.getNode(),
|
||||
"user-provided value"
|
||||
|
||||
@@ -14,18 +14,17 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
import DataFlow::PathGraph
|
||||
import semmle.go.security.IncorrectIntegerConversionLib
|
||||
import Flow::PathGraph
|
||||
|
||||
from
|
||||
DataFlow::PathNode source, DataFlow::PathNode sink, ConversionWithoutBoundsCheckConfig cfg,
|
||||
DataFlow::CallNode call, DataFlow::Node sinkConverted
|
||||
Flow::PathNode source, Flow::PathNode sink, DataFlow::CallNode call, DataFlow::Node sinkConverted
|
||||
where
|
||||
cfg.hasFlowPath(source, sink) and
|
||||
Flow::flowPath(source, sink) and
|
||||
call.getResult(0) = source.getNode() and
|
||||
sinkConverted = sink.getNode().getASuccessor()
|
||||
select sinkConverted, source, sink,
|
||||
"Incorrect conversion of " +
|
||||
describeBitSize(cfg.getSourceBitSize(), getIntTypeBitSize(source.getNode().getFile())) +
|
||||
" from $@ to a lower bit size type " + sinkConverted.getType().getUnderlyingType().getName() +
|
||||
describeBitSize(getSourceBitSize(sink.getState()), getIntTypeBitSize(source.getNode().getFile()))
|
||||
+ " from $@ to a lower bit size type " + sinkConverted.getType().getUnderlyingType().getName() +
|
||||
" without an upper bound check.", source, call.getTarget().getQualifiedName()
|
||||
|
||||
@@ -11,17 +11,16 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
import semmle.go.security.RequestForgery::RequestForgery
|
||||
import semmle.go.security.RequestForgery
|
||||
import semmle.go.security.SafeUrlFlow
|
||||
import DataFlow::PathGraph
|
||||
import RequestForgery::Flow::PathGraph
|
||||
|
||||
from
|
||||
Configuration cfg, SafeUrlFlow::Configuration scfg, DataFlow::PathNode source,
|
||||
DataFlow::PathNode sink, DataFlow::Node request
|
||||
RequestForgery::Flow::PathNode source, RequestForgery::Flow::PathNode sink, DataFlow::Node request
|
||||
where
|
||||
cfg.hasFlowPath(source, sink) and
|
||||
request = sink.getNode().(Sink).getARequest() and
|
||||
RequestForgery::Flow::flowPath(source, sink) and
|
||||
request = sink.getNode().(RequestForgery::Sink).getARequest() and
|
||||
// this excludes flow from safe parts of request URLs, for example the full URL
|
||||
not scfg.hasFlow(_, sink.getNode())
|
||||
not SafeUrlFlow::Flow::flow(_, sink.getNode())
|
||||
select request, source, sink, "The $@ of this request depends on a $@.", sink.getNode(),
|
||||
sink.getNode().(Sink).getKind(), source, "user-provided value"
|
||||
sink.getNode().(RequestForgery::Sink).getKind(), source, "user-provided value"
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
|
||||
import go
|
||||
import LDAPInjection
|
||||
import DataFlow::PathGraph
|
||||
import LdapInjectionFlow::PathGraph
|
||||
|
||||
from LdapInjectionConfiguration config, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where config.hasFlowPath(source, sink)
|
||||
from LdapInjectionFlow::PathNode source, LdapInjectionFlow::PathNode sink
|
||||
where LdapInjectionFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "LDAP query parameter depends on a $@.", source.getNode(),
|
||||
"user-provided value"
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import go
|
||||
import DataFlow::PathGraph
|
||||
|
||||
/**
|
||||
* A sanitizer function that prevents LDAP injection attacks.
|
||||
@@ -97,10 +96,12 @@ private class LdapClientDNSink extends LdapSink {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `LdapInjectionFlow` instead.
|
||||
*
|
||||
* A taint-tracking configuration for reasoning about when an `UntrustedFlowSource`
|
||||
* flows into an argument or field that is vulnerable to LDAP injection.
|
||||
*/
|
||||
class LdapInjectionConfiguration extends TaintTracking::Configuration {
|
||||
deprecated class LdapInjectionConfiguration extends TaintTracking::Configuration {
|
||||
LdapInjectionConfiguration() { this = "Ldap injection" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource }
|
||||
@@ -109,3 +110,17 @@ class LdapInjectionConfiguration extends TaintTracking::Configuration {
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node sanitizer) { sanitizer instanceof LdapSanitizer }
|
||||
}
|
||||
|
||||
private module LdapInjectionConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof LdapSink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) { node instanceof LdapSanitizer }
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks taint flow for reasoning about when an `UntrustedFlowSource` flows
|
||||
* into an argument or field that is vulnerable to LDAP injection.
|
||||
*/
|
||||
module LdapInjectionFlow = TaintTracking::Global<LdapInjectionConfig>;
|
||||
|
||||
@@ -65,10 +65,12 @@ private class SetCookieSink extends DataFlow::Node {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `NameToNetHttpCookieTrackingFlow` instead.
|
||||
*
|
||||
* A taint-tracking configuration for tracking flow from sensitive names to
|
||||
* `net/http.SetCookie`.
|
||||
*/
|
||||
class NameToNetHttpCookieTrackingConfiguration extends TaintTracking::Configuration {
|
||||
deprecated class NameToNetHttpCookieTrackingConfiguration extends TaintTracking::Configuration {
|
||||
NameToNetHttpCookieTrackingConfiguration() { this = "NameToNetHttpCookieTrackingConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { isAuthVariable(source.asExpr()) }
|
||||
@@ -84,11 +86,30 @@ class NameToNetHttpCookieTrackingConfiguration extends TaintTracking::Configurat
|
||||
}
|
||||
}
|
||||
|
||||
private module NameToNetHttpCookieTrackingConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { isAuthVariable(source.asExpr()) }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof SetCookieSink }
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(StructLit sl |
|
||||
sl.getType() instanceof NetHttpCookieType and
|
||||
getValueForFieldWrite(sl, "Name") = pred and
|
||||
sl = succ.asExpr()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Tracks taint flow from sensitive names to `net/http.SetCookie`. */
|
||||
module NameToNetHttpCookieTrackingFlow = TaintTracking::Global<NameToNetHttpCookieTrackingConfig>;
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `BoolToNetHttpCookieTrackingFlow` instead.
|
||||
*
|
||||
* A taint-tracking configuration for tracking flow from `bool` assigned to
|
||||
* `HttpOnly` that flows into `net/http.SetCookie`.
|
||||
*/
|
||||
class BoolToNetHttpCookieTrackingConfiguration extends TaintTracking::Configuration {
|
||||
deprecated class BoolToNetHttpCookieTrackingConfiguration extends TaintTracking::Configuration {
|
||||
BoolToNetHttpCookieTrackingConfiguration() { this = "BoolToNetHttpCookieTrackingConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
@@ -106,11 +127,35 @@ class BoolToNetHttpCookieTrackingConfiguration extends TaintTracking::Configurat
|
||||
}
|
||||
}
|
||||
|
||||
private module BoolToNetHttpCookieTrackingConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source.getType().getUnderlyingType() instanceof BoolType
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof SetCookieSink }
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(StructLit sl |
|
||||
sl.getType() instanceof NetHttpCookieType and
|
||||
getValueForFieldWrite(sl, "HttpOnly") = pred and
|
||||
sl = succ.asExpr()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks taint flow from a `bool` assigned to `HttpOnly` to
|
||||
* `net/http.SetCookie`.
|
||||
*/
|
||||
module BoolToNetHttpCookieTrackingFlow = TaintTracking::Global<BoolToNetHttpCookieTrackingConfig>;
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `BoolToGinSetCookieTrackingFlow` instead.
|
||||
*
|
||||
* A taint-tracking configuration for tracking flow from `HttpOnly` set to
|
||||
* `false` to `gin-gonic/gin.Context.SetCookie`.
|
||||
*/
|
||||
class BoolToGinSetCookieTrackingConfiguration extends DataFlow::Configuration {
|
||||
deprecated class BoolToGinSetCookieTrackingConfiguration extends DataFlow::Configuration {
|
||||
BoolToGinSetCookieTrackingConfiguration() { this = "BoolToGinSetCookieTrackingConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source.getBoolValue() = false }
|
||||
@@ -127,11 +172,34 @@ class BoolToGinSetCookieTrackingConfiguration extends DataFlow::Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
private module BoolToGinSetCookieTrackingConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source.getBoolValue() = false }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(DataFlow::MethodCallNode mcn |
|
||||
mcn.getTarget() instanceof GinContextSetCookieMethod and
|
||||
mcn.getArgument(6) = sink and
|
||||
exists(DataFlow::Node nameArg |
|
||||
NameToGinSetCookieTrackingFlow::flowTo(nameArg) and
|
||||
mcn.getArgument(0) = nameArg
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks data flow from `HttpOnly` set to `false` to
|
||||
* `gin-gonic/gin.Context.SetCookie`.
|
||||
*/
|
||||
module BoolToGinSetCookieTrackingFlow = DataFlow::Global<BoolToGinSetCookieTrackingConfig>;
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `NameToGinSetCookieTrackingFlow` instead.
|
||||
*
|
||||
* A taint-tracking configuration for tracking flow from sensitive names to
|
||||
* `gin-gonic/gin.Context.SetCookie`.
|
||||
*/
|
||||
private class NameToGinSetCookieTrackingConfiguration extends DataFlow2::Configuration {
|
||||
deprecated private class NameToGinSetCookieTrackingConfiguration extends DataFlow2::Configuration {
|
||||
NameToGinSetCookieTrackingConfiguration() { this = "NameToGinSetCookieTrackingConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { isAuthVariable(source.asExpr()) }
|
||||
@@ -144,6 +212,22 @@ private class NameToGinSetCookieTrackingConfiguration extends DataFlow2::Configu
|
||||
}
|
||||
}
|
||||
|
||||
private module NameToGinSetCookieTrackingConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { isAuthVariable(source.asExpr()) }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(DataFlow::MethodCallNode mcn |
|
||||
mcn.getTarget() instanceof GinContextSetCookieMethod and
|
||||
mcn.getArgument(0) = sink
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks taint flow from sensitive names to `gin-gonic/gin.Context.SetCookie`.
|
||||
*/
|
||||
private module NameToGinSetCookieTrackingFlow = DataFlow::Global<NameToGinSetCookieTrackingConfig>;
|
||||
|
||||
/**
|
||||
* The receiver of `gorilla/sessions.Session.Save` call.
|
||||
*/
|
||||
@@ -168,10 +252,12 @@ private class GorillaStoreSaveSink extends DataFlow::Node {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `GorillaCookieStoreSaveTrackingFlow` instead.
|
||||
*
|
||||
* A taint-tracking configuration for tracking flow from gorilla cookie store
|
||||
* creation to `gorilla/sessions.Session.Save`.
|
||||
*/
|
||||
class GorillaCookieStoreSaveTrackingConfiguration extends DataFlow::Configuration {
|
||||
deprecated class GorillaCookieStoreSaveTrackingConfiguration extends DataFlow::Configuration {
|
||||
GorillaCookieStoreSaveTrackingConfiguration() {
|
||||
this = "GorillaCookieStoreSaveTrackingConfiguration"
|
||||
}
|
||||
@@ -198,11 +284,42 @@ class GorillaCookieStoreSaveTrackingConfiguration extends DataFlow::Configuratio
|
||||
}
|
||||
}
|
||||
|
||||
private module GorillaCookieStoreSaveTrackingConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source
|
||||
.(DataFlow::CallNode)
|
||||
.getTarget()
|
||||
.hasQualifiedName(package("github.com/gorilla/sessions", ""), "NewCookieStore")
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink instanceof GorillaSessionSaveSink or
|
||||
sink instanceof GorillaStoreSaveSink
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(DataFlow::MethodCallNode cn |
|
||||
cn.getTarget()
|
||||
.hasQualifiedName(package("github.com/gorilla/sessions", ""), "CookieStore", "Get") and
|
||||
pred = cn.getReceiver() and
|
||||
succ = cn.getResult(0)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks data flow from gorilla cookie store creation to
|
||||
* `gorilla/sessions.Session.Save`.
|
||||
*/
|
||||
module GorillaCookieStoreSaveTrackingFlow = DataFlow::Global<GorillaCookieStoreSaveTrackingConfig>;
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `GorillaSessionOptionsTrackingFlow` instead.
|
||||
*
|
||||
* A taint-tracking configuration for tracking flow from session options to
|
||||
* `gorilla/sessions.Session.Save`.
|
||||
*/
|
||||
class GorillaSessionOptionsTrackingConfiguration extends TaintTracking::Configuration {
|
||||
deprecated class GorillaSessionOptionsTrackingConfiguration extends TaintTracking::Configuration {
|
||||
GorillaSessionOptionsTrackingConfiguration() {
|
||||
this = "GorillaSessionOptionsTrackingConfiguration"
|
||||
}
|
||||
@@ -224,11 +341,39 @@ class GorillaSessionOptionsTrackingConfiguration extends TaintTracking::Configur
|
||||
}
|
||||
}
|
||||
|
||||
private module GorillaSessionOptionsTrackingConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
exists(StructLit sl |
|
||||
sl.getType().hasQualifiedName(package("github.com/gorilla/sessions", ""), "Options") and
|
||||
source.asExpr() = sl
|
||||
)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof GorillaSessionSaveSink }
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(GorillaSessionOptionsField f, DataFlow::Write w, DataFlow::Node base |
|
||||
w.writesField(base, f, pred) and
|
||||
succ = base
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks taint flow from session options to
|
||||
* `gorilla/sessions.Session.Save`.
|
||||
*/
|
||||
module GorillaSessionOptionsTrackingFlow =
|
||||
TaintTracking::Global<GorillaSessionOptionsTrackingConfig>;
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `BoolToGorillaSessionOptionsTrackingFlow` instead.
|
||||
*
|
||||
* A taint-tracking configuration for tracking flow from a `bool` assigned to
|
||||
* `HttpOnly` to `gorilla/sessions.Session.Save`.
|
||||
*/
|
||||
class BoolToGorillaSessionOptionsTrackingConfiguration extends TaintTracking::Configuration {
|
||||
deprecated class BoolToGorillaSessionOptionsTrackingConfiguration extends TaintTracking::Configuration
|
||||
{
|
||||
BoolToGorillaSessionOptionsTrackingConfiguration() {
|
||||
this = "BoolToGorillaSessionOptionsTrackingConfiguration"
|
||||
}
|
||||
@@ -251,3 +396,30 @@ class BoolToGorillaSessionOptionsTrackingConfiguration extends TaintTracking::Co
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private module BoolToGorillaSessionOptionsTrackingConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source.getType().getUnderlyingType() instanceof BoolType
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof GorillaSessionSaveSink }
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(StructLit sl |
|
||||
getValueForFieldWrite(sl, "HttpOnly") = pred and
|
||||
sl = succ.asExpr()
|
||||
)
|
||||
or
|
||||
exists(GorillaSessionOptionsField f, DataFlow::Write w, DataFlow::Node base |
|
||||
w.writesField(base, f, pred) and
|
||||
succ = base
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks taint flow from a `bool` assigned to `HttpOnly` to
|
||||
* `gorilla/sessions.Session.Save`.
|
||||
*/
|
||||
module BoolToGorillaSessionOptionsTrackingFlow =
|
||||
TaintTracking::Global<BoolToGorillaSessionOptionsTrackingConfig>;
|
||||
|
||||
@@ -15,25 +15,43 @@
|
||||
|
||||
import go
|
||||
import AuthCookie
|
||||
import DataFlow::PathGraph
|
||||
|
||||
module NetHttpCookieTrackingFlow =
|
||||
DataFlow::MergePathGraph<NameToNetHttpCookieTrackingFlow::PathNode,
|
||||
BoolToNetHttpCookieTrackingFlow::PathNode, NameToNetHttpCookieTrackingFlow::PathGraph,
|
||||
BoolToNetHttpCookieTrackingFlow::PathGraph>;
|
||||
|
||||
module GorillaTrackingFlow =
|
||||
DataFlow::MergePathGraph3<GorillaCookieStoreSaveTrackingFlow::PathNode,
|
||||
GorillaSessionOptionsTrackingFlow::PathNode, BoolToGorillaSessionOptionsTrackingFlow::PathNode,
|
||||
GorillaCookieStoreSaveTrackingFlow::PathGraph, GorillaSessionOptionsTrackingFlow::PathGraph,
|
||||
BoolToGorillaSessionOptionsTrackingFlow::PathGraph>;
|
||||
|
||||
module MergedFlow =
|
||||
DataFlow::MergePathGraph3<NetHttpCookieTrackingFlow::PathNode,
|
||||
BoolToGinSetCookieTrackingFlow::PathNode, GorillaTrackingFlow::PathNode,
|
||||
NetHttpCookieTrackingFlow::PathGraph, BoolToGinSetCookieTrackingFlow::PathGraph,
|
||||
GorillaTrackingFlow::PathGraph>;
|
||||
|
||||
import MergedFlow::PathGraph
|
||||
|
||||
/** Holds if `HttpOnly` of `net/http.SetCookie` is set to `false` or not set (default value is used). */
|
||||
predicate isNetHttpCookieFlow(DataFlow::PathNode source, DataFlow::PathNode sink) {
|
||||
exists(DataFlow::PathNode sensitiveName, DataFlow::PathNode setCookieSink |
|
||||
exists(NameToNetHttpCookieTrackingConfiguration cfg |
|
||||
cfg.hasFlowPath(sensitiveName, setCookieSink)
|
||||
) and
|
||||
predicate isNetHttpCookieFlow(
|
||||
NetHttpCookieTrackingFlow::PathNode source, NetHttpCookieTrackingFlow::PathNode sink
|
||||
) {
|
||||
exists(
|
||||
NameToNetHttpCookieTrackingFlow::PathNode sensitiveName,
|
||||
NameToNetHttpCookieTrackingFlow::PathNode setCookieSink
|
||||
|
|
||||
NameToNetHttpCookieTrackingFlow::flowPath(sensitiveName, setCookieSink) and
|
||||
(
|
||||
not any(BoolToNetHttpCookieTrackingConfiguration cfg).hasFlowTo(setCookieSink.getNode()) and
|
||||
source = sensitiveName and
|
||||
sink = setCookieSink
|
||||
not BoolToNetHttpCookieTrackingFlow::flowTo(sink.getNode()) and
|
||||
source.asPathNode1() = sensitiveName and
|
||||
sink.asPathNode1() = setCookieSink
|
||||
or
|
||||
exists(BoolToNetHttpCookieTrackingConfiguration cfg, DataFlow::PathNode setCookieSink2 |
|
||||
cfg.hasFlowPath(source, setCookieSink2) and
|
||||
source.getNode().getBoolValue() = false and
|
||||
sink = setCookieSink2 and
|
||||
setCookieSink.getNode() = setCookieSink2.getNode()
|
||||
)
|
||||
BoolToNetHttpCookieTrackingFlow::flowPath(source.asPathNode2(), sink.asPathNode2()) and
|
||||
source.getNode().getBoolValue() = false and
|
||||
setCookieSink.getNode() = sink.getNode()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -42,44 +60,40 @@ predicate isNetHttpCookieFlow(DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
* Holds if there is gorilla cookie store creation to `Save` path and
|
||||
* `HttpOnly` is set to `false` or not set (default value is used).
|
||||
*/
|
||||
predicate isGorillaSessionsCookieFlow(DataFlow::PathNode source, DataFlow::PathNode sink) {
|
||||
exists(DataFlow::PathNode cookieStoreCreate, DataFlow::PathNode sessionSave |
|
||||
any(GorillaCookieStoreSaveTrackingConfiguration cfg).hasFlowPath(cookieStoreCreate, sessionSave) and
|
||||
predicate isGorillaSessionsCookieFlow(
|
||||
GorillaTrackingFlow::PathNode source, GorillaTrackingFlow::PathNode sink
|
||||
) {
|
||||
exists(
|
||||
GorillaCookieStoreSaveTrackingFlow::PathNode cookieStoreCreate,
|
||||
GorillaCookieStoreSaveTrackingFlow::PathNode sessionSave
|
||||
|
|
||||
GorillaCookieStoreSaveTrackingFlow::flowPath(cookieStoreCreate, sessionSave) and
|
||||
(
|
||||
not any(GorillaSessionOptionsTrackingConfiguration cfg).hasFlowTo(sessionSave.getNode()) and
|
||||
source = cookieStoreCreate and
|
||||
sink = sessionSave
|
||||
not GorillaSessionOptionsTrackingFlow::flowTo(sink.getNode()) and
|
||||
source.asPathNode1() = cookieStoreCreate and
|
||||
sink.asPathNode1() = sessionSave
|
||||
or
|
||||
exists(
|
||||
GorillaSessionOptionsTrackingConfiguration cfg, DataFlow::PathNode options,
|
||||
DataFlow::PathNode sessionSave2
|
||||
|
|
||||
cfg.hasFlowPath(options, sessionSave2) and
|
||||
exists(GorillaTrackingFlow::PathNode options, GorillaTrackingFlow::PathNode sessionSave2 |
|
||||
GorillaSessionOptionsTrackingFlow::flowPath(options.asPathNode2(),
|
||||
sessionSave2.asPathNode2()) and
|
||||
(
|
||||
not any(BoolToGorillaSessionOptionsTrackingConfiguration boolCfg)
|
||||
.hasFlowTo(sessionSave.getNode()) and
|
||||
not BoolToGorillaSessionOptionsTrackingFlow::flowTo(sink.getNode()) and
|
||||
sink = sessionSave2 and
|
||||
source = options and
|
||||
sessionSave.getNode() = sessionSave2.getNode()
|
||||
or
|
||||
exists(
|
||||
BoolToGorillaSessionOptionsTrackingConfiguration boolCfg,
|
||||
DataFlow::PathNode sessionSave3
|
||||
|
|
||||
boolCfg.hasFlowPath(source, sessionSave3) and
|
||||
source.getNode().getBoolValue() = false and
|
||||
sink = sessionSave3 and
|
||||
sessionSave.getNode() = sessionSave3.getNode()
|
||||
)
|
||||
BoolToGorillaSessionOptionsTrackingFlow::flowPath(source.asPathNode3(), sink.asPathNode3()) and
|
||||
source.getNode().getBoolValue() = false and
|
||||
sink.getNode() = sessionSave.getNode()
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
from MergedFlow::PathNode source, MergedFlow::PathNode sink
|
||||
where
|
||||
isNetHttpCookieFlow(source, sink) or
|
||||
any(BoolToGinSetCookieTrackingConfiguration cfg).hasFlowPath(source, sink) or
|
||||
isGorillaSessionsCookieFlow(source, sink)
|
||||
isNetHttpCookieFlow(source.asPathNode1(), sink.asPathNode1()) or
|
||||
BoolToGinSetCookieTrackingFlow::flowPath(source.asPathNode2(), sink.asPathNode2()) or
|
||||
isGorillaSessionsCookieFlow(source.asPathNode3(), sink.asPathNode3())
|
||||
select sink.getNode(), source, sink, "Cookie attribute 'HttpOnly' is not set to true."
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
import DataFlow::PathGraph
|
||||
import semmle.go.security.SensitiveActions
|
||||
|
||||
private predicate isBadResult(DataFlow::Node e) {
|
||||
@@ -97,17 +96,19 @@ private class SensitiveStringSink extends Sink {
|
||||
}
|
||||
}
|
||||
|
||||
class SecretTracking extends TaintTracking::Configuration {
|
||||
SecretTracking() { this = "SecretTracking" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
module Config implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source instanceof UntrustedFlowSource and not isBadResult(source)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof Sink and not isBadResult(sink) }
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof Sink and not isBadResult(sink) }
|
||||
}
|
||||
|
||||
from SecretTracking cfg, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where cfg.hasFlowPath(source, sink)
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
|
||||
import Flow::PathGraph
|
||||
|
||||
from Flow::PathNode source, Flow::PathNode sink
|
||||
where Flow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "$@ may be vulnerable to timing attacks.", source.getNode(),
|
||||
"Hardcoded String"
|
||||
|
||||
@@ -33,34 +33,34 @@ class PamStartFunc extends Function {
|
||||
PamStartFunc() { this.hasQualifiedName("github.com/msteinert/pam", ["StartFunc", "Start"]) }
|
||||
}
|
||||
|
||||
class PamStartToAcctMgmtConfig extends TaintTracking::Configuration {
|
||||
PamStartToAcctMgmtConfig() { this = "PAM auth bypass (Start to AcctMgmt)" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
// PAM auth bypass (Start to AcctMgmt)
|
||||
module PamStartToAcctMgmtConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
exists(PamStartFunc p | p.getACall().getResult(0) = source)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(PamAcctMgmt p | p.getACall().getReceiver() = sink)
|
||||
}
|
||||
}
|
||||
|
||||
class PamStartToAuthenticateConfig extends TaintTracking::Configuration {
|
||||
PamStartToAuthenticateConfig() { this = "PAM auth bypass (Start to Authenticate)" }
|
||||
module PamStartToAcctMgmtFlow = TaintTracking::Global<PamStartToAcctMgmtConfig>;
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
// PAM auth bypass (Start to Authenticate)
|
||||
module PamStartToAuthenticateConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
exists(PamStartFunc p | p.getACall().getResult(0) = source)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(PamAuthenticate p | p.getACall().getReceiver() = sink)
|
||||
}
|
||||
}
|
||||
|
||||
from
|
||||
PamStartToAcctMgmtConfig acctMgmtConfig, PamStartToAuthenticateConfig authConfig,
|
||||
DataFlow::Node source, DataFlow::Node sink
|
||||
module PamStartToAuthenticateFlow = TaintTracking::Global<PamStartToAuthenticateConfig>;
|
||||
|
||||
from DataFlow::Node source, DataFlow::Node sink
|
||||
where
|
||||
not isInTestFile(source.asExpr()) and
|
||||
(authConfig.hasFlow(source, sink) and not acctMgmtConfig.hasFlow(source, _))
|
||||
(PamStartToAuthenticateFlow::flow(source, sink) and not PamStartToAcctMgmtFlow::flow(source, _))
|
||||
select source, "This Pam transaction may not be secure."
|
||||
|
||||
@@ -11,9 +11,9 @@
|
||||
|
||||
import go
|
||||
import HardcodedKeysLib
|
||||
import DataFlow::PathGraph
|
||||
import HardcodedKeys::Flow::PathGraph
|
||||
|
||||
from HardcodedKeys::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where cfg.hasFlowPath(source, sink)
|
||||
from HardcodedKeys::Flow::PathNode source, HardcodedKeys::Flow::PathNode sink
|
||||
where HardcodedKeys::Flow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "$@ is used to sign a JWT token.", source.getNode(),
|
||||
"Hardcoded String"
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
import go
|
||||
import StringOps
|
||||
import DataFlow::PathGraph
|
||||
|
||||
/**
|
||||
* Provides default sources, sinks and sanitizers for reasoning about
|
||||
@@ -363,9 +362,11 @@ module HardcodedKeys {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Flow` instead.
|
||||
*
|
||||
* A configuration depicting taint flow for studying JWT token signing vulnerabilities.
|
||||
*/
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
deprecated class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "Hard-coded JWT Signing Key" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
@@ -374,4 +375,15 @@ module HardcodedKeys {
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node sanitizer) { sanitizer instanceof Sanitizer }
|
||||
}
|
||||
|
||||
private module Config 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 }
|
||||
}
|
||||
|
||||
/** Tracks taint flow for reasoning about JWT token signing vulnerabilities. */
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
}
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
import WeakCryptoAlgorithmCustomizations::WeakCryptoAlgorithm
|
||||
import DataFlow::PathGraph
|
||||
import WeakCryptoAlgorithmCustomizations
|
||||
import WeakCryptoAlgorithm::Flow::PathGraph
|
||||
|
||||
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where cfg.hasFlowPath(source, sink)
|
||||
from WeakCryptoAlgorithm::Flow::PathNode source, WeakCryptoAlgorithm::Flow::PathNode sink
|
||||
where WeakCryptoAlgorithm::Flow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "$@ is used in a weak cryptographic algorithm.",
|
||||
source.getNode(), "Sensitive data"
|
||||
|
||||
@@ -49,9 +49,11 @@ module WeakCryptoAlgorithm {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Flow` instead.
|
||||
*
|
||||
* A configuration depicting taint flow from sensitive information to weak cryptographic algorithms.
|
||||
*/
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
deprecated class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "WeakCryptoAlgorithm" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
@@ -63,4 +65,18 @@ module WeakCryptoAlgorithm {
|
||||
node instanceof Sanitizer
|
||||
}
|
||||
}
|
||||
|
||||
private module Config 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 }
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks taint flow from sensitive information to weak cryptographic
|
||||
* algorithms.
|
||||
*/
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
import DataFlow::PathGraph
|
||||
import semmle.go.dataflow.internal.TaintTrackingUtil
|
||||
|
||||
/**
|
||||
@@ -28,31 +27,34 @@ predicate divideByZeroSanitizerGuard(DataFlow::Node g, Expr e, boolean branch) {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for reasoning about division by zero, where divisor is user-controlled and unchecked.
|
||||
*/
|
||||
class DivideByZeroCheckConfig extends TaintTracking::Configuration {
|
||||
DivideByZeroCheckConfig() { this = "DivideByZeroCheckConfig" }
|
||||
module Config implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource }
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
exists(Function f, DataFlow::CallNode cn | cn = f.getACall() |
|
||||
f.hasQualifiedName("strconv", ["Atoi", "ParseInt", "ParseUint", "ParseFloat"]) and
|
||||
pred = cn.getArgument(0) and
|
||||
succ = cn.getResult(0)
|
||||
node1 = cn.getArgument(0) and
|
||||
node2 = cn.getResult(0)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node = DataFlow::BarrierGuard<divideByZeroSanitizerGuard/3>::getABarrierNode()
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink = DataFlow::exprNode(any(QuoExpr e).getRightOperand())
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, DivideByZeroCheckConfig cfg
|
||||
where cfg.hasFlowPath(source, sink)
|
||||
/**
|
||||
* Tracks taint flow for reasoning about division by zero, where divisor is
|
||||
* user-controlled and unchecked.
|
||||
*/
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
|
||||
import Flow::PathGraph
|
||||
|
||||
from Flow::PathNode source, Flow::PathNode sink
|
||||
where Flow::flowPath(source, sink)
|
||||
select sink, source, sink, "This variable might be zero leading to a division-by-zero panic."
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
import DataFlow::PathGraph
|
||||
import DsnInjectionCustomizations
|
||||
import DsnInjectionFlow::PathGraph
|
||||
|
||||
/** An untrusted flow source taken as a source for the `DsnInjection` taint-flow configuration. */
|
||||
private class UntrustedFlowAsSource extends Source instanceof UntrustedFlowSource { }
|
||||
|
||||
from DsnInjection cfg, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where cfg.hasFlowPath(source, sink)
|
||||
from DsnInjectionFlow::PathNode source, DsnInjectionFlow::PathNode sink
|
||||
where DsnInjectionFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "Data-Source Name is built using $@.", source.getNode(),
|
||||
"untrusted user input"
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
/** Provides a taint-tracking model to reason about Data-Source name injection vulnerabilities. */
|
||||
|
||||
import go
|
||||
import DataFlow::PathGraph
|
||||
import semmle.go.dataflow.barrierguardutil.RegexpCheck
|
||||
|
||||
/** A source for `DsnInjection` taint-flow configuration. */
|
||||
abstract class Source extends DataFlow::Node { }
|
||||
|
||||
/** A taint-tracking configuration to reason about Data Source Name injection vulnerabilities. */
|
||||
class DsnInjection extends TaintTracking::Configuration {
|
||||
/**
|
||||
* DEPRECATED: Use `DsnInjectionFlow` instead.
|
||||
*
|
||||
* A taint-tracking configuration to reason about Data Source Name injection vulnerabilities.
|
||||
*/
|
||||
deprecated class DsnInjection extends TaintTracking::Configuration {
|
||||
DsnInjection() { this = "DsnInjection" }
|
||||
|
||||
override predicate isSource(DataFlow::Node node) { node instanceof Source }
|
||||
@@ -25,6 +28,27 @@ class DsnInjection extends TaintTracking::Configuration {
|
||||
override predicate isSanitizer(DataFlow::Node node) { node instanceof RegexpCheckBarrier }
|
||||
}
|
||||
|
||||
private module DsnInjectionConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(DataFlow::CallNode c |
|
||||
c.getTarget().hasQualifiedName("database/sql", "Open") and
|
||||
c.getArgument(0).getStringValue() = "mysql"
|
||||
|
|
||||
sink = c.getArgument(1)
|
||||
)
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) { node instanceof RegexpCheckBarrier }
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks taint flow for reasoning about Data Source Name injection
|
||||
* vulnerabilities.
|
||||
*/
|
||||
module DsnInjectionFlow = TaintTracking::Global<DsnInjectionConfig>;
|
||||
|
||||
/** A model of a function which decodes or unmarshals a tainted input, propagating taint from any argument to either the method receiver or return value. */
|
||||
private class DecodeFunctionModel extends TaintTracking::FunctionModel {
|
||||
DecodeFunctionModel() {
|
||||
|
||||
@@ -10,15 +10,15 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
import DataFlow::PathGraph
|
||||
import DsnInjectionCustomizations
|
||||
import DsnInjectionFlow::PathGraph
|
||||
|
||||
/** An argument passed via the command line taken as a source for the `DsnInjection` taint-flow configuration. */
|
||||
/** An argument passed via the command line taken as a source for the `DsnInjectionFlow` taint-flow. */
|
||||
private class OsArgsSource extends Source {
|
||||
OsArgsSource() { this = any(Variable c | c.hasQualifiedName("os", "Args")).getARead() }
|
||||
}
|
||||
|
||||
from DsnInjection cfg, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where cfg.hasFlowPath(source, sink)
|
||||
from DsnInjectionFlow::PathNode source, DsnInjectionFlow::PathNode sink
|
||||
where DsnInjectionFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "This query depends on a $@.", source.getNode(),
|
||||
"user-provided value"
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
import DataFlow::PathGraph
|
||||
|
||||
/**
|
||||
* Holds if the provided `untrusted` node flows into a conversion to a PassthroughType.
|
||||
@@ -21,10 +20,10 @@ import DataFlow::PathGraph
|
||||
predicate flowsFromUntrustedToConversion(
|
||||
DataFlow::Node untrusted, PassthroughTypeName targetType, DataFlow::Node conversionSink
|
||||
) {
|
||||
exists(FlowConfFromUntrustedToPassthroughTypeConversion cfg, DataFlow::Node source |
|
||||
cfg.hasFlow(source, conversionSink) and
|
||||
exists(DataFlow::Node source |
|
||||
UntrustedToPassthroughTypeConversionFlow::flow(source, conversionSink) and
|
||||
source = untrusted and
|
||||
targetType = cfg.getDstTypeName()
|
||||
UntrustedToPassthroughTypeConversionConfig::isSinkToPassthroughType(conversionSink, targetType)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -36,78 +35,47 @@ class PassthroughTypeName extends string {
|
||||
PassthroughTypeName() { this = ["HTML", "HTMLAttr", "JS", "JSStr", "CSS", "Srcset", "URL"] }
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for reasoning about when an UntrustedFlowSource
|
||||
* is converted into a special "passthrough" type which will not be escaped by the template generator;
|
||||
* this allows the injection of arbitrary content (html, css, js) into the generated
|
||||
* output of the templates.
|
||||
*/
|
||||
class FlowConfFromUntrustedToPassthroughTypeConversion extends TaintTracking::Configuration {
|
||||
PassthroughTypeName dstTypeName;
|
||||
module UntrustedToPassthroughTypeConversionConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource }
|
||||
|
||||
FlowConfFromUntrustedToPassthroughTypeConversion() {
|
||||
this = "UntrustedToConversion" + dstTypeName
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of conversion's destination type.
|
||||
*/
|
||||
PassthroughTypeName getDstTypeName() { result = dstTypeName }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource }
|
||||
|
||||
private predicate isSinkToPassthroughType(DataFlow::TypeCastNode sink, PassthroughTypeName name) {
|
||||
additional predicate isSinkToPassthroughType(DataFlow::TypeCastNode sink, PassthroughTypeName name) {
|
||||
exists(Type typ |
|
||||
typ = sink.getResultType() and
|
||||
typ.getUnderlyingType*().hasQualifiedName("html/template", name)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { this.isSinkToPassthroughType(sink, dstTypeName) }
|
||||
predicate isSink(DataFlow::Node sink) { isSinkToPassthroughType(sink, _) }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node sanitizer) {
|
||||
sanitizer instanceof SharedXss::Sanitizer or sanitizer.getType() instanceof NumericType
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node instanceof SharedXss::Sanitizer or node.getType() instanceof NumericType
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks taint flow for reasoning about when an `UntrustedFlowSource` is
|
||||
* converted into a special "passthrough" type which will not be escaped by the
|
||||
* template generator; this allows the injection of arbitrary content (html,
|
||||
* css, js) into the generated output of the templates.
|
||||
*/
|
||||
module UntrustedToPassthroughTypeConversionFlow =
|
||||
TaintTracking::Global<UntrustedToPassthroughTypeConversionConfig>;
|
||||
|
||||
/**
|
||||
* Holds if the provided `conversion` node flows into the provided `execSink`.
|
||||
*/
|
||||
predicate flowsFromConversionToExec(
|
||||
DataFlow::Node conversion, PassthroughTypeName targetType, DataFlow::Node execSink
|
||||
) {
|
||||
exists(
|
||||
FlowConfPassthroughTypeConversionToTemplateExecutionCall cfg, DataFlow::Node source,
|
||||
DataFlow::Node execSinkLocal
|
||||
|
|
||||
cfg.hasFlow(source, execSinkLocal) and
|
||||
source = conversion and
|
||||
execSink = execSinkLocal and
|
||||
targetType = cfg.getDstTypeName()
|
||||
)
|
||||
PassthroughTypeConversionToTemplateExecutionCallFlow::flow(conversion, execSink) and
|
||||
PassthroughTypeConversionToTemplateExecutionCallConfig::isSourceConversionToPassthroughType(conversion,
|
||||
targetType)
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for reasoning about when the result of a conversion
|
||||
* to a PassthroughType flows to a template execution call.
|
||||
*/
|
||||
class FlowConfPassthroughTypeConversionToTemplateExecutionCall extends TaintTracking::Configuration {
|
||||
PassthroughTypeName dstTypeName;
|
||||
module PassthroughTypeConversionToTemplateExecutionCallConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { isSourceConversionToPassthroughType(source, _) }
|
||||
|
||||
FlowConfPassthroughTypeConversionToTemplateExecutionCall() {
|
||||
this = "ConversionToExec" + dstTypeName
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of conversion's destination type.
|
||||
*/
|
||||
PassthroughTypeName getDstTypeName() { result = dstTypeName }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
this.isSourceConversionToPassthroughType(source, dstTypeName)
|
||||
}
|
||||
|
||||
private predicate isSourceConversionToPassthroughType(
|
||||
additional predicate isSourceConversionToPassthroughType(
|
||||
DataFlow::TypeCastNode source, PassthroughTypeName name
|
||||
) {
|
||||
exists(Type typ |
|
||||
@@ -116,9 +84,16 @@ class FlowConfPassthroughTypeConversionToTemplateExecutionCall extends TaintTrac
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { isSinkToTemplateExec(sink, _) }
|
||||
predicate isSink(DataFlow::Node sink) { isSinkToTemplateExec(sink, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks taint flow for reasoning about when the result of a conversion to a
|
||||
* PassthroughType flows to a template execution call.
|
||||
*/
|
||||
module PassthroughTypeConversionToTemplateExecutionCallFlow =
|
||||
TaintTracking::Global<PassthroughTypeConversionToTemplateExecutionCallConfig>;
|
||||
|
||||
/**
|
||||
* Holds if the sink is a data value argument of a template execution call.
|
||||
*/
|
||||
@@ -133,41 +108,46 @@ predicate isSinkToTemplateExec(DataFlow::Node sink, DataFlow::CallNode call) {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for reasoning about when an UntrustedFlowSource
|
||||
* flows into a template executor call.
|
||||
*/
|
||||
class FlowConfFromUntrustedToTemplateExecutionCall extends TaintTracking::Configuration {
|
||||
FlowConfFromUntrustedToTemplateExecutionCall() {
|
||||
this = "FlowConfFromUntrustedToTemplateExecutionCall"
|
||||
}
|
||||
module FromUntrustedToTemplateExecutionCallConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { isSinkToTemplateExec(sink, _) }
|
||||
predicate isSink(DataFlow::Node sink) { isSinkToTemplateExec(sink, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks taint flow from an `UntrustedFlowSource` into a template executor
|
||||
* call.
|
||||
*/
|
||||
module FromUntrustedToTemplateExecutionCallFlow =
|
||||
TaintTracking::Global<FromUntrustedToTemplateExecutionCallConfig>;
|
||||
|
||||
import FromUntrustedToTemplateExecutionCallFlow::PathGraph
|
||||
|
||||
/**
|
||||
* Holds if the provided `untrusted` node flows into the provided `execSink`.
|
||||
*/
|
||||
predicate flowsFromUntrustedToExec(DataFlow::PathNode untrusted, DataFlow::PathNode execSink) {
|
||||
exists(FlowConfFromUntrustedToTemplateExecutionCall cfg | cfg.hasFlowPath(untrusted, execSink))
|
||||
predicate flowsFromUntrustedToExec(
|
||||
FromUntrustedToTemplateExecutionCallFlow::PathNode untrusted,
|
||||
FromUntrustedToTemplateExecutionCallFlow::PathNode execSink
|
||||
) {
|
||||
FromUntrustedToTemplateExecutionCallFlow::flowPath(untrusted, execSink)
|
||||
}
|
||||
|
||||
from
|
||||
DataFlow::PathNode untrustedSource, DataFlow::PathNode templateExecCall,
|
||||
PassthroughTypeName targetTypeName, DataFlow::PathNode conversion
|
||||
FromUntrustedToTemplateExecutionCallFlow::PathNode untrustedSource,
|
||||
FromUntrustedToTemplateExecutionCallFlow::PathNode templateExecCall,
|
||||
PassthroughTypeName targetTypeName, DataFlow::Node conversion
|
||||
where
|
||||
// A = untrusted remote flow source
|
||||
// B = conversion to PassthroughType
|
||||
// C = template execution call
|
||||
// Flows:
|
||||
// A -> B
|
||||
flowsFromUntrustedToConversion(untrustedSource.getNode(), targetTypeName, conversion.getNode()) and
|
||||
flowsFromUntrustedToConversion(untrustedSource.getNode(), targetTypeName, conversion) and
|
||||
// B -> C
|
||||
flowsFromConversionToExec(conversion.getNode(), targetTypeName, templateExecCall.getNode()) and
|
||||
flowsFromConversionToExec(conversion, targetTypeName, templateExecCall.getNode()) and
|
||||
// A -> C
|
||||
flowsFromUntrustedToExec(untrustedSource, templateExecCall)
|
||||
select templateExecCall.getNode(), untrustedSource, templateExecCall,
|
||||
"Data from an $@ will not be auto-escaped because it was $@ to template." + targetTypeName,
|
||||
untrustedSource.getNode(), "untrusted source", conversion.getNode(), "converted"
|
||||
untrustedSource.getNode(), "untrusted source", conversion, "converted"
|
||||
|
||||
@@ -17,13 +17,13 @@ import SensitiveConditionBypass
|
||||
|
||||
from
|
||||
ControlFlow::ConditionGuardNode guard, DataFlow::Node sensitiveSink,
|
||||
SensitiveExpr::Classification classification, Configuration config, DataFlow::PathNode source,
|
||||
DataFlow::PathNode operand, ComparisonExpr comp
|
||||
SensitiveExpr::Classification classification, DataFlow::Node source, DataFlow::Node operand,
|
||||
ComparisonExpr comp
|
||||
where
|
||||
// there should be a flow between source and the operand sink
|
||||
config.hasFlowPath(source, operand) and
|
||||
Flow::flow(source, operand) and
|
||||
// both the operand should belong to the same comparison expression
|
||||
operand.getNode().asExpr() = comp.getAnOperand() and
|
||||
operand.asExpr() = comp.getAnOperand() and
|
||||
// get the ConditionGuardNode corresponding to the comparison expr.
|
||||
guard.getCondition() = comp and
|
||||
// the sink `sensitiveSink` should be sensitive,
|
||||
|
||||
@@ -43,10 +43,12 @@ private class ConstComparisonExpr extends ComparisonExpr {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Flow` instead.
|
||||
*
|
||||
* A data-flow configuration for reasoning about
|
||||
* user-controlled bypassing of sensitive actions.
|
||||
*/
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
deprecated class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "Condtional Expression Check Bypass" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
@@ -66,3 +68,28 @@ class Configuration extends TaintTracking::Configuration {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private module Config implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source instanceof UntrustedFlowSource
|
||||
or
|
||||
exists(DataFlow::FieldReadNode f |
|
||||
f.getField().hasQualifiedName("net/http", "Request", "Host")
|
||||
|
|
||||
source = f
|
||||
)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(ConstComparisonExpr c |
|
||||
c.getAnOperand() = sink.asExpr() and
|
||||
not c.isPotentialFalsePositive()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks taint flow for reasoning about user-controlled bypassing of sensitive
|
||||
* actions.
|
||||
*/
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
|
||||
@@ -12,30 +12,28 @@
|
||||
|
||||
import go
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for reasoning about conditional bypass.
|
||||
*/
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "ConditionalBypass" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
module Config implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source instanceof UntrustedFlowSource
|
||||
or
|
||||
source = any(Field f | f.hasQualifiedName("net/http", "Request", "Host")).getARead()
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(ComparisonExpr c | c.getAnOperand() = sink.asExpr())
|
||||
}
|
||||
}
|
||||
|
||||
/** Tracks taint flow for reasoning about conditional bypass. */
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
|
||||
from
|
||||
Configuration config, DataFlow::PathNode lhsSource, DataFlow::PathNode lhs,
|
||||
DataFlow::PathNode rhsSource, DataFlow::PathNode rhs, ComparisonExpr c
|
||||
DataFlow::Node lhsSource, DataFlow::Node lhs, DataFlow::Node rhsSource, DataFlow::Node rhs,
|
||||
ComparisonExpr c
|
||||
where
|
||||
config.hasFlowPath(rhsSource, rhs) and
|
||||
rhs.getNode().asExpr() = c.getRightOperand() and
|
||||
config.hasFlowPath(lhsSource, lhs) and
|
||||
lhs.getNode().asExpr() = c.getLeftOperand()
|
||||
select c, "This comparison of a $@ with another $@ can be bypassed by a malicious user.",
|
||||
lhsSource.getNode(), "user-controlled value", rhsSource.getNode(), "user-controlled value"
|
||||
Flow::flow(rhsSource, rhs) and
|
||||
rhs.asExpr() = c.getRightOperand() and
|
||||
Flow::flow(lhsSource, lhs) and
|
||||
lhs.asExpr() = c.getLeftOperand()
|
||||
select c, "This comparison of a $@ with another $@ can be bypassed by a malicious user.", lhsSource,
|
||||
"user-controlled value", rhsSource, "user-controlled value"
|
||||
|
||||
@@ -12,12 +12,12 @@
|
||||
|
||||
import go
|
||||
import SSRF
|
||||
import DataFlow::PathGraph
|
||||
import ServerSideRequestForgery::Flow::PathGraph
|
||||
|
||||
from
|
||||
ServerSideRequestForgery::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink,
|
||||
ServerSideRequestForgery::Flow::PathNode source, ServerSideRequestForgery::Flow::PathNode sink,
|
||||
DataFlow::Node request
|
||||
where
|
||||
cfg.hasFlowPath(source, sink) and
|
||||
ServerSideRequestForgery::Flow::flowPath(source, sink) and
|
||||
request = sink.getNode().(ServerSideRequestForgery::Sink).getARequest()
|
||||
select request, source, sink, "The URL of this request depends on a user-provided value."
|
||||
|
||||
@@ -17,9 +17,11 @@ module ServerSideRequestForgery {
|
||||
private import semmle.go.dataflow.Properties
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Flow` instead.
|
||||
*
|
||||
* A taint-tracking configuration for reasoning about request forgery.
|
||||
*/
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
deprecated class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "SSRF" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
@@ -44,6 +46,26 @@ module ServerSideRequestForgery {
|
||||
}
|
||||
}
|
||||
|
||||
private module Config implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
// propagate to a URL when its host is assigned to
|
||||
exists(Write w, Field f, SsaWithFields v | f.hasQualifiedName("net/url", "URL", "Host") |
|
||||
w.writesField(v.getAUse(), f, node1) and node2 = v.getAUse()
|
||||
)
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
|
||||
|
||||
predicate isBarrierOut(DataFlow::Node node) { node instanceof SanitizerEdge }
|
||||
}
|
||||
|
||||
/** Tracks taint flow for reasoning about request forgery vulnerabilities. */
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
|
||||
/** A data flow source for request forgery vulnerabilities. */
|
||||
abstract class Source extends DataFlow::Node { }
|
||||
|
||||
|
||||
@@ -51,18 +51,14 @@ class AllowCredentialsHeaderWrite extends Http::HeaderWrite {
|
||||
AllowCredentialsHeaderWrite() { this.getHeaderName() = headerAllowCredentials() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for reasoning about when an UntrustedFlowSource
|
||||
* flows to a HeaderWrite that writes an `Access-Control-Allow-Origin` header's value.
|
||||
*/
|
||||
class FlowsUntrustedToAllowOriginHeader extends TaintTracking::Configuration {
|
||||
FlowsUntrustedToAllowOriginHeader() { this = "from-untrusted-to-allow-origin-header-value" }
|
||||
module UntrustedToAllowOriginHeaderConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource }
|
||||
additional predicate isSinkHW(DataFlow::Node sink, AllowOriginHeaderWrite hw) {
|
||||
sink = hw.getValue()
|
||||
}
|
||||
|
||||
predicate isSinkHW(DataFlow::Node sink, AllowOriginHeaderWrite hw) { sink = hw.getValue() }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
exists(ControlFlow::ConditionGuardNode cgn |
|
||||
cgn.ensures(any(AllowedFlag f).getAFlag().getANode(), _)
|
||||
|
|
||||
@@ -70,9 +66,15 @@ class FlowsUntrustedToAllowOriginHeader extends TaintTracking::Configuration {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { this.isSinkHW(sink, _) }
|
||||
predicate isSink(DataFlow::Node sink) { isSinkHW(sink, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks taint flowfor reasoning about when an `UntrustedFlowSource` flows to
|
||||
* a `HeaderWrite` that writes an `Access-Control-Allow-Origin` header's value.
|
||||
*/
|
||||
module UntrustedToAllowOriginHeaderFlow = TaintTracking::Global<UntrustedToAllowOriginHeaderConfig>;
|
||||
|
||||
/**
|
||||
* Holds if the provided `allowOriginHW` HeaderWrite's parent ResponseWriter
|
||||
* also has another HeaderWrite that sets a `Access-Control-Allow-Credentials`
|
||||
@@ -92,9 +94,9 @@ predicate allowCredentialsIsSetToTrue(AllowOriginHeaderWrite allowOriginHW) {
|
||||
* The `message` parameter is populated with the warning message to be returned by the query.
|
||||
*/
|
||||
predicate flowsFromUntrustedToAllowOrigin(AllowOriginHeaderWrite allowOriginHW, string message) {
|
||||
exists(FlowsUntrustedToAllowOriginHeader cfg, DataFlow::Node sink |
|
||||
cfg.hasFlowTo(sink) and
|
||||
cfg.isSinkHW(sink, allowOriginHW)
|
||||
exists(DataFlow::Node sink |
|
||||
UntrustedToAllowOriginHeaderFlow::flowTo(sink) and
|
||||
UntrustedToAllowOriginHeaderConfig::isSinkHW(sink, allowOriginHW)
|
||||
|
|
||||
message =
|
||||
headerAllowOrigin() + " header is set to a user-defined value, and " +
|
||||
@@ -120,18 +122,12 @@ class MapRead extends DataFlow::ElementReadNode {
|
||||
MapRead() { this.getBase().getType() instanceof MapType }
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for reasoning about when an UntrustedFlowSource
|
||||
* flows somewhere.
|
||||
*/
|
||||
class FlowsFromUntrusted extends TaintTracking::Configuration {
|
||||
FlowsFromUntrusted() { this = "from-untrusted" }
|
||||
module FromUntrustedConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource }
|
||||
predicate isSink(DataFlow::Node sink) { isSinkCgn(sink, _) }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { this.isSinkCgn(sink, _) }
|
||||
|
||||
predicate isSinkCgn(DataFlow::Node sink, ControlFlow::ConditionGuardNode cgn) {
|
||||
additional predicate isSinkCgn(DataFlow::Node sink, ControlFlow::ConditionGuardNode cgn) {
|
||||
exists(IfStmt ifs |
|
||||
exists(Expr operand |
|
||||
operand = ifs.getCond().getAChildExpr*() and
|
||||
@@ -165,12 +161,18 @@ class FlowsFromUntrusted extends TaintTracking::Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks taint flow for reasoning about when an `UntrustedFlowSource` flows
|
||||
* somewhere.
|
||||
*/
|
||||
module FromUntrustedFlow = TaintTracking::Global<FromUntrustedConfig>;
|
||||
|
||||
/**
|
||||
* Holds if the provided `allowOriginHW` is also destination of a `UntrustedFlowSource`.
|
||||
*/
|
||||
predicate flowsToGuardedByCheckOnUntrusted(AllowOriginHeaderWrite allowOriginHW) {
|
||||
exists(FlowsFromUntrusted cfg, DataFlow::Node sink, ControlFlow::ConditionGuardNode cgn |
|
||||
cfg.hasFlowTo(sink) and cfg.isSinkCgn(sink, cgn)
|
||||
exists(DataFlow::Node sink, ControlFlow::ConditionGuardNode cgn |
|
||||
FromUntrustedFlow::flowTo(sink) and FromUntrustedConfig::isSinkCgn(sink, cgn)
|
||||
|
|
||||
cgn.dominates(allowOriginHW.getBasicBlock())
|
||||
)
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
import DataFlow::PathGraph
|
||||
|
||||
/*
|
||||
* Returns the type after all aliases, named types, and pointer
|
||||
@@ -39,38 +38,41 @@ class ConversionToUnsafePointer extends DataFlow::TypeCastNode {
|
||||
}
|
||||
|
||||
/* Type casting from a `unsafe.Pointer`.*/
|
||||
class UnsafeTypeCastingConf extends TaintTracking::Configuration {
|
||||
UnsafeTypeCastingConf() { this = "UnsafeTypeCastingConf" }
|
||||
|
||||
predicate conversionIsSource(DataFlow::Node source, ConversionToUnsafePointer conv) {
|
||||
module UnsafeTypeCastingConfig implements DataFlow::ConfigSig {
|
||||
additional predicate conversionIsSource(DataFlow::Node source, ConversionToUnsafePointer conv) {
|
||||
source = conv
|
||||
}
|
||||
|
||||
predicate typeCastNodeIsSink(DataFlow::Node sink, DataFlow::TypeCastNode ca) {
|
||||
additional predicate typeCastNodeIsSink(DataFlow::Node sink, DataFlow::TypeCastNode ca) {
|
||||
ca.getOperand().getType() instanceof UnsafePointerType and
|
||||
sink = ca
|
||||
}
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { this.conversionIsSource(source, _) }
|
||||
predicate isSource(DataFlow::Node source) { conversionIsSource(source, _) }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { this.typeCastNodeIsSink(sink, _) }
|
||||
predicate isSink(DataFlow::Node sink) { typeCastNodeIsSink(sink, _) }
|
||||
}
|
||||
|
||||
/** Tracks taint flow for reasoning about type casting from a `unsafe.Pointer`. */
|
||||
module UnsafeTypeCastingFlow = TaintTracking::Global<UnsafeTypeCastingConfig>;
|
||||
|
||||
import UnsafeTypeCastingFlow::PathGraph
|
||||
|
||||
/*
|
||||
* Type casting from a shorter array to a longer array
|
||||
* through the use of unsafe pointers.
|
||||
*/
|
||||
|
||||
predicate castShortArrayToLongerArray(
|
||||
DataFlow::PathNode source, DataFlow::PathNode sink, string message
|
||||
UnsafeTypeCastingFlow::PathNode source, UnsafeTypeCastingFlow::PathNode sink, string message
|
||||
) {
|
||||
exists(
|
||||
UnsafeTypeCastingConf cfg, DataFlow::TypeCastNode castBig, ConversionToUnsafePointer castLittle,
|
||||
ArrayType arrTo, ArrayType arrFrom, int arrFromSize
|
||||
DataFlow::TypeCastNode castBig, ConversionToUnsafePointer castLittle, ArrayType arrTo,
|
||||
ArrayType arrFrom, int arrFromSize
|
||||
|
|
||||
cfg.hasFlowPath(source, sink) and
|
||||
cfg.conversionIsSource(source.getNode(), castLittle) and
|
||||
cfg.typeCastNodeIsSink(sink.getNode(), castBig) and
|
||||
UnsafeTypeCastingFlow::flowPath(source, sink) and
|
||||
UnsafeTypeCastingConfig::conversionIsSource(source.getNode(), castLittle) and
|
||||
UnsafeTypeCastingConfig::typeCastNodeIsSink(sink.getNode(), castBig) and
|
||||
arrTo = getFinalType(castBig.getResultType()) and
|
||||
(
|
||||
// Array (whole) to array:
|
||||
@@ -108,14 +110,16 @@ predicate castShortArrayToLongerArray(
|
||||
* through the use of unsafe pointers.
|
||||
*/
|
||||
|
||||
predicate castTypeToArray(DataFlow::PathNode source, DataFlow::PathNode sink, string message) {
|
||||
predicate castTypeToArray(
|
||||
UnsafeTypeCastingFlow::PathNode source, UnsafeTypeCastingFlow::PathNode sink, string message
|
||||
) {
|
||||
exists(
|
||||
UnsafeTypeCastingConf cfg, DataFlow::TypeCastNode castBig, ConversionToUnsafePointer castLittle,
|
||||
ArrayType arrTo, Type typeFrom
|
||||
DataFlow::TypeCastNode castBig, ConversionToUnsafePointer castLittle, ArrayType arrTo,
|
||||
Type typeFrom
|
||||
|
|
||||
cfg.hasFlowPath(source, sink) and
|
||||
cfg.conversionIsSource(source.getNode(), castLittle) and
|
||||
cfg.typeCastNodeIsSink(sink.getNode(), castBig) and
|
||||
UnsafeTypeCastingFlow::flowPath(source, sink) and
|
||||
UnsafeTypeCastingConfig::conversionIsSource(source.getNode(), castLittle) and
|
||||
UnsafeTypeCastingConfig::typeCastNodeIsSink(sink.getNode(), castBig) and
|
||||
arrTo = getFinalType(castBig.getResultType()) and
|
||||
not typeFrom.getUnderlyingType() instanceof ArrayType and
|
||||
not typeFrom instanceof PointerType and
|
||||
@@ -137,15 +141,15 @@ predicate castTypeToArray(DataFlow::PathNode source, DataFlow::PathNode sink, st
|
||||
*/
|
||||
|
||||
predicate castDifferentBitSizeNumbers(
|
||||
DataFlow::PathNode source, DataFlow::PathNode sink, string message
|
||||
UnsafeTypeCastingFlow::PathNode source, UnsafeTypeCastingFlow::PathNode sink, string message
|
||||
) {
|
||||
exists(
|
||||
UnsafeTypeCastingConf cfg, DataFlow::TypeCastNode castBig, ConversionToUnsafePointer castLittle,
|
||||
NumericType numTo, NumericType numFrom
|
||||
DataFlow::TypeCastNode castBig, ConversionToUnsafePointer castLittle, NumericType numTo,
|
||||
NumericType numFrom
|
||||
|
|
||||
cfg.hasFlowPath(source, sink) and
|
||||
cfg.conversionIsSource(source.getNode(), castLittle) and
|
||||
cfg.typeCastNodeIsSink(sink.getNode(), castBig) and
|
||||
UnsafeTypeCastingFlow::flowPath(source, sink) and
|
||||
UnsafeTypeCastingConfig::conversionIsSource(source.getNode(), castLittle) and
|
||||
UnsafeTypeCastingConfig::typeCastNodeIsSink(sink.getNode(), castBig) and
|
||||
numTo = getFinalType(castBig.getResultType()) and
|
||||
numFrom = getFinalType(castLittle.getOperand().getType()) and
|
||||
// TODO: also consider cast from uint to int?
|
||||
@@ -171,7 +175,7 @@ int getNumericTypeSize(NumericType typ) {
|
||||
result = typ.getSize()
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, string message
|
||||
from UnsafeTypeCastingFlow::PathNode source, UnsafeTypeCastingFlow::PathNode sink, string message
|
||||
where
|
||||
castShortArrayToLongerArray(source, sink, message) or
|
||||
castTypeToArray(source, sink, message) or
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
edges
|
||||
| CookieWithoutHttpOnly.go:12:10:12:18 | "session" | CookieWithoutHttpOnly.go:15:20:15:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:12:10:12:18 | "session" | CookieWithoutHttpOnly.go:15:20:15:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:12:10:12:18 | "session" | CookieWithoutHttpOnly.go:15:21:15:21 | c |
|
||||
| CookieWithoutHttpOnly.go:11:7:14:2 | struct literal | CookieWithoutHttpOnly.go:15:20:15:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:11:7:14:2 | struct literal | CookieWithoutHttpOnly.go:15:20:15:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:11:7:14:2 | struct literal | CookieWithoutHttpOnly.go:15:21:15:21 | c |
|
||||
| CookieWithoutHttpOnly.go:12:10:12:18 | "session" | CookieWithoutHttpOnly.go:11:7:14:2 | struct literal |
|
||||
| CookieWithoutHttpOnly.go:15:20:15:21 | &... | CookieWithoutHttpOnly.go:15:20:15:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:15:20:15:21 | &... | CookieWithoutHttpOnly.go:15:20:15:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:15:20:15:21 | &... | CookieWithoutHttpOnly.go:15:21:15:21 | c |
|
||||
@@ -9,12 +10,14 @@ edges
|
||||
| CookieWithoutHttpOnly.go:15:20:15:21 | &... [pointer] | CookieWithoutHttpOnly.go:15:20:15:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:15:20:15:21 | &... [pointer] | CookieWithoutHttpOnly.go:15:21:15:21 | c |
|
||||
| CookieWithoutHttpOnly.go:15:21:15:21 | c | CookieWithoutHttpOnly.go:15:20:15:21 | &... [pointer] |
|
||||
| CookieWithoutHttpOnly.go:20:13:20:21 | "session" | CookieWithoutHttpOnly.go:24:20:24:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:20:13:20:21 | "session" | CookieWithoutHttpOnly.go:24:20:24:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:20:13:20:21 | "session" | CookieWithoutHttpOnly.go:24:21:24:21 | c |
|
||||
| CookieWithoutHttpOnly.go:22:13:22:17 | false | CookieWithoutHttpOnly.go:24:20:24:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:22:13:22:17 | false | CookieWithoutHttpOnly.go:24:20:24:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:22:13:22:17 | false | CookieWithoutHttpOnly.go:24:21:24:21 | c |
|
||||
| CookieWithoutHttpOnly.go:19:7:23:2 | struct literal | CookieWithoutHttpOnly.go:24:20:24:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:19:7:23:2 | struct literal | CookieWithoutHttpOnly.go:24:20:24:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:19:7:23:2 | struct literal | CookieWithoutHttpOnly.go:24:20:24:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:19:7:23:2 | struct literal | CookieWithoutHttpOnly.go:24:20:24:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:19:7:23:2 | struct literal | CookieWithoutHttpOnly.go:24:21:24:21 | c |
|
||||
| CookieWithoutHttpOnly.go:19:7:23:2 | struct literal | CookieWithoutHttpOnly.go:24:21:24:21 | c |
|
||||
| CookieWithoutHttpOnly.go:20:13:20:21 | "session" | CookieWithoutHttpOnly.go:19:7:23:2 | struct literal |
|
||||
| CookieWithoutHttpOnly.go:22:13:22:17 | false | CookieWithoutHttpOnly.go:19:7:23:2 | struct literal |
|
||||
| CookieWithoutHttpOnly.go:24:20:24:21 | &... | CookieWithoutHttpOnly.go:24:20:24:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:24:20:24:21 | &... | CookieWithoutHttpOnly.go:24:20:24:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:24:20:24:21 | &... | CookieWithoutHttpOnly.go:24:20:24:21 | &... |
|
||||
@@ -29,12 +32,14 @@ edges
|
||||
| CookieWithoutHttpOnly.go:24:20:24:21 | &... [pointer] | CookieWithoutHttpOnly.go:24:21:24:21 | c |
|
||||
| CookieWithoutHttpOnly.go:24:21:24:21 | c | CookieWithoutHttpOnly.go:24:20:24:21 | &... [pointer] |
|
||||
| CookieWithoutHttpOnly.go:24:21:24:21 | c | CookieWithoutHttpOnly.go:24:20:24:21 | &... [pointer] |
|
||||
| CookieWithoutHttpOnly.go:29:13:29:21 | "session" | CookieWithoutHttpOnly.go:33:20:33:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:29:13:29:21 | "session" | CookieWithoutHttpOnly.go:33:20:33:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:29:13:29:21 | "session" | CookieWithoutHttpOnly.go:33:21:33:21 | c |
|
||||
| CookieWithoutHttpOnly.go:31:13:31:16 | true | CookieWithoutHttpOnly.go:33:20:33:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:31:13:31:16 | true | CookieWithoutHttpOnly.go:33:20:33:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:31:13:31:16 | true | CookieWithoutHttpOnly.go:33:21:33:21 | c |
|
||||
| CookieWithoutHttpOnly.go:28:7:32:2 | struct literal | CookieWithoutHttpOnly.go:33:20:33:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:28:7:32:2 | struct literal | CookieWithoutHttpOnly.go:33:20:33:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:28:7:32:2 | struct literal | CookieWithoutHttpOnly.go:33:20:33:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:28:7:32:2 | struct literal | CookieWithoutHttpOnly.go:33:20:33:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:28:7:32:2 | struct literal | CookieWithoutHttpOnly.go:33:21:33:21 | c |
|
||||
| CookieWithoutHttpOnly.go:28:7:32:2 | struct literal | CookieWithoutHttpOnly.go:33:21:33:21 | c |
|
||||
| CookieWithoutHttpOnly.go:29:13:29:21 | "session" | CookieWithoutHttpOnly.go:28:7:32:2 | struct literal |
|
||||
| CookieWithoutHttpOnly.go:31:13:31:16 | true | CookieWithoutHttpOnly.go:28:7:32:2 | struct literal |
|
||||
| CookieWithoutHttpOnly.go:33:20:33:21 | &... | CookieWithoutHttpOnly.go:33:20:33:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:33:20:33:21 | &... | CookieWithoutHttpOnly.go:33:20:33:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:33:20:33:21 | &... | CookieWithoutHttpOnly.go:33:20:33:21 | &... |
|
||||
@@ -49,12 +54,14 @@ edges
|
||||
| CookieWithoutHttpOnly.go:33:20:33:21 | &... [pointer] | CookieWithoutHttpOnly.go:33:21:33:21 | c |
|
||||
| CookieWithoutHttpOnly.go:33:21:33:21 | c | CookieWithoutHttpOnly.go:33:20:33:21 | &... [pointer] |
|
||||
| CookieWithoutHttpOnly.go:33:21:33:21 | c | CookieWithoutHttpOnly.go:33:20:33:21 | &... [pointer] |
|
||||
| CookieWithoutHttpOnly.go:38:10:38:18 | "session" | CookieWithoutHttpOnly.go:42:20:42:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:38:10:38:18 | "session" | CookieWithoutHttpOnly.go:42:20:42:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:38:10:38:18 | "session" | CookieWithoutHttpOnly.go:42:21:42:21 | c |
|
||||
| CookieWithoutHttpOnly.go:41:15:41:18 | true | CookieWithoutHttpOnly.go:42:20:42:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:41:15:41:18 | true | CookieWithoutHttpOnly.go:42:20:42:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:41:15:41:18 | true | CookieWithoutHttpOnly.go:42:21:42:21 | c |
|
||||
| CookieWithoutHttpOnly.go:37:7:40:2 | struct literal | CookieWithoutHttpOnly.go:42:20:42:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:37:7:40:2 | struct literal | CookieWithoutHttpOnly.go:42:20:42:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:37:7:40:2 | struct literal | CookieWithoutHttpOnly.go:42:20:42:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:37:7:40:2 | struct literal | CookieWithoutHttpOnly.go:42:20:42:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:37:7:40:2 | struct literal | CookieWithoutHttpOnly.go:42:21:42:21 | c |
|
||||
| CookieWithoutHttpOnly.go:37:7:40:2 | struct literal | CookieWithoutHttpOnly.go:42:21:42:21 | c |
|
||||
| CookieWithoutHttpOnly.go:38:10:38:18 | "session" | CookieWithoutHttpOnly.go:37:7:40:2 | struct literal |
|
||||
| CookieWithoutHttpOnly.go:41:15:41:18 | true | CookieWithoutHttpOnly.go:37:7:40:2 | struct literal |
|
||||
| CookieWithoutHttpOnly.go:42:20:42:21 | &... | CookieWithoutHttpOnly.go:42:20:42:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:42:20:42:21 | &... | CookieWithoutHttpOnly.go:42:20:42:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:42:20:42:21 | &... | CookieWithoutHttpOnly.go:42:20:42:21 | &... |
|
||||
@@ -69,12 +76,14 @@ edges
|
||||
| CookieWithoutHttpOnly.go:42:20:42:21 | &... [pointer] | CookieWithoutHttpOnly.go:42:21:42:21 | c |
|
||||
| CookieWithoutHttpOnly.go:42:21:42:21 | c | CookieWithoutHttpOnly.go:42:20:42:21 | &... [pointer] |
|
||||
| CookieWithoutHttpOnly.go:42:21:42:21 | c | CookieWithoutHttpOnly.go:42:20:42:21 | &... [pointer] |
|
||||
| CookieWithoutHttpOnly.go:47:10:47:18 | "session" | CookieWithoutHttpOnly.go:51:20:51:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:47:10:47:18 | "session" | CookieWithoutHttpOnly.go:51:20:51:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:47:10:47:18 | "session" | CookieWithoutHttpOnly.go:51:21:51:21 | c |
|
||||
| CookieWithoutHttpOnly.go:50:15:50:19 | false | CookieWithoutHttpOnly.go:51:20:51:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:50:15:50:19 | false | CookieWithoutHttpOnly.go:51:20:51:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:50:15:50:19 | false | CookieWithoutHttpOnly.go:51:21:51:21 | c |
|
||||
| CookieWithoutHttpOnly.go:46:7:49:2 | struct literal | CookieWithoutHttpOnly.go:51:20:51:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:46:7:49:2 | struct literal | CookieWithoutHttpOnly.go:51:20:51:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:46:7:49:2 | struct literal | CookieWithoutHttpOnly.go:51:20:51:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:46:7:49:2 | struct literal | CookieWithoutHttpOnly.go:51:20:51:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:46:7:49:2 | struct literal | CookieWithoutHttpOnly.go:51:21:51:21 | c |
|
||||
| CookieWithoutHttpOnly.go:46:7:49:2 | struct literal | CookieWithoutHttpOnly.go:51:21:51:21 | c |
|
||||
| CookieWithoutHttpOnly.go:47:10:47:18 | "session" | CookieWithoutHttpOnly.go:46:7:49:2 | struct literal |
|
||||
| CookieWithoutHttpOnly.go:50:15:50:19 | false | CookieWithoutHttpOnly.go:46:7:49:2 | struct literal |
|
||||
| CookieWithoutHttpOnly.go:51:20:51:21 | &... | CookieWithoutHttpOnly.go:51:20:51:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:51:20:51:21 | &... | CookieWithoutHttpOnly.go:51:20:51:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:51:20:51:21 | &... | CookieWithoutHttpOnly.go:51:20:51:21 | &... |
|
||||
@@ -89,18 +98,16 @@ edges
|
||||
| CookieWithoutHttpOnly.go:51:20:51:21 | &... [pointer] | CookieWithoutHttpOnly.go:51:21:51:21 | c |
|
||||
| CookieWithoutHttpOnly.go:51:21:51:21 | c | CookieWithoutHttpOnly.go:51:20:51:21 | &... [pointer] |
|
||||
| CookieWithoutHttpOnly.go:51:21:51:21 | c | CookieWithoutHttpOnly.go:51:20:51:21 | &... [pointer] |
|
||||
| CookieWithoutHttpOnly.go:55:2:55:4 | definition of val | CookieWithoutHttpOnly.go:61:20:61:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:55:2:55:4 | definition of val | CookieWithoutHttpOnly.go:61:20:61:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:55:2:55:4 | definition of val | CookieWithoutHttpOnly.go:61:21:61:21 | c |
|
||||
| CookieWithoutHttpOnly.go:55:9:55:13 | false | CookieWithoutHttpOnly.go:61:20:61:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:55:9:55:13 | false | CookieWithoutHttpOnly.go:61:20:61:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:55:9:55:13 | false | CookieWithoutHttpOnly.go:61:21:61:21 | c |
|
||||
| CookieWithoutHttpOnly.go:57:13:57:21 | "session" | CookieWithoutHttpOnly.go:61:20:61:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:57:13:57:21 | "session" | CookieWithoutHttpOnly.go:61:20:61:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:57:13:57:21 | "session" | CookieWithoutHttpOnly.go:61:21:61:21 | c |
|
||||
| CookieWithoutHttpOnly.go:59:13:59:15 | val | CookieWithoutHttpOnly.go:61:20:61:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:59:13:59:15 | val | CookieWithoutHttpOnly.go:61:20:61:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:59:13:59:15 | val | CookieWithoutHttpOnly.go:61:21:61:21 | c |
|
||||
| CookieWithoutHttpOnly.go:55:2:55:4 | definition of val | CookieWithoutHttpOnly.go:59:13:59:15 | val |
|
||||
| CookieWithoutHttpOnly.go:55:9:55:13 | false | CookieWithoutHttpOnly.go:59:13:59:15 | val |
|
||||
| CookieWithoutHttpOnly.go:56:7:60:2 | struct literal | CookieWithoutHttpOnly.go:61:20:61:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:56:7:60:2 | struct literal | CookieWithoutHttpOnly.go:61:20:61:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:56:7:60:2 | struct literal | CookieWithoutHttpOnly.go:61:20:61:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:56:7:60:2 | struct literal | CookieWithoutHttpOnly.go:61:20:61:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:56:7:60:2 | struct literal | CookieWithoutHttpOnly.go:61:21:61:21 | c |
|
||||
| CookieWithoutHttpOnly.go:56:7:60:2 | struct literal | CookieWithoutHttpOnly.go:61:21:61:21 | c |
|
||||
| CookieWithoutHttpOnly.go:57:13:57:21 | "session" | CookieWithoutHttpOnly.go:56:7:60:2 | struct literal |
|
||||
| CookieWithoutHttpOnly.go:59:13:59:15 | val | CookieWithoutHttpOnly.go:56:7:60:2 | struct literal |
|
||||
| CookieWithoutHttpOnly.go:61:20:61:21 | &... | CookieWithoutHttpOnly.go:61:20:61:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:61:20:61:21 | &... | CookieWithoutHttpOnly.go:61:20:61:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:61:20:61:21 | &... | CookieWithoutHttpOnly.go:61:20:61:21 | &... |
|
||||
@@ -115,18 +122,16 @@ edges
|
||||
| CookieWithoutHttpOnly.go:61:20:61:21 | &... [pointer] | CookieWithoutHttpOnly.go:61:21:61:21 | c |
|
||||
| CookieWithoutHttpOnly.go:61:21:61:21 | c | CookieWithoutHttpOnly.go:61:20:61:21 | &... [pointer] |
|
||||
| CookieWithoutHttpOnly.go:61:21:61:21 | c | CookieWithoutHttpOnly.go:61:20:61:21 | &... [pointer] |
|
||||
| CookieWithoutHttpOnly.go:65:2:65:4 | definition of val | CookieWithoutHttpOnly.go:71:20:71:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:65:2:65:4 | definition of val | CookieWithoutHttpOnly.go:71:20:71:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:65:2:65:4 | definition of val | CookieWithoutHttpOnly.go:71:21:71:21 | c |
|
||||
| CookieWithoutHttpOnly.go:65:9:65:12 | true | CookieWithoutHttpOnly.go:71:20:71:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:65:9:65:12 | true | CookieWithoutHttpOnly.go:71:20:71:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:65:9:65:12 | true | CookieWithoutHttpOnly.go:71:21:71:21 | c |
|
||||
| CookieWithoutHttpOnly.go:67:13:67:21 | "session" | CookieWithoutHttpOnly.go:71:20:71:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:67:13:67:21 | "session" | CookieWithoutHttpOnly.go:71:20:71:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:67:13:67:21 | "session" | CookieWithoutHttpOnly.go:71:21:71:21 | c |
|
||||
| CookieWithoutHttpOnly.go:69:13:69:15 | val | CookieWithoutHttpOnly.go:71:20:71:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:69:13:69:15 | val | CookieWithoutHttpOnly.go:71:20:71:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:69:13:69:15 | val | CookieWithoutHttpOnly.go:71:21:71:21 | c |
|
||||
| CookieWithoutHttpOnly.go:65:2:65:4 | definition of val | CookieWithoutHttpOnly.go:69:13:69:15 | val |
|
||||
| CookieWithoutHttpOnly.go:65:9:65:12 | true | CookieWithoutHttpOnly.go:69:13:69:15 | val |
|
||||
| CookieWithoutHttpOnly.go:66:7:70:2 | struct literal | CookieWithoutHttpOnly.go:71:20:71:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:66:7:70:2 | struct literal | CookieWithoutHttpOnly.go:71:20:71:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:66:7:70:2 | struct literal | CookieWithoutHttpOnly.go:71:20:71:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:66:7:70:2 | struct literal | CookieWithoutHttpOnly.go:71:20:71:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:66:7:70:2 | struct literal | CookieWithoutHttpOnly.go:71:21:71:21 | c |
|
||||
| CookieWithoutHttpOnly.go:66:7:70:2 | struct literal | CookieWithoutHttpOnly.go:71:21:71:21 | c |
|
||||
| CookieWithoutHttpOnly.go:67:13:67:21 | "session" | CookieWithoutHttpOnly.go:66:7:70:2 | struct literal |
|
||||
| CookieWithoutHttpOnly.go:69:13:69:15 | val | CookieWithoutHttpOnly.go:66:7:70:2 | struct literal |
|
||||
| CookieWithoutHttpOnly.go:71:20:71:21 | &... | CookieWithoutHttpOnly.go:71:20:71:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:71:20:71:21 | &... | CookieWithoutHttpOnly.go:71:20:71:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:71:20:71:21 | &... | CookieWithoutHttpOnly.go:71:20:71:21 | &... |
|
||||
@@ -141,18 +146,16 @@ edges
|
||||
| CookieWithoutHttpOnly.go:71:20:71:21 | &... [pointer] | CookieWithoutHttpOnly.go:71:21:71:21 | c |
|
||||
| CookieWithoutHttpOnly.go:71:21:71:21 | c | CookieWithoutHttpOnly.go:71:20:71:21 | &... [pointer] |
|
||||
| CookieWithoutHttpOnly.go:71:21:71:21 | c | CookieWithoutHttpOnly.go:71:20:71:21 | &... [pointer] |
|
||||
| CookieWithoutHttpOnly.go:75:2:75:4 | definition of val | CookieWithoutHttpOnly.go:81:20:81:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:75:2:75:4 | definition of val | CookieWithoutHttpOnly.go:81:20:81:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:75:2:75:4 | definition of val | CookieWithoutHttpOnly.go:81:21:81:21 | c |
|
||||
| CookieWithoutHttpOnly.go:75:9:75:12 | true | CookieWithoutHttpOnly.go:81:20:81:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:75:9:75:12 | true | CookieWithoutHttpOnly.go:81:20:81:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:75:9:75:12 | true | CookieWithoutHttpOnly.go:81:21:81:21 | c |
|
||||
| CookieWithoutHttpOnly.go:77:10:77:18 | "session" | CookieWithoutHttpOnly.go:81:20:81:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:77:10:77:18 | "session" | CookieWithoutHttpOnly.go:81:20:81:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:77:10:77:18 | "session" | CookieWithoutHttpOnly.go:81:21:81:21 | c |
|
||||
| CookieWithoutHttpOnly.go:80:15:80:17 | val | CookieWithoutHttpOnly.go:81:20:81:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:80:15:80:17 | val | CookieWithoutHttpOnly.go:81:20:81:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:80:15:80:17 | val | CookieWithoutHttpOnly.go:81:21:81:21 | c |
|
||||
| CookieWithoutHttpOnly.go:75:2:75:4 | definition of val | CookieWithoutHttpOnly.go:80:15:80:17 | val |
|
||||
| CookieWithoutHttpOnly.go:75:9:75:12 | true | CookieWithoutHttpOnly.go:80:15:80:17 | val |
|
||||
| CookieWithoutHttpOnly.go:76:7:79:2 | struct literal | CookieWithoutHttpOnly.go:81:20:81:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:76:7:79:2 | struct literal | CookieWithoutHttpOnly.go:81:20:81:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:76:7:79:2 | struct literal | CookieWithoutHttpOnly.go:81:20:81:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:76:7:79:2 | struct literal | CookieWithoutHttpOnly.go:81:20:81:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:76:7:79:2 | struct literal | CookieWithoutHttpOnly.go:81:21:81:21 | c |
|
||||
| CookieWithoutHttpOnly.go:76:7:79:2 | struct literal | CookieWithoutHttpOnly.go:81:21:81:21 | c |
|
||||
| CookieWithoutHttpOnly.go:77:10:77:18 | "session" | CookieWithoutHttpOnly.go:76:7:79:2 | struct literal |
|
||||
| CookieWithoutHttpOnly.go:80:15:80:17 | val | CookieWithoutHttpOnly.go:76:7:79:2 | struct literal |
|
||||
| CookieWithoutHttpOnly.go:81:20:81:21 | &... | CookieWithoutHttpOnly.go:81:20:81:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:81:20:81:21 | &... | CookieWithoutHttpOnly.go:81:20:81:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:81:20:81:21 | &... | CookieWithoutHttpOnly.go:81:20:81:21 | &... |
|
||||
@@ -167,18 +170,16 @@ edges
|
||||
| CookieWithoutHttpOnly.go:81:20:81:21 | &... [pointer] | CookieWithoutHttpOnly.go:81:21:81:21 | c |
|
||||
| CookieWithoutHttpOnly.go:81:21:81:21 | c | CookieWithoutHttpOnly.go:81:20:81:21 | &... [pointer] |
|
||||
| CookieWithoutHttpOnly.go:81:21:81:21 | c | CookieWithoutHttpOnly.go:81:20:81:21 | &... [pointer] |
|
||||
| CookieWithoutHttpOnly.go:85:2:85:4 | definition of val | CookieWithoutHttpOnly.go:91:20:91:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:85:2:85:4 | definition of val | CookieWithoutHttpOnly.go:91:20:91:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:85:2:85:4 | definition of val | CookieWithoutHttpOnly.go:91:21:91:21 | c |
|
||||
| CookieWithoutHttpOnly.go:85:9:85:13 | false | CookieWithoutHttpOnly.go:91:20:91:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:85:9:85:13 | false | CookieWithoutHttpOnly.go:91:20:91:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:85:9:85:13 | false | CookieWithoutHttpOnly.go:91:21:91:21 | c |
|
||||
| CookieWithoutHttpOnly.go:87:10:87:18 | "session" | CookieWithoutHttpOnly.go:91:20:91:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:87:10:87:18 | "session" | CookieWithoutHttpOnly.go:91:20:91:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:87:10:87:18 | "session" | CookieWithoutHttpOnly.go:91:21:91:21 | c |
|
||||
| CookieWithoutHttpOnly.go:90:15:90:17 | val | CookieWithoutHttpOnly.go:91:20:91:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:90:15:90:17 | val | CookieWithoutHttpOnly.go:91:20:91:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:90:15:90:17 | val | CookieWithoutHttpOnly.go:91:21:91:21 | c |
|
||||
| CookieWithoutHttpOnly.go:85:2:85:4 | definition of val | CookieWithoutHttpOnly.go:90:15:90:17 | val |
|
||||
| CookieWithoutHttpOnly.go:85:9:85:13 | false | CookieWithoutHttpOnly.go:90:15:90:17 | val |
|
||||
| CookieWithoutHttpOnly.go:86:7:89:2 | struct literal | CookieWithoutHttpOnly.go:91:20:91:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:86:7:89:2 | struct literal | CookieWithoutHttpOnly.go:91:20:91:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:86:7:89:2 | struct literal | CookieWithoutHttpOnly.go:91:20:91:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:86:7:89:2 | struct literal | CookieWithoutHttpOnly.go:91:20:91:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:86:7:89:2 | struct literal | CookieWithoutHttpOnly.go:91:21:91:21 | c |
|
||||
| CookieWithoutHttpOnly.go:86:7:89:2 | struct literal | CookieWithoutHttpOnly.go:91:21:91:21 | c |
|
||||
| CookieWithoutHttpOnly.go:87:10:87:18 | "session" | CookieWithoutHttpOnly.go:86:7:89:2 | struct literal |
|
||||
| CookieWithoutHttpOnly.go:90:15:90:17 | val | CookieWithoutHttpOnly.go:86:7:89:2 | struct literal |
|
||||
| CookieWithoutHttpOnly.go:91:20:91:21 | &... | CookieWithoutHttpOnly.go:91:20:91:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:91:20:91:21 | &... | CookieWithoutHttpOnly.go:91:20:91:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:91:20:91:21 | &... | CookieWithoutHttpOnly.go:91:20:91:21 | &... |
|
||||
@@ -193,9 +194,10 @@ edges
|
||||
| CookieWithoutHttpOnly.go:91:20:91:21 | &... [pointer] | CookieWithoutHttpOnly.go:91:21:91:21 | c |
|
||||
| CookieWithoutHttpOnly.go:91:21:91:21 | c | CookieWithoutHttpOnly.go:91:20:91:21 | &... [pointer] |
|
||||
| CookieWithoutHttpOnly.go:91:21:91:21 | c | CookieWithoutHttpOnly.go:91:20:91:21 | &... [pointer] |
|
||||
| CookieWithoutHttpOnly.go:99:15:99:19 | false | CookieWithoutHttpOnly.go:100:20:100:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:99:15:99:19 | false | CookieWithoutHttpOnly.go:100:20:100:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:99:15:99:19 | false | CookieWithoutHttpOnly.go:100:21:100:21 | c |
|
||||
| CookieWithoutHttpOnly.go:95:7:98:2 | struct literal | CookieWithoutHttpOnly.go:100:20:100:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:95:7:98:2 | struct literal | CookieWithoutHttpOnly.go:100:20:100:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:95:7:98:2 | struct literal | CookieWithoutHttpOnly.go:100:21:100:21 | c |
|
||||
| CookieWithoutHttpOnly.go:99:15:99:19 | false | CookieWithoutHttpOnly.go:95:7:98:2 | struct literal |
|
||||
| CookieWithoutHttpOnly.go:100:20:100:21 | &... | CookieWithoutHttpOnly.go:100:20:100:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:100:20:100:21 | &... | CookieWithoutHttpOnly.go:100:20:100:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:100:20:100:21 | &... | CookieWithoutHttpOnly.go:100:21:100:21 | c |
|
||||
@@ -203,12 +205,15 @@ edges
|
||||
| CookieWithoutHttpOnly.go:100:20:100:21 | &... [pointer] | CookieWithoutHttpOnly.go:100:20:100:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:100:20:100:21 | &... [pointer] | CookieWithoutHttpOnly.go:100:21:100:21 | c |
|
||||
| CookieWithoutHttpOnly.go:100:21:100:21 | c | CookieWithoutHttpOnly.go:100:20:100:21 | &... [pointer] |
|
||||
| CookieWithoutHttpOnly.go:104:10:104:18 | "session" | CookieWithoutHttpOnly.go:110:20:110:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:104:10:104:18 | "session" | CookieWithoutHttpOnly.go:110:20:110:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:104:10:104:18 | "session" | CookieWithoutHttpOnly.go:110:21:110:21 | c |
|
||||
| CookieWithoutHttpOnly.go:109:15:109:19 | false | CookieWithoutHttpOnly.go:110:20:110:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:109:15:109:19 | false | CookieWithoutHttpOnly.go:110:20:110:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:109:15:109:19 | false | CookieWithoutHttpOnly.go:110:21:110:21 | c |
|
||||
| CookieWithoutHttpOnly.go:104:10:104:18 | "session" | CookieWithoutHttpOnly.go:106:10:106:13 | name |
|
||||
| CookieWithoutHttpOnly.go:105:7:108:2 | struct literal | CookieWithoutHttpOnly.go:110:20:110:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:105:7:108:2 | struct literal | CookieWithoutHttpOnly.go:110:20:110:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:105:7:108:2 | struct literal | CookieWithoutHttpOnly.go:110:20:110:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:105:7:108:2 | struct literal | CookieWithoutHttpOnly.go:110:20:110:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:105:7:108:2 | struct literal | CookieWithoutHttpOnly.go:110:21:110:21 | c |
|
||||
| CookieWithoutHttpOnly.go:105:7:108:2 | struct literal | CookieWithoutHttpOnly.go:110:21:110:21 | c |
|
||||
| CookieWithoutHttpOnly.go:106:10:106:13 | name | CookieWithoutHttpOnly.go:105:7:108:2 | struct literal |
|
||||
| CookieWithoutHttpOnly.go:109:15:109:19 | false | CookieWithoutHttpOnly.go:105:7:108:2 | struct literal |
|
||||
| CookieWithoutHttpOnly.go:110:20:110:21 | &... | CookieWithoutHttpOnly.go:110:20:110:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:110:20:110:21 | &... | CookieWithoutHttpOnly.go:110:20:110:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:110:20:110:21 | &... | CookieWithoutHttpOnly.go:110:20:110:21 | &... |
|
||||
@@ -223,15 +228,15 @@ edges
|
||||
| CookieWithoutHttpOnly.go:110:20:110:21 | &... [pointer] | CookieWithoutHttpOnly.go:110:21:110:21 | c |
|
||||
| CookieWithoutHttpOnly.go:110:21:110:21 | c | CookieWithoutHttpOnly.go:110:20:110:21 | &... [pointer] |
|
||||
| CookieWithoutHttpOnly.go:110:21:110:21 | c | CookieWithoutHttpOnly.go:110:20:110:21 | &... [pointer] |
|
||||
| CookieWithoutHttpOnly.go:114:13:114:24 | "login_name" | CookieWithoutHttpOnly.go:120:20:120:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:114:13:114:24 | "login_name" | CookieWithoutHttpOnly.go:120:20:120:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:114:13:114:24 | "login_name" | CookieWithoutHttpOnly.go:120:21:120:21 | c |
|
||||
| CookieWithoutHttpOnly.go:116:10:116:16 | session | CookieWithoutHttpOnly.go:120:20:120:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:116:10:116:16 | session | CookieWithoutHttpOnly.go:120:20:120:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:116:10:116:16 | session | CookieWithoutHttpOnly.go:120:21:120:21 | c |
|
||||
| CookieWithoutHttpOnly.go:119:15:119:19 | false | CookieWithoutHttpOnly.go:120:20:120:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:119:15:119:19 | false | CookieWithoutHttpOnly.go:120:20:120:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:119:15:119:19 | false | CookieWithoutHttpOnly.go:120:21:120:21 | c |
|
||||
| CookieWithoutHttpOnly.go:114:13:114:24 | "login_name" | CookieWithoutHttpOnly.go:116:10:116:16 | session |
|
||||
| CookieWithoutHttpOnly.go:115:7:118:2 | struct literal | CookieWithoutHttpOnly.go:120:20:120:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:115:7:118:2 | struct literal | CookieWithoutHttpOnly.go:120:20:120:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:115:7:118:2 | struct literal | CookieWithoutHttpOnly.go:120:20:120:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:115:7:118:2 | struct literal | CookieWithoutHttpOnly.go:120:20:120:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:115:7:118:2 | struct literal | CookieWithoutHttpOnly.go:120:21:120:21 | c |
|
||||
| CookieWithoutHttpOnly.go:115:7:118:2 | struct literal | CookieWithoutHttpOnly.go:120:21:120:21 | c |
|
||||
| CookieWithoutHttpOnly.go:116:10:116:16 | session | CookieWithoutHttpOnly.go:115:7:118:2 | struct literal |
|
||||
| CookieWithoutHttpOnly.go:119:15:119:19 | false | CookieWithoutHttpOnly.go:115:7:118:2 | struct literal |
|
||||
| CookieWithoutHttpOnly.go:120:20:120:21 | &... | CookieWithoutHttpOnly.go:120:20:120:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:120:20:120:21 | &... | CookieWithoutHttpOnly.go:120:20:120:21 | &... |
|
||||
| CookieWithoutHttpOnly.go:120:20:120:21 | &... | CookieWithoutHttpOnly.go:120:20:120:21 | &... |
|
||||
@@ -253,26 +258,24 @@ edges
|
||||
| CookieWithoutHttpOnly.go:123:13:123:49 | call to NewCookieStore | CookieWithoutHttpOnly.go:170:16:170:20 | store |
|
||||
| CookieWithoutHttpOnly.go:123:13:123:49 | call to NewCookieStore | CookieWithoutHttpOnly.go:183:16:183:20 | store |
|
||||
| CookieWithoutHttpOnly.go:123:13:123:49 | call to NewCookieStore | CookieWithoutHttpOnly.go:195:16:195:20 | store |
|
||||
| CookieWithoutHttpOnly.go:126:16:126:20 | store | CookieWithoutHttpOnly.go:129:2:129:8 | session |
|
||||
| CookieWithoutHttpOnly.go:133:2:133:9 | definition of httpOnly | CookieWithoutHttpOnly.go:135:2:135:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:133:2:133:9 | definition of httpOnly | CookieWithoutHttpOnly.go:137:2:137:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:133:2:133:9 | definition of httpOnly | CookieWithoutHttpOnly.go:142:2:142:8 | session |
|
||||
| CookieWithoutHttpOnly.go:133:14:133:18 | false | CookieWithoutHttpOnly.go:135:2:135:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:133:14:133:18 | false | CookieWithoutHttpOnly.go:137:2:137:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:133:14:133:18 | false | CookieWithoutHttpOnly.go:142:2:142:8 | session |
|
||||
| CookieWithoutHttpOnly.go:126:2:126:43 | ... := ...[0] | CookieWithoutHttpOnly.go:129:2:129:8 | session |
|
||||
| CookieWithoutHttpOnly.go:126:16:126:20 | store | CookieWithoutHttpOnly.go:126:2:126:43 | ... := ...[0] |
|
||||
| CookieWithoutHttpOnly.go:133:2:133:9 | definition of httpOnly | CookieWithoutHttpOnly.go:139:13:139:20 | httpOnly |
|
||||
| CookieWithoutHttpOnly.go:133:14:133:18 | false | CookieWithoutHttpOnly.go:139:13:139:20 | httpOnly |
|
||||
| CookieWithoutHttpOnly.go:134:2:134:8 | definition of session [pointer] | CookieWithoutHttpOnly.go:135:2:135:8 | session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:134:2:134:8 | definition of session [pointer] | CookieWithoutHttpOnly.go:135:2:135:8 | session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:134:2:134:8 | definition of session [pointer] | CookieWithoutHttpOnly.go:137:2:137:8 | session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:134:2:134:8 | definition of session [pointer] | CookieWithoutHttpOnly.go:137:2:137:8 | session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:134:2:134:8 | definition of session [pointer] | CookieWithoutHttpOnly.go:142:2:142:8 | session |
|
||||
| CookieWithoutHttpOnly.go:134:2:134:8 | definition of session [pointer] | CookieWithoutHttpOnly.go:142:2:142:8 | session |
|
||||
| CookieWithoutHttpOnly.go:134:16:134:20 | store | CookieWithoutHttpOnly.go:142:2:142:8 | session |
|
||||
| CookieWithoutHttpOnly.go:134:2:134:43 | ... := ...[0] | CookieWithoutHttpOnly.go:142:2:142:8 | session |
|
||||
| CookieWithoutHttpOnly.go:134:16:134:20 | store | CookieWithoutHttpOnly.go:134:2:134:43 | ... := ...[0] |
|
||||
| CookieWithoutHttpOnly.go:135:2:135:8 | implicit dereference | CookieWithoutHttpOnly.go:134:2:134:8 | definition of session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:135:2:135:8 | implicit dereference | CookieWithoutHttpOnly.go:134:2:134:8 | definition of session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:135:2:135:8 | implicit dereference | CookieWithoutHttpOnly.go:135:2:135:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:135:2:135:8 | implicit dereference | CookieWithoutHttpOnly.go:135:2:135:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:135:2:135:8 | implicit dereference | CookieWithoutHttpOnly.go:137:2:137:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:135:2:135:8 | implicit dereference | CookieWithoutHttpOnly.go:137:2:137:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:135:2:135:8 | implicit dereference | CookieWithoutHttpOnly.go:137:2:137:8 | session |
|
||||
| CookieWithoutHttpOnly.go:135:2:135:8 | implicit dereference | CookieWithoutHttpOnly.go:137:2:137:8 | session |
|
||||
| CookieWithoutHttpOnly.go:135:2:135:8 | implicit dereference | CookieWithoutHttpOnly.go:142:2:142:8 | session |
|
||||
| CookieWithoutHttpOnly.go:135:2:135:8 | implicit dereference | CookieWithoutHttpOnly.go:142:2:142:8 | session |
|
||||
| CookieWithoutHttpOnly.go:135:2:135:8 | session [pointer] | CookieWithoutHttpOnly.go:135:2:135:8 | implicit dereference |
|
||||
@@ -281,54 +284,59 @@ edges
|
||||
| CookieWithoutHttpOnly.go:137:2:137:8 | implicit dereference | CookieWithoutHttpOnly.go:134:2:134:8 | definition of session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:137:2:137:8 | implicit dereference | CookieWithoutHttpOnly.go:135:2:135:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:137:2:137:8 | implicit dereference | CookieWithoutHttpOnly.go:135:2:135:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:137:2:137:8 | implicit dereference | CookieWithoutHttpOnly.go:137:2:137:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:137:2:137:8 | implicit dereference | CookieWithoutHttpOnly.go:137:2:137:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:137:2:137:8 | implicit dereference | CookieWithoutHttpOnly.go:137:2:137:8 | session |
|
||||
| CookieWithoutHttpOnly.go:137:2:137:8 | implicit dereference | CookieWithoutHttpOnly.go:137:2:137:8 | session |
|
||||
| CookieWithoutHttpOnly.go:137:2:137:8 | implicit dereference | CookieWithoutHttpOnly.go:142:2:142:8 | session |
|
||||
| CookieWithoutHttpOnly.go:137:2:137:8 | implicit dereference | CookieWithoutHttpOnly.go:142:2:142:8 | session |
|
||||
| CookieWithoutHttpOnly.go:137:2:137:8 | session | CookieWithoutHttpOnly.go:137:2:137:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:137:2:137:8 | session | CookieWithoutHttpOnly.go:137:2:137:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:137:2:137:8 | session [pointer] | CookieWithoutHttpOnly.go:137:2:137:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:137:2:137:8 | session [pointer] | CookieWithoutHttpOnly.go:137:2:137:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:137:21:140:2 | struct literal | CookieWithoutHttpOnly.go:135:2:135:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:137:21:140:2 | struct literal | CookieWithoutHttpOnly.go:137:2:137:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:137:21:140:2 | struct literal | CookieWithoutHttpOnly.go:142:2:142:8 | session |
|
||||
| CookieWithoutHttpOnly.go:139:13:139:20 | httpOnly | CookieWithoutHttpOnly.go:135:2:135:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:139:13:139:20 | httpOnly | CookieWithoutHttpOnly.go:137:2:137:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:139:13:139:20 | httpOnly | CookieWithoutHttpOnly.go:142:2:142:8 | session |
|
||||
| CookieWithoutHttpOnly.go:137:20:140:2 | &... | CookieWithoutHttpOnly.go:137:2:137:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:137:20:140:2 | &... | CookieWithoutHttpOnly.go:137:2:137:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:137:20:140:2 | &... | CookieWithoutHttpOnly.go:137:2:137:8 | session |
|
||||
| CookieWithoutHttpOnly.go:137:20:140:2 | &... | CookieWithoutHttpOnly.go:137:2:137:8 | session |
|
||||
| CookieWithoutHttpOnly.go:137:20:140:2 | &... | CookieWithoutHttpOnly.go:137:20:140:2 | &... |
|
||||
| CookieWithoutHttpOnly.go:137:20:140:2 | &... | CookieWithoutHttpOnly.go:137:21:140:2 | struct literal |
|
||||
| CookieWithoutHttpOnly.go:137:21:140:2 | struct literal | CookieWithoutHttpOnly.go:137:20:140:2 | &... |
|
||||
| CookieWithoutHttpOnly.go:137:21:140:2 | struct literal | CookieWithoutHttpOnly.go:137:20:140:2 | &... |
|
||||
| CookieWithoutHttpOnly.go:139:13:139:20 | httpOnly | CookieWithoutHttpOnly.go:137:21:140:2 | struct literal |
|
||||
| CookieWithoutHttpOnly.go:146:2:146:8 | definition of session [pointer] | CookieWithoutHttpOnly.go:147:2:147:8 | session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:146:2:146:8 | definition of session [pointer] | CookieWithoutHttpOnly.go:149:2:149:8 | session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:146:2:146:8 | definition of session [pointer] | CookieWithoutHttpOnly.go:153:2:153:8 | session |
|
||||
| CookieWithoutHttpOnly.go:146:16:146:20 | store | CookieWithoutHttpOnly.go:153:2:153:8 | session |
|
||||
| CookieWithoutHttpOnly.go:146:2:146:43 | ... := ...[0] | CookieWithoutHttpOnly.go:153:2:153:8 | session |
|
||||
| CookieWithoutHttpOnly.go:146:16:146:20 | store | CookieWithoutHttpOnly.go:146:2:146:43 | ... := ...[0] |
|
||||
| CookieWithoutHttpOnly.go:147:2:147:8 | implicit dereference | CookieWithoutHttpOnly.go:146:2:146:8 | definition of session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:147:2:147:8 | implicit dereference | CookieWithoutHttpOnly.go:147:2:147:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:147:2:147:8 | implicit dereference | CookieWithoutHttpOnly.go:149:2:149:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:147:2:147:8 | implicit dereference | CookieWithoutHttpOnly.go:149:2:149:8 | session |
|
||||
| CookieWithoutHttpOnly.go:147:2:147:8 | implicit dereference | CookieWithoutHttpOnly.go:153:2:153:8 | session |
|
||||
| CookieWithoutHttpOnly.go:147:2:147:8 | session [pointer] | CookieWithoutHttpOnly.go:147:2:147:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:149:2:149:8 | implicit dereference | CookieWithoutHttpOnly.go:146:2:146:8 | definition of session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:149:2:149:8 | implicit dereference | CookieWithoutHttpOnly.go:147:2:147:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:149:2:149:8 | implicit dereference | CookieWithoutHttpOnly.go:149:2:149:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:149:2:149:8 | implicit dereference | CookieWithoutHttpOnly.go:149:2:149:8 | session |
|
||||
| CookieWithoutHttpOnly.go:149:2:149:8 | implicit dereference | CookieWithoutHttpOnly.go:153:2:153:8 | session |
|
||||
| CookieWithoutHttpOnly.go:149:2:149:8 | session | CookieWithoutHttpOnly.go:149:2:149:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:149:2:149:8 | session [pointer] | CookieWithoutHttpOnly.go:149:2:149:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:149:21:151:2 | struct literal | CookieWithoutHttpOnly.go:147:2:147:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:149:21:151:2 | struct literal | CookieWithoutHttpOnly.go:149:2:149:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:149:21:151:2 | struct literal | CookieWithoutHttpOnly.go:153:2:153:8 | session |
|
||||
| CookieWithoutHttpOnly.go:157:2:157:9 | definition of httpOnly | CookieWithoutHttpOnly.go:159:2:159:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:157:2:157:9 | definition of httpOnly | CookieWithoutHttpOnly.go:161:2:161:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:157:2:157:9 | definition of httpOnly | CookieWithoutHttpOnly.go:166:2:166:8 | session |
|
||||
| CookieWithoutHttpOnly.go:157:14:157:17 | true | CookieWithoutHttpOnly.go:159:2:159:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:157:14:157:17 | true | CookieWithoutHttpOnly.go:161:2:161:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:157:14:157:17 | true | CookieWithoutHttpOnly.go:166:2:166:8 | session |
|
||||
| CookieWithoutHttpOnly.go:149:20:151:2 | &... | CookieWithoutHttpOnly.go:149:2:149:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:149:20:151:2 | &... | CookieWithoutHttpOnly.go:149:2:149:8 | session |
|
||||
| CookieWithoutHttpOnly.go:149:20:151:2 | &... | CookieWithoutHttpOnly.go:149:20:151:2 | &... |
|
||||
| CookieWithoutHttpOnly.go:149:21:151:2 | struct literal | CookieWithoutHttpOnly.go:149:20:151:2 | &... |
|
||||
| CookieWithoutHttpOnly.go:157:2:157:9 | definition of httpOnly | CookieWithoutHttpOnly.go:163:13:163:20 | httpOnly |
|
||||
| CookieWithoutHttpOnly.go:157:14:157:17 | true | CookieWithoutHttpOnly.go:163:13:163:20 | httpOnly |
|
||||
| CookieWithoutHttpOnly.go:158:2:158:8 | definition of session [pointer] | CookieWithoutHttpOnly.go:159:2:159:8 | session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:158:2:158:8 | definition of session [pointer] | CookieWithoutHttpOnly.go:159:2:159:8 | session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:158:2:158:8 | definition of session [pointer] | CookieWithoutHttpOnly.go:161:2:161:8 | session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:158:2:158:8 | definition of session [pointer] | CookieWithoutHttpOnly.go:161:2:161:8 | session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:158:2:158:8 | definition of session [pointer] | CookieWithoutHttpOnly.go:166:2:166:8 | session |
|
||||
| CookieWithoutHttpOnly.go:158:2:158:8 | definition of session [pointer] | CookieWithoutHttpOnly.go:166:2:166:8 | session |
|
||||
| CookieWithoutHttpOnly.go:158:16:158:20 | store | CookieWithoutHttpOnly.go:166:2:166:8 | session |
|
||||
| CookieWithoutHttpOnly.go:158:2:158:43 | ... := ...[0] | CookieWithoutHttpOnly.go:166:2:166:8 | session |
|
||||
| CookieWithoutHttpOnly.go:158:16:158:20 | store | CookieWithoutHttpOnly.go:158:2:158:43 | ... := ...[0] |
|
||||
| CookieWithoutHttpOnly.go:159:2:159:8 | implicit dereference | CookieWithoutHttpOnly.go:158:2:158:8 | definition of session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:159:2:159:8 | implicit dereference | CookieWithoutHttpOnly.go:158:2:158:8 | definition of session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:159:2:159:8 | implicit dereference | CookieWithoutHttpOnly.go:159:2:159:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:159:2:159:8 | implicit dereference | CookieWithoutHttpOnly.go:159:2:159:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:159:2:159:8 | implicit dereference | CookieWithoutHttpOnly.go:161:2:161:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:159:2:159:8 | implicit dereference | CookieWithoutHttpOnly.go:161:2:161:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:159:2:159:8 | implicit dereference | CookieWithoutHttpOnly.go:161:2:161:8 | session |
|
||||
| CookieWithoutHttpOnly.go:159:2:159:8 | implicit dereference | CookieWithoutHttpOnly.go:161:2:161:8 | session |
|
||||
| CookieWithoutHttpOnly.go:159:2:159:8 | implicit dereference | CookieWithoutHttpOnly.go:166:2:166:8 | session |
|
||||
| CookieWithoutHttpOnly.go:159:2:159:8 | implicit dereference | CookieWithoutHttpOnly.go:166:2:166:8 | session |
|
||||
| CookieWithoutHttpOnly.go:159:2:159:8 | session [pointer] | CookieWithoutHttpOnly.go:159:2:159:8 | implicit dereference |
|
||||
@@ -337,37 +345,39 @@ edges
|
||||
| CookieWithoutHttpOnly.go:161:2:161:8 | implicit dereference | CookieWithoutHttpOnly.go:158:2:158:8 | definition of session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:161:2:161:8 | implicit dereference | CookieWithoutHttpOnly.go:159:2:159:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:161:2:161:8 | implicit dereference | CookieWithoutHttpOnly.go:159:2:159:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:161:2:161:8 | implicit dereference | CookieWithoutHttpOnly.go:161:2:161:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:161:2:161:8 | implicit dereference | CookieWithoutHttpOnly.go:161:2:161:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:161:2:161:8 | implicit dereference | CookieWithoutHttpOnly.go:161:2:161:8 | session |
|
||||
| CookieWithoutHttpOnly.go:161:2:161:8 | implicit dereference | CookieWithoutHttpOnly.go:161:2:161:8 | session |
|
||||
| CookieWithoutHttpOnly.go:161:2:161:8 | implicit dereference | CookieWithoutHttpOnly.go:166:2:166:8 | session |
|
||||
| CookieWithoutHttpOnly.go:161:2:161:8 | implicit dereference | CookieWithoutHttpOnly.go:166:2:166:8 | session |
|
||||
| CookieWithoutHttpOnly.go:161:2:161:8 | session | CookieWithoutHttpOnly.go:161:2:161:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:161:2:161:8 | session | CookieWithoutHttpOnly.go:161:2:161:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:161:2:161:8 | session [pointer] | CookieWithoutHttpOnly.go:161:2:161:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:161:2:161:8 | session [pointer] | CookieWithoutHttpOnly.go:161:2:161:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:161:21:164:2 | struct literal | CookieWithoutHttpOnly.go:159:2:159:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:161:21:164:2 | struct literal | CookieWithoutHttpOnly.go:161:2:161:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:161:21:164:2 | struct literal | CookieWithoutHttpOnly.go:166:2:166:8 | session |
|
||||
| CookieWithoutHttpOnly.go:163:13:163:20 | httpOnly | CookieWithoutHttpOnly.go:159:2:159:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:163:13:163:20 | httpOnly | CookieWithoutHttpOnly.go:161:2:161:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:163:13:163:20 | httpOnly | CookieWithoutHttpOnly.go:166:2:166:8 | session |
|
||||
| CookieWithoutHttpOnly.go:169:56:169:63 | argument corresponding to httpOnly | CookieWithoutHttpOnly.go:171:2:171:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:169:56:169:63 | argument corresponding to httpOnly | CookieWithoutHttpOnly.go:173:2:173:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:169:56:169:63 | argument corresponding to httpOnly | CookieWithoutHttpOnly.go:178:2:178:8 | session |
|
||||
| CookieWithoutHttpOnly.go:169:56:169:63 | definition of httpOnly | CookieWithoutHttpOnly.go:171:2:171:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:169:56:169:63 | definition of httpOnly | CookieWithoutHttpOnly.go:173:2:173:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:169:56:169:63 | definition of httpOnly | CookieWithoutHttpOnly.go:178:2:178:8 | session |
|
||||
| CookieWithoutHttpOnly.go:161:20:164:2 | &... | CookieWithoutHttpOnly.go:161:2:161:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:161:20:164:2 | &... | CookieWithoutHttpOnly.go:161:2:161:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:161:20:164:2 | &... | CookieWithoutHttpOnly.go:161:2:161:8 | session |
|
||||
| CookieWithoutHttpOnly.go:161:20:164:2 | &... | CookieWithoutHttpOnly.go:161:2:161:8 | session |
|
||||
| CookieWithoutHttpOnly.go:161:20:164:2 | &... | CookieWithoutHttpOnly.go:161:20:164:2 | &... |
|
||||
| CookieWithoutHttpOnly.go:161:20:164:2 | &... | CookieWithoutHttpOnly.go:161:21:164:2 | struct literal |
|
||||
| CookieWithoutHttpOnly.go:161:21:164:2 | struct literal | CookieWithoutHttpOnly.go:161:20:164:2 | &... |
|
||||
| CookieWithoutHttpOnly.go:161:21:164:2 | struct literal | CookieWithoutHttpOnly.go:161:20:164:2 | &... |
|
||||
| CookieWithoutHttpOnly.go:163:13:163:20 | httpOnly | CookieWithoutHttpOnly.go:161:21:164:2 | struct literal |
|
||||
| CookieWithoutHttpOnly.go:169:56:169:63 | argument corresponding to httpOnly | CookieWithoutHttpOnly.go:175:13:175:20 | httpOnly |
|
||||
| CookieWithoutHttpOnly.go:169:56:169:63 | definition of httpOnly | CookieWithoutHttpOnly.go:175:13:175:20 | httpOnly |
|
||||
| CookieWithoutHttpOnly.go:170:2:170:8 | definition of session [pointer] | CookieWithoutHttpOnly.go:171:2:171:8 | session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:170:2:170:8 | definition of session [pointer] | CookieWithoutHttpOnly.go:171:2:171:8 | session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:170:2:170:8 | definition of session [pointer] | CookieWithoutHttpOnly.go:173:2:173:8 | session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:170:2:170:8 | definition of session [pointer] | CookieWithoutHttpOnly.go:173:2:173:8 | session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:170:2:170:8 | definition of session [pointer] | CookieWithoutHttpOnly.go:178:2:178:8 | session |
|
||||
| CookieWithoutHttpOnly.go:170:2:170:8 | definition of session [pointer] | CookieWithoutHttpOnly.go:178:2:178:8 | session |
|
||||
| CookieWithoutHttpOnly.go:170:16:170:20 | store | CookieWithoutHttpOnly.go:178:2:178:8 | session |
|
||||
| CookieWithoutHttpOnly.go:170:2:170:43 | ... := ...[0] | CookieWithoutHttpOnly.go:178:2:178:8 | session |
|
||||
| CookieWithoutHttpOnly.go:170:16:170:20 | store | CookieWithoutHttpOnly.go:170:2:170:43 | ... := ...[0] |
|
||||
| CookieWithoutHttpOnly.go:171:2:171:8 | implicit dereference | CookieWithoutHttpOnly.go:170:2:170:8 | definition of session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:171:2:171:8 | implicit dereference | CookieWithoutHttpOnly.go:170:2:170:8 | definition of session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:171:2:171:8 | implicit dereference | CookieWithoutHttpOnly.go:171:2:171:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:171:2:171:8 | implicit dereference | CookieWithoutHttpOnly.go:171:2:171:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:171:2:171:8 | implicit dereference | CookieWithoutHttpOnly.go:173:2:173:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:171:2:171:8 | implicit dereference | CookieWithoutHttpOnly.go:173:2:173:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:171:2:171:8 | implicit dereference | CookieWithoutHttpOnly.go:173:2:173:8 | session |
|
||||
| CookieWithoutHttpOnly.go:171:2:171:8 | implicit dereference | CookieWithoutHttpOnly.go:173:2:173:8 | session |
|
||||
| CookieWithoutHttpOnly.go:171:2:171:8 | implicit dereference | CookieWithoutHttpOnly.go:178:2:178:8 | session |
|
||||
| CookieWithoutHttpOnly.go:171:2:171:8 | implicit dereference | CookieWithoutHttpOnly.go:178:2:178:8 | session |
|
||||
| CookieWithoutHttpOnly.go:171:2:171:8 | session [pointer] | CookieWithoutHttpOnly.go:171:2:171:8 | implicit dereference |
|
||||
@@ -376,26 +386,36 @@ edges
|
||||
| CookieWithoutHttpOnly.go:173:2:173:8 | implicit dereference | CookieWithoutHttpOnly.go:170:2:170:8 | definition of session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:173:2:173:8 | implicit dereference | CookieWithoutHttpOnly.go:171:2:171:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:173:2:173:8 | implicit dereference | CookieWithoutHttpOnly.go:171:2:171:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:173:2:173:8 | implicit dereference | CookieWithoutHttpOnly.go:173:2:173:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:173:2:173:8 | implicit dereference | CookieWithoutHttpOnly.go:173:2:173:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:173:2:173:8 | implicit dereference | CookieWithoutHttpOnly.go:173:2:173:8 | session |
|
||||
| CookieWithoutHttpOnly.go:173:2:173:8 | implicit dereference | CookieWithoutHttpOnly.go:173:2:173:8 | session |
|
||||
| CookieWithoutHttpOnly.go:173:2:173:8 | implicit dereference | CookieWithoutHttpOnly.go:178:2:178:8 | session |
|
||||
| CookieWithoutHttpOnly.go:173:2:173:8 | implicit dereference | CookieWithoutHttpOnly.go:178:2:178:8 | session |
|
||||
| CookieWithoutHttpOnly.go:173:2:173:8 | session | CookieWithoutHttpOnly.go:173:2:173:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:173:2:173:8 | session | CookieWithoutHttpOnly.go:173:2:173:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:173:2:173:8 | session [pointer] | CookieWithoutHttpOnly.go:173:2:173:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:173:2:173:8 | session [pointer] | CookieWithoutHttpOnly.go:173:2:173:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:173:21:176:2 | struct literal | CookieWithoutHttpOnly.go:171:2:171:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:173:21:176:2 | struct literal | CookieWithoutHttpOnly.go:173:2:173:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:173:21:176:2 | struct literal | CookieWithoutHttpOnly.go:178:2:178:8 | session |
|
||||
| CookieWithoutHttpOnly.go:175:13:175:20 | httpOnly | CookieWithoutHttpOnly.go:171:2:171:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:175:13:175:20 | httpOnly | CookieWithoutHttpOnly.go:173:2:173:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:175:13:175:20 | httpOnly | CookieWithoutHttpOnly.go:178:2:178:8 | session |
|
||||
| CookieWithoutHttpOnly.go:183:16:183:20 | store | CookieWithoutHttpOnly.go:191:19:191:25 | session |
|
||||
| CookieWithoutHttpOnly.go:195:16:195:20 | store | CookieWithoutHttpOnly.go:202:19:202:25 | session |
|
||||
| CookieWithoutHttpOnly.go:173:20:176:2 | &... | CookieWithoutHttpOnly.go:173:2:173:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:173:20:176:2 | &... | CookieWithoutHttpOnly.go:173:2:173:8 | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:173:20:176:2 | &... | CookieWithoutHttpOnly.go:173:2:173:8 | session |
|
||||
| CookieWithoutHttpOnly.go:173:20:176:2 | &... | CookieWithoutHttpOnly.go:173:2:173:8 | session |
|
||||
| CookieWithoutHttpOnly.go:173:20:176:2 | &... | CookieWithoutHttpOnly.go:173:20:176:2 | &... |
|
||||
| CookieWithoutHttpOnly.go:173:20:176:2 | &... | CookieWithoutHttpOnly.go:173:21:176:2 | struct literal |
|
||||
| CookieWithoutHttpOnly.go:173:21:176:2 | struct literal | CookieWithoutHttpOnly.go:173:20:176:2 | &... |
|
||||
| CookieWithoutHttpOnly.go:173:21:176:2 | struct literal | CookieWithoutHttpOnly.go:173:20:176:2 | &... |
|
||||
| CookieWithoutHttpOnly.go:175:13:175:20 | httpOnly | CookieWithoutHttpOnly.go:173:21:176:2 | struct literal |
|
||||
| CookieWithoutHttpOnly.go:183:2:183:43 | ... := ...[0] | CookieWithoutHttpOnly.go:191:19:191:25 | session |
|
||||
| CookieWithoutHttpOnly.go:183:16:183:20 | store | CookieWithoutHttpOnly.go:183:2:183:43 | ... := ...[0] |
|
||||
| CookieWithoutHttpOnly.go:195:2:195:43 | ... := ...[0] | CookieWithoutHttpOnly.go:202:19:202:25 | session |
|
||||
| CookieWithoutHttpOnly.go:195:16:195:20 | store | CookieWithoutHttpOnly.go:195:2:195:43 | ... := ...[0] |
|
||||
nodes
|
||||
| CookieWithoutHttpOnly.go:11:7:14:2 | struct literal | semmle.label | struct literal |
|
||||
| CookieWithoutHttpOnly.go:12:10:12:18 | "session" | semmle.label | "session" |
|
||||
| CookieWithoutHttpOnly.go:15:20:15:21 | &... | semmle.label | &... |
|
||||
| CookieWithoutHttpOnly.go:15:20:15:21 | &... | semmle.label | &... |
|
||||
| CookieWithoutHttpOnly.go:15:20:15:21 | &... [pointer] | semmle.label | &... [pointer] |
|
||||
| CookieWithoutHttpOnly.go:15:21:15:21 | c | semmle.label | c |
|
||||
| CookieWithoutHttpOnly.go:19:7:23:2 | struct literal | semmle.label | struct literal |
|
||||
| CookieWithoutHttpOnly.go:19:7:23:2 | struct literal | semmle.label | struct literal |
|
||||
| CookieWithoutHttpOnly.go:20:13:20:21 | "session" | semmle.label | "session" |
|
||||
| CookieWithoutHttpOnly.go:22:13:22:17 | false | semmle.label | false |
|
||||
| CookieWithoutHttpOnly.go:24:20:24:21 | &... | semmle.label | &... |
|
||||
@@ -406,6 +426,8 @@ nodes
|
||||
| CookieWithoutHttpOnly.go:24:20:24:21 | &... [pointer] | semmle.label | &... [pointer] |
|
||||
| CookieWithoutHttpOnly.go:24:21:24:21 | c | semmle.label | c |
|
||||
| CookieWithoutHttpOnly.go:24:21:24:21 | c | semmle.label | c |
|
||||
| CookieWithoutHttpOnly.go:28:7:32:2 | struct literal | semmle.label | struct literal |
|
||||
| CookieWithoutHttpOnly.go:28:7:32:2 | struct literal | semmle.label | struct literal |
|
||||
| CookieWithoutHttpOnly.go:29:13:29:21 | "session" | semmle.label | "session" |
|
||||
| CookieWithoutHttpOnly.go:31:13:31:16 | true | semmle.label | true |
|
||||
| CookieWithoutHttpOnly.go:33:20:33:21 | &... | semmle.label | &... |
|
||||
@@ -416,6 +438,8 @@ nodes
|
||||
| CookieWithoutHttpOnly.go:33:20:33:21 | &... [pointer] | semmle.label | &... [pointer] |
|
||||
| CookieWithoutHttpOnly.go:33:21:33:21 | c | semmle.label | c |
|
||||
| CookieWithoutHttpOnly.go:33:21:33:21 | c | semmle.label | c |
|
||||
| CookieWithoutHttpOnly.go:37:7:40:2 | struct literal | semmle.label | struct literal |
|
||||
| CookieWithoutHttpOnly.go:37:7:40:2 | struct literal | semmle.label | struct literal |
|
||||
| CookieWithoutHttpOnly.go:38:10:38:18 | "session" | semmle.label | "session" |
|
||||
| CookieWithoutHttpOnly.go:41:15:41:18 | true | semmle.label | true |
|
||||
| CookieWithoutHttpOnly.go:42:20:42:21 | &... | semmle.label | &... |
|
||||
@@ -426,6 +450,8 @@ nodes
|
||||
| CookieWithoutHttpOnly.go:42:20:42:21 | &... [pointer] | semmle.label | &... [pointer] |
|
||||
| CookieWithoutHttpOnly.go:42:21:42:21 | c | semmle.label | c |
|
||||
| CookieWithoutHttpOnly.go:42:21:42:21 | c | semmle.label | c |
|
||||
| CookieWithoutHttpOnly.go:46:7:49:2 | struct literal | semmle.label | struct literal |
|
||||
| CookieWithoutHttpOnly.go:46:7:49:2 | struct literal | semmle.label | struct literal |
|
||||
| CookieWithoutHttpOnly.go:47:10:47:18 | "session" | semmle.label | "session" |
|
||||
| CookieWithoutHttpOnly.go:50:15:50:19 | false | semmle.label | false |
|
||||
| CookieWithoutHttpOnly.go:51:20:51:21 | &... | semmle.label | &... |
|
||||
@@ -438,6 +464,8 @@ nodes
|
||||
| CookieWithoutHttpOnly.go:51:21:51:21 | c | semmle.label | c |
|
||||
| CookieWithoutHttpOnly.go:55:2:55:4 | definition of val | semmle.label | definition of val |
|
||||
| CookieWithoutHttpOnly.go:55:9:55:13 | false | semmle.label | false |
|
||||
| CookieWithoutHttpOnly.go:56:7:60:2 | struct literal | semmle.label | struct literal |
|
||||
| CookieWithoutHttpOnly.go:56:7:60:2 | struct literal | semmle.label | struct literal |
|
||||
| CookieWithoutHttpOnly.go:57:13:57:21 | "session" | semmle.label | "session" |
|
||||
| CookieWithoutHttpOnly.go:59:13:59:15 | val | semmle.label | val |
|
||||
| CookieWithoutHttpOnly.go:61:20:61:21 | &... | semmle.label | &... |
|
||||
@@ -450,6 +478,8 @@ nodes
|
||||
| CookieWithoutHttpOnly.go:61:21:61:21 | c | semmle.label | c |
|
||||
| CookieWithoutHttpOnly.go:65:2:65:4 | definition of val | semmle.label | definition of val |
|
||||
| CookieWithoutHttpOnly.go:65:9:65:12 | true | semmle.label | true |
|
||||
| CookieWithoutHttpOnly.go:66:7:70:2 | struct literal | semmle.label | struct literal |
|
||||
| CookieWithoutHttpOnly.go:66:7:70:2 | struct literal | semmle.label | struct literal |
|
||||
| CookieWithoutHttpOnly.go:67:13:67:21 | "session" | semmle.label | "session" |
|
||||
| CookieWithoutHttpOnly.go:69:13:69:15 | val | semmle.label | val |
|
||||
| CookieWithoutHttpOnly.go:71:20:71:21 | &... | semmle.label | &... |
|
||||
@@ -462,6 +492,8 @@ nodes
|
||||
| CookieWithoutHttpOnly.go:71:21:71:21 | c | semmle.label | c |
|
||||
| CookieWithoutHttpOnly.go:75:2:75:4 | definition of val | semmle.label | definition of val |
|
||||
| CookieWithoutHttpOnly.go:75:9:75:12 | true | semmle.label | true |
|
||||
| CookieWithoutHttpOnly.go:76:7:79:2 | struct literal | semmle.label | struct literal |
|
||||
| CookieWithoutHttpOnly.go:76:7:79:2 | struct literal | semmle.label | struct literal |
|
||||
| CookieWithoutHttpOnly.go:77:10:77:18 | "session" | semmle.label | "session" |
|
||||
| CookieWithoutHttpOnly.go:80:15:80:17 | val | semmle.label | val |
|
||||
| CookieWithoutHttpOnly.go:81:20:81:21 | &... | semmle.label | &... |
|
||||
@@ -474,6 +506,8 @@ nodes
|
||||
| CookieWithoutHttpOnly.go:81:21:81:21 | c | semmle.label | c |
|
||||
| CookieWithoutHttpOnly.go:85:2:85:4 | definition of val | semmle.label | definition of val |
|
||||
| CookieWithoutHttpOnly.go:85:9:85:13 | false | semmle.label | false |
|
||||
| CookieWithoutHttpOnly.go:86:7:89:2 | struct literal | semmle.label | struct literal |
|
||||
| CookieWithoutHttpOnly.go:86:7:89:2 | struct literal | semmle.label | struct literal |
|
||||
| CookieWithoutHttpOnly.go:87:10:87:18 | "session" | semmle.label | "session" |
|
||||
| CookieWithoutHttpOnly.go:90:15:90:17 | val | semmle.label | val |
|
||||
| CookieWithoutHttpOnly.go:91:20:91:21 | &... | semmle.label | &... |
|
||||
@@ -484,12 +518,16 @@ nodes
|
||||
| CookieWithoutHttpOnly.go:91:20:91:21 | &... [pointer] | semmle.label | &... [pointer] |
|
||||
| CookieWithoutHttpOnly.go:91:21:91:21 | c | semmle.label | c |
|
||||
| CookieWithoutHttpOnly.go:91:21:91:21 | c | semmle.label | c |
|
||||
| CookieWithoutHttpOnly.go:95:7:98:2 | struct literal | semmle.label | struct literal |
|
||||
| CookieWithoutHttpOnly.go:99:15:99:19 | false | semmle.label | false |
|
||||
| CookieWithoutHttpOnly.go:100:20:100:21 | &... | semmle.label | &... |
|
||||
| CookieWithoutHttpOnly.go:100:20:100:21 | &... | semmle.label | &... |
|
||||
| CookieWithoutHttpOnly.go:100:20:100:21 | &... [pointer] | semmle.label | &... [pointer] |
|
||||
| CookieWithoutHttpOnly.go:100:21:100:21 | c | semmle.label | c |
|
||||
| CookieWithoutHttpOnly.go:104:10:104:18 | "session" | semmle.label | "session" |
|
||||
| CookieWithoutHttpOnly.go:105:7:108:2 | struct literal | semmle.label | struct literal |
|
||||
| CookieWithoutHttpOnly.go:105:7:108:2 | struct literal | semmle.label | struct literal |
|
||||
| CookieWithoutHttpOnly.go:106:10:106:13 | name | semmle.label | name |
|
||||
| CookieWithoutHttpOnly.go:109:15:109:19 | false | semmle.label | false |
|
||||
| CookieWithoutHttpOnly.go:110:20:110:21 | &... | semmle.label | &... |
|
||||
| CookieWithoutHttpOnly.go:110:20:110:21 | &... | semmle.label | &... |
|
||||
@@ -500,6 +538,8 @@ nodes
|
||||
| CookieWithoutHttpOnly.go:110:21:110:21 | c | semmle.label | c |
|
||||
| CookieWithoutHttpOnly.go:110:21:110:21 | c | semmle.label | c |
|
||||
| CookieWithoutHttpOnly.go:114:13:114:24 | "login_name" | semmle.label | "login_name" |
|
||||
| CookieWithoutHttpOnly.go:115:7:118:2 | struct literal | semmle.label | struct literal |
|
||||
| CookieWithoutHttpOnly.go:115:7:118:2 | struct literal | semmle.label | struct literal |
|
||||
| CookieWithoutHttpOnly.go:116:10:116:16 | session | semmle.label | session |
|
||||
| CookieWithoutHttpOnly.go:119:15:119:19 | false | semmle.label | false |
|
||||
| CookieWithoutHttpOnly.go:120:20:120:21 | &... | semmle.label | &... |
|
||||
@@ -511,12 +551,14 @@ nodes
|
||||
| CookieWithoutHttpOnly.go:120:21:120:21 | c | semmle.label | c |
|
||||
| CookieWithoutHttpOnly.go:120:21:120:21 | c | semmle.label | c |
|
||||
| CookieWithoutHttpOnly.go:123:13:123:49 | call to NewCookieStore | semmle.label | call to NewCookieStore |
|
||||
| CookieWithoutHttpOnly.go:126:2:126:43 | ... := ...[0] | semmle.label | ... := ...[0] |
|
||||
| CookieWithoutHttpOnly.go:126:16:126:20 | store | semmle.label | store |
|
||||
| CookieWithoutHttpOnly.go:129:2:129:8 | session | semmle.label | session |
|
||||
| CookieWithoutHttpOnly.go:133:2:133:9 | definition of httpOnly | semmle.label | definition of httpOnly |
|
||||
| CookieWithoutHttpOnly.go:133:14:133:18 | false | semmle.label | false |
|
||||
| CookieWithoutHttpOnly.go:134:2:134:8 | definition of session [pointer] | semmle.label | definition of session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:134:2:134:8 | definition of session [pointer] | semmle.label | definition of session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:134:2:134:43 | ... := ...[0] | semmle.label | ... := ...[0] |
|
||||
| CookieWithoutHttpOnly.go:134:16:134:20 | store | semmle.label | store |
|
||||
| CookieWithoutHttpOnly.go:135:2:135:8 | implicit dereference | semmle.label | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:135:2:135:8 | implicit dereference | semmle.label | implicit dereference |
|
||||
@@ -524,19 +566,27 @@ nodes
|
||||
| CookieWithoutHttpOnly.go:135:2:135:8 | session [pointer] | semmle.label | session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:137:2:137:8 | implicit dereference | semmle.label | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:137:2:137:8 | implicit dereference | semmle.label | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:137:2:137:8 | session | semmle.label | session |
|
||||
| CookieWithoutHttpOnly.go:137:2:137:8 | session | semmle.label | session |
|
||||
| CookieWithoutHttpOnly.go:137:2:137:8 | session [pointer] | semmle.label | session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:137:2:137:8 | session [pointer] | semmle.label | session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:137:20:140:2 | &... | semmle.label | &... |
|
||||
| CookieWithoutHttpOnly.go:137:20:140:2 | &... | semmle.label | &... |
|
||||
| CookieWithoutHttpOnly.go:137:21:140:2 | struct literal | semmle.label | struct literal |
|
||||
| CookieWithoutHttpOnly.go:137:21:140:2 | struct literal | semmle.label | struct literal |
|
||||
| CookieWithoutHttpOnly.go:139:13:139:20 | httpOnly | semmle.label | httpOnly |
|
||||
| CookieWithoutHttpOnly.go:142:2:142:8 | session | semmle.label | session |
|
||||
| CookieWithoutHttpOnly.go:142:2:142:8 | session | semmle.label | session |
|
||||
| CookieWithoutHttpOnly.go:142:2:142:8 | session | semmle.label | session |
|
||||
| CookieWithoutHttpOnly.go:146:2:146:8 | definition of session [pointer] | semmle.label | definition of session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:146:2:146:43 | ... := ...[0] | semmle.label | ... := ...[0] |
|
||||
| CookieWithoutHttpOnly.go:146:16:146:20 | store | semmle.label | store |
|
||||
| CookieWithoutHttpOnly.go:147:2:147:8 | implicit dereference | semmle.label | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:147:2:147:8 | session [pointer] | semmle.label | session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:149:2:149:8 | implicit dereference | semmle.label | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:149:2:149:8 | session | semmle.label | session |
|
||||
| CookieWithoutHttpOnly.go:149:2:149:8 | session [pointer] | semmle.label | session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:149:20:151:2 | &... | semmle.label | &... |
|
||||
| CookieWithoutHttpOnly.go:149:21:151:2 | struct literal | semmle.label | struct literal |
|
||||
| CookieWithoutHttpOnly.go:153:2:153:8 | session | semmle.label | session |
|
||||
| CookieWithoutHttpOnly.go:153:2:153:8 | session | semmle.label | session |
|
||||
@@ -544,6 +594,7 @@ nodes
|
||||
| CookieWithoutHttpOnly.go:157:14:157:17 | true | semmle.label | true |
|
||||
| CookieWithoutHttpOnly.go:158:2:158:8 | definition of session [pointer] | semmle.label | definition of session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:158:2:158:8 | definition of session [pointer] | semmle.label | definition of session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:158:2:158:43 | ... := ...[0] | semmle.label | ... := ...[0] |
|
||||
| CookieWithoutHttpOnly.go:158:16:158:20 | store | semmle.label | store |
|
||||
| CookieWithoutHttpOnly.go:159:2:159:8 | implicit dereference | semmle.label | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:159:2:159:8 | implicit dereference | semmle.label | implicit dereference |
|
||||
@@ -551,8 +602,13 @@ nodes
|
||||
| CookieWithoutHttpOnly.go:159:2:159:8 | session [pointer] | semmle.label | session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:161:2:161:8 | implicit dereference | semmle.label | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:161:2:161:8 | implicit dereference | semmle.label | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:161:2:161:8 | session | semmle.label | session |
|
||||
| CookieWithoutHttpOnly.go:161:2:161:8 | session | semmle.label | session |
|
||||
| CookieWithoutHttpOnly.go:161:2:161:8 | session [pointer] | semmle.label | session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:161:2:161:8 | session [pointer] | semmle.label | session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:161:20:164:2 | &... | semmle.label | &... |
|
||||
| CookieWithoutHttpOnly.go:161:20:164:2 | &... | semmle.label | &... |
|
||||
| CookieWithoutHttpOnly.go:161:21:164:2 | struct literal | semmle.label | struct literal |
|
||||
| CookieWithoutHttpOnly.go:161:21:164:2 | struct literal | semmle.label | struct literal |
|
||||
| CookieWithoutHttpOnly.go:163:13:163:20 | httpOnly | semmle.label | httpOnly |
|
||||
| CookieWithoutHttpOnly.go:166:2:166:8 | session | semmle.label | session |
|
||||
@@ -562,6 +618,7 @@ nodes
|
||||
| CookieWithoutHttpOnly.go:169:56:169:63 | definition of httpOnly | semmle.label | definition of httpOnly |
|
||||
| CookieWithoutHttpOnly.go:170:2:170:8 | definition of session [pointer] | semmle.label | definition of session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:170:2:170:8 | definition of session [pointer] | semmle.label | definition of session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:170:2:170:43 | ... := ...[0] | semmle.label | ... := ...[0] |
|
||||
| CookieWithoutHttpOnly.go:170:16:170:20 | store | semmle.label | store |
|
||||
| CookieWithoutHttpOnly.go:171:2:171:8 | implicit dereference | semmle.label | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:171:2:171:8 | implicit dereference | semmle.label | implicit dereference |
|
||||
@@ -569,15 +626,22 @@ nodes
|
||||
| CookieWithoutHttpOnly.go:171:2:171:8 | session [pointer] | semmle.label | session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:173:2:173:8 | implicit dereference | semmle.label | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:173:2:173:8 | implicit dereference | semmle.label | implicit dereference |
|
||||
| CookieWithoutHttpOnly.go:173:2:173:8 | session | semmle.label | session |
|
||||
| CookieWithoutHttpOnly.go:173:2:173:8 | session | semmle.label | session |
|
||||
| CookieWithoutHttpOnly.go:173:2:173:8 | session [pointer] | semmle.label | session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:173:2:173:8 | session [pointer] | semmle.label | session [pointer] |
|
||||
| CookieWithoutHttpOnly.go:173:20:176:2 | &... | semmle.label | &... |
|
||||
| CookieWithoutHttpOnly.go:173:20:176:2 | &... | semmle.label | &... |
|
||||
| CookieWithoutHttpOnly.go:173:21:176:2 | struct literal | semmle.label | struct literal |
|
||||
| CookieWithoutHttpOnly.go:173:21:176:2 | struct literal | semmle.label | struct literal |
|
||||
| CookieWithoutHttpOnly.go:175:13:175:20 | httpOnly | semmle.label | httpOnly |
|
||||
| CookieWithoutHttpOnly.go:178:2:178:8 | session | semmle.label | session |
|
||||
| CookieWithoutHttpOnly.go:178:2:178:8 | session | semmle.label | session |
|
||||
| CookieWithoutHttpOnly.go:178:2:178:8 | session | semmle.label | session |
|
||||
| CookieWithoutHttpOnly.go:183:2:183:43 | ... := ...[0] | semmle.label | ... := ...[0] |
|
||||
| CookieWithoutHttpOnly.go:183:16:183:20 | store | semmle.label | store |
|
||||
| CookieWithoutHttpOnly.go:191:19:191:25 | session | semmle.label | session |
|
||||
| CookieWithoutHttpOnly.go:195:2:195:43 | ... := ...[0] | semmle.label | ... := ...[0] |
|
||||
| CookieWithoutHttpOnly.go:195:16:195:20 | store | semmle.label | store |
|
||||
| CookieWithoutHttpOnly.go:202:19:202:25 | session | semmle.label | session |
|
||||
| CookieWithoutHttpOnly.go:214:66:214:70 | false | semmle.label | false |
|
||||
|
||||
@@ -1,21 +1,31 @@
|
||||
edges
|
||||
| DivideByZero.go:10:12:10:16 | selection of URL | DivideByZero.go:10:12:10:24 | call to Query |
|
||||
| DivideByZero.go:10:12:10:24 | call to Query | DivideByZero.go:12:16:12:20 | value |
|
||||
| DivideByZero.go:10:12:10:24 | call to Query | DivideByZero.go:11:27:11:32 | param1 |
|
||||
| DivideByZero.go:11:2:11:33 | ... := ...[0] | DivideByZero.go:12:16:12:20 | value |
|
||||
| DivideByZero.go:11:27:11:32 | param1 | DivideByZero.go:11:2:11:33 | ... := ...[0] |
|
||||
| DivideByZero.go:17:12:17:16 | selection of URL | DivideByZero.go:17:12:17:24 | call to Query |
|
||||
| DivideByZero.go:17:12:17:24 | call to Query | DivideByZero.go:18:11:18:24 | type conversion |
|
||||
| DivideByZero.go:18:11:18:24 | type conversion | DivideByZero.go:19:16:19:20 | value |
|
||||
| DivideByZero.go:24:12:24:16 | selection of URL | DivideByZero.go:24:12:24:24 | call to Query |
|
||||
| DivideByZero.go:24:12:24:24 | call to Query | DivideByZero.go:26:16:26:20 | value |
|
||||
| DivideByZero.go:24:12:24:24 | call to Query | DivideByZero.go:25:31:25:36 | param1 |
|
||||
| DivideByZero.go:25:2:25:45 | ... := ...[0] | DivideByZero.go:26:16:26:20 | value |
|
||||
| DivideByZero.go:25:31:25:36 | param1 | DivideByZero.go:25:2:25:45 | ... := ...[0] |
|
||||
| DivideByZero.go:31:12:31:16 | selection of URL | DivideByZero.go:31:12:31:24 | call to Query |
|
||||
| DivideByZero.go:31:12:31:24 | call to Query | DivideByZero.go:33:16:33:20 | value |
|
||||
| DivideByZero.go:31:12:31:24 | call to Query | DivideByZero.go:32:33:32:38 | param1 |
|
||||
| DivideByZero.go:32:2:32:43 | ... := ...[0] | DivideByZero.go:33:16:33:20 | value |
|
||||
| DivideByZero.go:32:33:32:38 | param1 | DivideByZero.go:32:2:32:43 | ... := ...[0] |
|
||||
| DivideByZero.go:38:12:38:16 | selection of URL | DivideByZero.go:38:12:38:24 | call to Query |
|
||||
| DivideByZero.go:38:12:38:24 | call to Query | DivideByZero.go:40:16:40:20 | value |
|
||||
| DivideByZero.go:38:12:38:24 | call to Query | DivideByZero.go:39:32:39:37 | param1 |
|
||||
| DivideByZero.go:39:2:39:46 | ... := ...[0] | DivideByZero.go:40:16:40:20 | value |
|
||||
| DivideByZero.go:39:32:39:37 | param1 | DivideByZero.go:39:2:39:46 | ... := ...[0] |
|
||||
| DivideByZero.go:54:12:54:16 | selection of URL | DivideByZero.go:54:12:54:24 | call to Query |
|
||||
| DivideByZero.go:54:12:54:24 | call to Query | DivideByZero.go:55:11:55:24 | type conversion |
|
||||
| DivideByZero.go:55:11:55:24 | type conversion | DivideByZero.go:57:17:57:21 | value |
|
||||
nodes
|
||||
| DivideByZero.go:10:12:10:16 | selection of URL | semmle.label | selection of URL |
|
||||
| DivideByZero.go:10:12:10:24 | call to Query | semmle.label | call to Query |
|
||||
| DivideByZero.go:11:2:11:33 | ... := ...[0] | semmle.label | ... := ...[0] |
|
||||
| DivideByZero.go:11:27:11:32 | param1 | semmle.label | param1 |
|
||||
| DivideByZero.go:12:16:12:20 | value | semmle.label | value |
|
||||
| DivideByZero.go:17:12:17:16 | selection of URL | semmle.label | selection of URL |
|
||||
| DivideByZero.go:17:12:17:24 | call to Query | semmle.label | call to Query |
|
||||
@@ -23,12 +33,18 @@ nodes
|
||||
| DivideByZero.go:19:16:19:20 | value | semmle.label | value |
|
||||
| DivideByZero.go:24:12:24:16 | selection of URL | semmle.label | selection of URL |
|
||||
| DivideByZero.go:24:12:24:24 | call to Query | semmle.label | call to Query |
|
||||
| DivideByZero.go:25:2:25:45 | ... := ...[0] | semmle.label | ... := ...[0] |
|
||||
| DivideByZero.go:25:31:25:36 | param1 | semmle.label | param1 |
|
||||
| DivideByZero.go:26:16:26:20 | value | semmle.label | value |
|
||||
| DivideByZero.go:31:12:31:16 | selection of URL | semmle.label | selection of URL |
|
||||
| DivideByZero.go:31:12:31:24 | call to Query | semmle.label | call to Query |
|
||||
| DivideByZero.go:32:2:32:43 | ... := ...[0] | semmle.label | ... := ...[0] |
|
||||
| DivideByZero.go:32:33:32:38 | param1 | semmle.label | param1 |
|
||||
| DivideByZero.go:33:16:33:20 | value | semmle.label | value |
|
||||
| DivideByZero.go:38:12:38:16 | selection of URL | semmle.label | selection of URL |
|
||||
| DivideByZero.go:38:12:38:24 | call to Query | semmle.label | call to Query |
|
||||
| DivideByZero.go:39:2:39:46 | ... := ...[0] | semmle.label | ... := ...[0] |
|
||||
| DivideByZero.go:39:32:39:37 | param1 | semmle.label | param1 |
|
||||
| DivideByZero.go:40:16:40:20 | value | semmle.label | value |
|
||||
| DivideByZero.go:54:12:54:16 | selection of URL | semmle.label | selection of URL |
|
||||
| DivideByZero.go:54:12:54:24 | call to Query | semmle.label | call to Query |
|
||||
|
||||
@@ -1,143 +1,65 @@
|
||||
edges
|
||||
| HTMLTemplateEscapingPassthrough.go:29:12:29:41 | type conversion | HTMLTemplateEscapingPassthrough.go:30:39:30:39 | a |
|
||||
| HTMLTemplateEscapingPassthrough.go:29:12:29:41 | type conversion | HTMLTemplateEscapingPassthrough.go:30:39:30:39 | a |
|
||||
| HTMLTemplateEscapingPassthrough.go:29:26:29:40 | call to UserAgent | HTMLTemplateEscapingPassthrough.go:29:12:29:41 | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:29:26:29:40 | call to UserAgent | HTMLTemplateEscapingPassthrough.go:29:12:29:41 | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:35:9:35:38 | type conversion | HTMLTemplateEscapingPassthrough.go:36:40:36:40 | a |
|
||||
| HTMLTemplateEscapingPassthrough.go:35:9:35:38 | type conversion | HTMLTemplateEscapingPassthrough.go:36:40:36:40 | a |
|
||||
| HTMLTemplateEscapingPassthrough.go:35:23:35:37 | call to UserAgent | HTMLTemplateEscapingPassthrough.go:35:9:35:38 | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:35:23:35:37 | call to UserAgent | HTMLTemplateEscapingPassthrough.go:35:9:35:38 | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:40:9:40:34 | type conversion | HTMLTemplateEscapingPassthrough.go:41:40:41:40 | a |
|
||||
| HTMLTemplateEscapingPassthrough.go:40:9:40:34 | type conversion | HTMLTemplateEscapingPassthrough.go:41:40:41:40 | a |
|
||||
| HTMLTemplateEscapingPassthrough.go:40:19:40:33 | call to UserAgent | HTMLTemplateEscapingPassthrough.go:40:9:40:34 | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:40:19:40:33 | call to UserAgent | HTMLTemplateEscapingPassthrough.go:40:9:40:34 | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:46:11:46:44 | type conversion | HTMLTemplateEscapingPassthrough.go:47:41:47:41 | c |
|
||||
| HTMLTemplateEscapingPassthrough.go:46:11:46:44 | type conversion | HTMLTemplateEscapingPassthrough.go:47:41:47:41 | c |
|
||||
| HTMLTemplateEscapingPassthrough.go:46:29:46:43 | call to UserAgent | HTMLTemplateEscapingPassthrough.go:46:11:46:44 | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:46:29:46:43 | call to UserAgent | HTMLTemplateEscapingPassthrough.go:46:11:46:44 | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:50:11:50:38 | type conversion | HTMLTemplateEscapingPassthrough.go:51:44:51:44 | d |
|
||||
| HTMLTemplateEscapingPassthrough.go:50:11:50:38 | type conversion | HTMLTemplateEscapingPassthrough.go:51:44:51:44 | d |
|
||||
| HTMLTemplateEscapingPassthrough.go:50:23:50:37 | call to UserAgent | HTMLTemplateEscapingPassthrough.go:50:11:50:38 | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:50:23:50:37 | call to UserAgent | HTMLTemplateEscapingPassthrough.go:50:11:50:38 | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:54:11:54:41 | type conversion | HTMLTemplateEscapingPassthrough.go:55:44:55:44 | e |
|
||||
| HTMLTemplateEscapingPassthrough.go:54:11:54:41 | type conversion | HTMLTemplateEscapingPassthrough.go:55:44:55:44 | e |
|
||||
| HTMLTemplateEscapingPassthrough.go:54:26:54:40 | call to UserAgent | HTMLTemplateEscapingPassthrough.go:54:11:54:41 | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:54:26:54:40 | call to UserAgent | HTMLTemplateEscapingPassthrough.go:54:11:54:41 | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:58:11:58:39 | type conversion | HTMLTemplateEscapingPassthrough.go:59:38:59:38 | b |
|
||||
| HTMLTemplateEscapingPassthrough.go:58:11:58:39 | type conversion | HTMLTemplateEscapingPassthrough.go:59:38:59:38 | b |
|
||||
| HTMLTemplateEscapingPassthrough.go:58:24:58:38 | call to UserAgent | HTMLTemplateEscapingPassthrough.go:58:11:58:39 | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:58:24:58:38 | call to UserAgent | HTMLTemplateEscapingPassthrough.go:58:11:58:39 | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:62:11:62:42 | type conversion | HTMLTemplateEscapingPassthrough.go:63:44:63:44 | f |
|
||||
| HTMLTemplateEscapingPassthrough.go:62:11:62:42 | type conversion | HTMLTemplateEscapingPassthrough.go:63:44:63:44 | f |
|
||||
| HTMLTemplateEscapingPassthrough.go:62:27:62:41 | call to UserAgent | HTMLTemplateEscapingPassthrough.go:62:11:62:42 | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:62:27:62:41 | call to UserAgent | HTMLTemplateEscapingPassthrough.go:62:11:62:42 | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:66:11:66:39 | type conversion | HTMLTemplateEscapingPassthrough.go:67:38:67:38 | g |
|
||||
| HTMLTemplateEscapingPassthrough.go:66:11:66:39 | type conversion | HTMLTemplateEscapingPassthrough.go:67:38:67:38 | g |
|
||||
| HTMLTemplateEscapingPassthrough.go:66:24:66:38 | call to UserAgent | HTMLTemplateEscapingPassthrough.go:66:11:66:39 | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:66:24:66:38 | call to UserAgent | HTMLTemplateEscapingPassthrough.go:66:11:66:39 | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:75:17:75:31 | call to UserAgent | HTMLTemplateEscapingPassthrough.go:76:38:76:44 | escaped |
|
||||
| HTMLTemplateEscapingPassthrough.go:81:10:81:24 | call to UserAgent | HTMLTemplateEscapingPassthrough.go:82:16:82:33 | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:81:10:81:24 | call to UserAgent | HTMLTemplateEscapingPassthrough.go:84:38:84:40 | src |
|
||||
| HTMLTemplateEscapingPassthrough.go:89:10:89:24 | call to UserAgent | HTMLTemplateEscapingPassthrough.go:91:64:91:66 | src |
|
||||
| HTMLTemplateEscapingPassthrough.go:91:16:91:77 | type conversion | HTMLTemplateEscapingPassthrough.go:92:38:92:46 | converted |
|
||||
| HTMLTemplateEscapingPassthrough.go:91:16:91:77 | type conversion | HTMLTemplateEscapingPassthrough.go:92:38:92:46 | converted |
|
||||
| HTMLTemplateEscapingPassthrough.go:91:38:91:67 | call to HTMLEscapeString | HTMLTemplateEscapingPassthrough.go:91:16:91:77 | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:91:64:91:66 | src | HTMLTemplateEscapingPassthrough.go:91:38:91:67 | call to HTMLEscapeString |
|
||||
| HTMLTemplateEscapingPassthrough.go:101:9:101:14 | selection of Form | HTMLTemplateEscapingPassthrough.go:101:9:101:24 | call to Get |
|
||||
| HTMLTemplateEscapingPassthrough.go:101:9:101:24 | call to Get | HTMLTemplateEscapingPassthrough.go:115:8:115:15 | call to getId |
|
||||
| HTMLTemplateEscapingPassthrough.go:104:18:104:18 | definition of x | HTMLTemplateEscapingPassthrough.go:105:9:105:24 | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:105:9:105:24 | type conversion | HTMLTemplateEscapingPassthrough.go:123:11:123:36 | call to passthrough |
|
||||
| HTMLTemplateEscapingPassthrough.go:108:35:108:35 | definition of x | HTMLTemplateEscapingPassthrough.go:110:19:110:19 | x |
|
||||
| HTMLTemplateEscapingPassthrough.go:115:8:115:15 | call to getId | HTMLTemplateEscapingPassthrough.go:116:15:116:15 | x |
|
||||
| HTMLTemplateEscapingPassthrough.go:116:15:116:15 | x | HTMLTemplateEscapingPassthrough.go:104:18:104:18 | definition of x |
|
||||
| HTMLTemplateEscapingPassthrough.go:123:11:123:36 | call to passthrough | HTMLTemplateEscapingPassthrough.go:108:35:108:35 | definition of x |
|
||||
nodes
|
||||
| HTMLTemplateEscapingPassthrough.go:29:12:29:41 | type conversion | semmle.label | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:29:12:29:41 | type conversion | semmle.label | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:29:12:29:41 | type conversion | semmle.label | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:29:26:29:40 | call to UserAgent | semmle.label | call to UserAgent |
|
||||
| HTMLTemplateEscapingPassthrough.go:29:26:29:40 | call to UserAgent | semmle.label | call to UserAgent |
|
||||
| HTMLTemplateEscapingPassthrough.go:30:39:30:39 | a | semmle.label | a |
|
||||
| HTMLTemplateEscapingPassthrough.go:30:39:30:39 | a | semmle.label | a |
|
||||
| HTMLTemplateEscapingPassthrough.go:35:9:35:38 | type conversion | semmle.label | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:35:9:35:38 | type conversion | semmle.label | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:35:9:35:38 | type conversion | semmle.label | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:35:23:35:37 | call to UserAgent | semmle.label | call to UserAgent |
|
||||
| HTMLTemplateEscapingPassthrough.go:35:23:35:37 | call to UserAgent | semmle.label | call to UserAgent |
|
||||
| HTMLTemplateEscapingPassthrough.go:36:40:36:40 | a | semmle.label | a |
|
||||
| HTMLTemplateEscapingPassthrough.go:36:40:36:40 | a | semmle.label | a |
|
||||
| HTMLTemplateEscapingPassthrough.go:40:9:40:34 | type conversion | semmle.label | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:40:9:40:34 | type conversion | semmle.label | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:40:9:40:34 | type conversion | semmle.label | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:40:19:40:33 | call to UserAgent | semmle.label | call to UserAgent |
|
||||
| HTMLTemplateEscapingPassthrough.go:40:19:40:33 | call to UserAgent | semmle.label | call to UserAgent |
|
||||
| HTMLTemplateEscapingPassthrough.go:41:40:41:40 | a | semmle.label | a |
|
||||
| HTMLTemplateEscapingPassthrough.go:41:40:41:40 | a | semmle.label | a |
|
||||
| HTMLTemplateEscapingPassthrough.go:46:11:46:44 | type conversion | semmle.label | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:46:11:46:44 | type conversion | semmle.label | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:46:11:46:44 | type conversion | semmle.label | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:46:29:46:43 | call to UserAgent | semmle.label | call to UserAgent |
|
||||
| HTMLTemplateEscapingPassthrough.go:46:29:46:43 | call to UserAgent | semmle.label | call to UserAgent |
|
||||
| HTMLTemplateEscapingPassthrough.go:47:41:47:41 | c | semmle.label | c |
|
||||
| HTMLTemplateEscapingPassthrough.go:47:41:47:41 | c | semmle.label | c |
|
||||
| HTMLTemplateEscapingPassthrough.go:50:11:50:38 | type conversion | semmle.label | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:50:11:50:38 | type conversion | semmle.label | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:50:11:50:38 | type conversion | semmle.label | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:50:23:50:37 | call to UserAgent | semmle.label | call to UserAgent |
|
||||
| HTMLTemplateEscapingPassthrough.go:50:23:50:37 | call to UserAgent | semmle.label | call to UserAgent |
|
||||
| HTMLTemplateEscapingPassthrough.go:51:44:51:44 | d | semmle.label | d |
|
||||
| HTMLTemplateEscapingPassthrough.go:51:44:51:44 | d | semmle.label | d |
|
||||
| HTMLTemplateEscapingPassthrough.go:54:11:54:41 | type conversion | semmle.label | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:54:11:54:41 | type conversion | semmle.label | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:54:11:54:41 | type conversion | semmle.label | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:54:26:54:40 | call to UserAgent | semmle.label | call to UserAgent |
|
||||
| HTMLTemplateEscapingPassthrough.go:54:26:54:40 | call to UserAgent | semmle.label | call to UserAgent |
|
||||
| HTMLTemplateEscapingPassthrough.go:55:44:55:44 | e | semmle.label | e |
|
||||
| HTMLTemplateEscapingPassthrough.go:55:44:55:44 | e | semmle.label | e |
|
||||
| HTMLTemplateEscapingPassthrough.go:58:11:58:39 | type conversion | semmle.label | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:58:11:58:39 | type conversion | semmle.label | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:58:11:58:39 | type conversion | semmle.label | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:58:24:58:38 | call to UserAgent | semmle.label | call to UserAgent |
|
||||
| HTMLTemplateEscapingPassthrough.go:58:24:58:38 | call to UserAgent | semmle.label | call to UserAgent |
|
||||
| HTMLTemplateEscapingPassthrough.go:59:38:59:38 | b | semmle.label | b |
|
||||
| HTMLTemplateEscapingPassthrough.go:59:38:59:38 | b | semmle.label | b |
|
||||
| HTMLTemplateEscapingPassthrough.go:62:11:62:42 | type conversion | semmle.label | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:62:11:62:42 | type conversion | semmle.label | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:62:11:62:42 | type conversion | semmle.label | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:62:27:62:41 | call to UserAgent | semmle.label | call to UserAgent |
|
||||
| HTMLTemplateEscapingPassthrough.go:62:27:62:41 | call to UserAgent | semmle.label | call to UserAgent |
|
||||
| HTMLTemplateEscapingPassthrough.go:63:44:63:44 | f | semmle.label | f |
|
||||
| HTMLTemplateEscapingPassthrough.go:63:44:63:44 | f | semmle.label | f |
|
||||
| HTMLTemplateEscapingPassthrough.go:66:11:66:39 | type conversion | semmle.label | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:66:11:66:39 | type conversion | semmle.label | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:66:11:66:39 | type conversion | semmle.label | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:66:24:66:38 | call to UserAgent | semmle.label | call to UserAgent |
|
||||
| HTMLTemplateEscapingPassthrough.go:66:24:66:38 | call to UserAgent | semmle.label | call to UserAgent |
|
||||
| HTMLTemplateEscapingPassthrough.go:67:38:67:38 | g | semmle.label | g |
|
||||
| HTMLTemplateEscapingPassthrough.go:67:38:67:38 | g | semmle.label | g |
|
||||
| HTMLTemplateEscapingPassthrough.go:75:17:75:31 | call to UserAgent | semmle.label | call to UserAgent |
|
||||
| HTMLTemplateEscapingPassthrough.go:76:38:76:44 | escaped | semmle.label | escaped |
|
||||
| HTMLTemplateEscapingPassthrough.go:81:10:81:24 | call to UserAgent | semmle.label | call to UserAgent |
|
||||
| HTMLTemplateEscapingPassthrough.go:81:10:81:24 | call to UserAgent | semmle.label | call to UserAgent |
|
||||
| HTMLTemplateEscapingPassthrough.go:82:16:82:33 | type conversion | semmle.label | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:84:38:84:40 | src | semmle.label | src |
|
||||
| HTMLTemplateEscapingPassthrough.go:89:10:89:24 | call to UserAgent | semmle.label | call to UserAgent |
|
||||
| HTMLTemplateEscapingPassthrough.go:91:16:91:77 | type conversion | semmle.label | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:91:16:91:77 | type conversion | semmle.label | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:91:38:91:67 | call to HTMLEscapeString | semmle.label | call to HTMLEscapeString |
|
||||
| HTMLTemplateEscapingPassthrough.go:91:64:91:66 | src | semmle.label | src |
|
||||
| HTMLTemplateEscapingPassthrough.go:92:38:92:46 | converted | semmle.label | converted |
|
||||
| HTMLTemplateEscapingPassthrough.go:92:38:92:46 | converted | semmle.label | converted |
|
||||
| HTMLTemplateEscapingPassthrough.go:101:9:101:14 | selection of Form | semmle.label | selection of Form |
|
||||
| HTMLTemplateEscapingPassthrough.go:101:9:101:24 | call to Get | semmle.label | call to Get |
|
||||
| HTMLTemplateEscapingPassthrough.go:104:18:104:18 | definition of x | semmle.label | definition of x |
|
||||
| HTMLTemplateEscapingPassthrough.go:105:9:105:24 | type conversion | semmle.label | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:105:9:105:24 | type conversion | semmle.label | type conversion |
|
||||
| HTMLTemplateEscapingPassthrough.go:108:35:108:35 | definition of x | semmle.label | definition of x |
|
||||
| HTMLTemplateEscapingPassthrough.go:110:19:110:19 | x | semmle.label | x |
|
||||
| HTMLTemplateEscapingPassthrough.go:115:8:115:15 | call to getId | semmle.label | call to getId |
|
||||
| HTMLTemplateEscapingPassthrough.go:116:15:116:15 | x | semmle.label | x |
|
||||
| HTMLTemplateEscapingPassthrough.go:123:11:123:36 | call to passthrough | semmle.label | call to passthrough |
|
||||
subpaths
|
||||
#select
|
||||
| HTMLTemplateEscapingPassthrough.go:30:39:30:39 | a | HTMLTemplateEscapingPassthrough.go:29:26:29:40 | call to UserAgent | HTMLTemplateEscapingPassthrough.go:30:39:30:39 | a | Data from an $@ will not be auto-escaped because it was $@ to template.HTML | HTMLTemplateEscapingPassthrough.go:29:26:29:40 | call to UserAgent | untrusted source | HTMLTemplateEscapingPassthrough.go:29:12:29:41 | type conversion | converted |
|
||||
|
||||
@@ -17,7 +17,7 @@ func TaintTracking_ClevergoTechClevergoV052() {
|
||||
{
|
||||
fromString598 := source().(string)
|
||||
intoString631 := clevergo.CleanPath(fromString598)
|
||||
sink(intoString631) // $ taintSink
|
||||
sink(intoString631) // $ hasTaintFlow="intoString631"
|
||||
}
|
||||
}
|
||||
// Taint-tracking through method calls.
|
||||
@@ -30,13 +30,13 @@ func TaintTracking_ClevergoTechClevergoV052() {
|
||||
fromString165 := source().(string)
|
||||
var mediumObjCQL clevergo.Application
|
||||
intoURL150, _ := mediumObjCQL.RouteURL(fromString165, "")
|
||||
sink(intoURL150) // $ taintSink
|
||||
sink(intoURL150) // $ hasTaintFlow="intoURL150"
|
||||
}
|
||||
{
|
||||
fromString340 := source().(string)
|
||||
var mediumObjCQL clevergo.Application
|
||||
intoURL471, _ := mediumObjCQL.RouteURL("", fromString340)
|
||||
sink(intoURL471) // $ taintSink
|
||||
sink(intoURL471) // $ hasTaintFlow="intoURL471"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,7 @@ func TaintTracking_ClevergoTechClevergoV052() {
|
||||
{
|
||||
fromContext290 := source().(clevergo.Context)
|
||||
intoContext758 := fromContext290.Context()
|
||||
sink(intoContext758) // $ taintSink
|
||||
sink(intoContext758) // $ hasTaintFlow="intoContext758"
|
||||
}
|
||||
}
|
||||
// Taint-tracking through method calls on clevergo.tech/clevergo.Params.
|
||||
@@ -55,7 +55,7 @@ func TaintTracking_ClevergoTechClevergoV052() {
|
||||
{
|
||||
fromParams396 := source().(clevergo.Params)
|
||||
intoString707 := fromParams396.String("")
|
||||
sink(intoString707) // $ taintSink untrustedFlowSource
|
||||
sink(intoString707) // $ hasTaintFlow="intoString707" untrustedFlowSource
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,7 +69,7 @@ func TaintTracking_ClevergoTechClevergoV052() {
|
||||
var intoInterface718 interface{}
|
||||
var mediumObjCQL clevergo.Decoder
|
||||
mediumObjCQL.Decode(fromRequest912, intoInterface718)
|
||||
sink(intoInterface718) // $ taintSink untrustedFlowSource
|
||||
sink(intoInterface718) // $ hasTaintFlow="intoInterface718" untrustedFlowSource
|
||||
}
|
||||
}
|
||||
// Taint-tracking through method calls on clevergo.tech/clevergo.Renderer interface.
|
||||
@@ -80,7 +80,7 @@ func TaintTracking_ClevergoTechClevergoV052() {
|
||||
var intoWriter633 io.Writer
|
||||
var mediumObjCQL clevergo.Renderer
|
||||
mediumObjCQL.Render(intoWriter633, "", fromInterface972, nil)
|
||||
sink(intoWriter633) // $ taintSink
|
||||
sink(intoWriter633) // $ hasTaintFlow="intoWriter633"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,31 +1,4 @@
|
||||
import go
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
import experimental.frameworks.CleverGo
|
||||
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "test-configuration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
exists(Function fn | fn.hasQualifiedName(_, "source") | source = fn.getACall().getResult())
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(Function fn | fn.hasQualifiedName(_, "sink") | sink = fn.getACall().getAnArgument())
|
||||
}
|
||||
}
|
||||
|
||||
module TaintTrackingTest implements TestSig {
|
||||
string getARelevantTag() { result = "taintSink" }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
tag = "taintSink" and
|
||||
exists(DataFlow::Node sink | any(Configuration c).hasFlow(_, sink) |
|
||||
element = sink.toString() and
|
||||
value = "" and
|
||||
sink.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
|
||||
location.getStartColumn(), location.getEndLine(), location.getEndColumn())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeTest<TaintTrackingTest>
|
||||
import TestUtilities.InlineFlowTest
|
||||
import DefaultFlowTest
|
||||
|
||||
@@ -15,7 +15,7 @@ func TaintTracking_GithubComGofiberFiberV1146() {
|
||||
{
|
||||
fromString656 := source().(string)
|
||||
intoError414 := fiber.NewError(0, fromString656)
|
||||
sink(intoError414) // $ taintSink
|
||||
sink(intoError414) // $ hasTaintFlow="intoError414"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,79 +28,79 @@ func TaintTracking_GithubComGofiberUtilsV0010() {
|
||||
{
|
||||
fromString989 := source().(string)
|
||||
intoByte982 := utils.GetBytes(fromString989)
|
||||
sink(intoByte982) // $ taintSink
|
||||
sink(intoByte982) // $ hasTaintFlow="intoByte982"
|
||||
}
|
||||
// func GetString(b []byte) string
|
||||
{
|
||||
fromByte417 := source().([]byte)
|
||||
intoString584 := utils.GetString(fromByte417)
|
||||
sink(intoString584) // $ taintSink
|
||||
sink(intoString584) // $ hasTaintFlow="intoString584"
|
||||
}
|
||||
// func ImmutableString(s string) string
|
||||
{
|
||||
fromString991 := source().(string)
|
||||
intoString881 := utils.ImmutableString(fromString991)
|
||||
sink(intoString881) // $ taintSink
|
||||
sink(intoString881) // $ hasTaintFlow="intoString881"
|
||||
}
|
||||
// func ToLower(b string) string
|
||||
{
|
||||
fromString494 := source().(string)
|
||||
intoString873 := utils.ToLower(fromString494)
|
||||
sink(intoString873) // $ taintSink
|
||||
sink(intoString873) // $ hasTaintFlow="intoString873"
|
||||
}
|
||||
// func ToLowerBytes(b []byte) []byte
|
||||
{
|
||||
fromByte599 := source().([]byte)
|
||||
intoByte409 := utils.ToLowerBytes(fromByte599)
|
||||
sink(intoByte409) // $ taintSink
|
||||
sink(intoByte409) // $ hasTaintFlow="intoByte409"
|
||||
}
|
||||
// func ToUpper(b string) string
|
||||
{
|
||||
fromString246 := source().(string)
|
||||
intoString898 := utils.ToUpper(fromString246)
|
||||
sink(intoString898) // $ taintSink
|
||||
sink(intoString898) // $ hasTaintFlow="intoString898"
|
||||
}
|
||||
// func ToUpperBytes(b []byte) []byte
|
||||
{
|
||||
fromByte598 := source().([]byte)
|
||||
intoByte631 := utils.ToUpperBytes(fromByte598)
|
||||
sink(intoByte631) // $ taintSink
|
||||
sink(intoByte631) // $ hasTaintFlow="intoByte631"
|
||||
}
|
||||
// func Trim(s string, cutset byte) string
|
||||
{
|
||||
fromString165 := source().(string)
|
||||
intoString150 := utils.Trim(fromString165, 0)
|
||||
sink(intoString150) // $ taintSink
|
||||
sink(intoString150) // $ hasTaintFlow="intoString150"
|
||||
}
|
||||
// func TrimBytes(b []byte, cutset byte) []byte
|
||||
{
|
||||
fromByte340 := source().([]byte)
|
||||
intoByte471 := utils.TrimBytes(fromByte340, 0)
|
||||
sink(intoByte471) // $ taintSink
|
||||
sink(intoByte471) // $ hasTaintFlow="intoByte471"
|
||||
}
|
||||
// func TrimLeft(s string, cutset byte) string
|
||||
{
|
||||
fromString290 := source().(string)
|
||||
intoString758 := utils.TrimLeft(fromString290, 0)
|
||||
sink(intoString758) // $ taintSink
|
||||
sink(intoString758) // $ hasTaintFlow="intoString758"
|
||||
}
|
||||
// func TrimLeftBytes(b []byte, cutset byte) []byte
|
||||
{
|
||||
fromByte396 := source().([]byte)
|
||||
intoByte707 := utils.TrimLeftBytes(fromByte396, 0)
|
||||
sink(intoByte707) // $ taintSink
|
||||
sink(intoByte707) // $ hasTaintFlow="intoByte707"
|
||||
}
|
||||
// func TrimRight(s string, cutset byte) string
|
||||
{
|
||||
fromString912 := source().(string)
|
||||
intoString718 := utils.TrimRight(fromString912, 0)
|
||||
sink(intoString718) // $ taintSink
|
||||
sink(intoString718) // $ hasTaintFlow="intoString718"
|
||||
}
|
||||
// func TrimRightBytes(b []byte, cutset byte) []byte
|
||||
{
|
||||
fromByte972 := source().([]byte)
|
||||
intoByte633 := utils.TrimRightBytes(fromByte972, 0)
|
||||
sink(intoByte633) // $ taintSink
|
||||
sink(intoByte633) // $ hasTaintFlow="intoByte633"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,31 +1,4 @@
|
||||
import go
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
import experimental.frameworks.Fiber
|
||||
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "test-configuration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
exists(Function fn | fn.hasQualifiedName(_, "source") | source = fn.getACall().getResult())
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(Function fn | fn.hasQualifiedName(_, "sink") | sink = fn.getACall().getAnArgument())
|
||||
}
|
||||
}
|
||||
|
||||
module TaintTrackingTest implements TestSig {
|
||||
string getARelevantTag() { result = "taintSink" }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
tag = "taintSink" and
|
||||
exists(DataFlow::Node sink | any(Configuration c).hasFlow(_, sink) |
|
||||
element = sink.toString() and
|
||||
value = "" and
|
||||
sink.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
|
||||
location.getStartColumn(), location.getEndLine(), location.getEndColumn())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeTest<TaintTrackingTest>
|
||||
import TestUtilities.InlineFlowTest
|
||||
import DefaultFlowTest
|
||||
|
||||
@@ -1,56 +1,3 @@
|
||||
import go
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
class DataConfiguration extends DataFlow::Configuration {
|
||||
DataConfiguration() { this = "data-configuration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source = any(DataFlow::CallNode c | c.getCalleeName() = "source").getResult(0)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
sink = any(DataFlow::CallNode c | c.getCalleeName() = "sink").getArgument(0)
|
||||
}
|
||||
}
|
||||
|
||||
module DataFlowTest implements TestSig {
|
||||
string getARelevantTag() { result = "dataflow" }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
tag = "dataflow" and
|
||||
exists(DataFlow::Node sink | any(DataConfiguration c).hasFlow(_, sink) |
|
||||
element = sink.toString() and
|
||||
value = "" and
|
||||
sink.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
|
||||
location.getStartColumn(), location.getEndLine(), location.getEndColumn())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TaintConfiguration extends TaintTracking::Configuration {
|
||||
TaintConfiguration() { this = "taint-configuration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source = any(DataFlow::CallNode c | c.getCalleeName() = "source").getResult(0)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
sink = any(DataFlow::CallNode c | c.getCalleeName() = "sink").getArgument(0)
|
||||
}
|
||||
}
|
||||
|
||||
module TaintFlowTest implements TestSig {
|
||||
string getARelevantTag() { result = "taintflow" }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
tag = "taintflow" and
|
||||
exists(DataFlow::Node sink | any(TaintConfiguration c).hasFlow(_, sink) |
|
||||
element = sink.toString() and
|
||||
value = "" and
|
||||
sink.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
|
||||
location.getStartColumn(), location.getEndLine(), location.getEndColumn())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeTest<MergeTests<DataFlowTest, TaintFlowTest>>
|
||||
import TestUtilities.InlineFlowTest
|
||||
import DefaultFlowTest
|
||||
|
||||
@@ -16,10 +16,10 @@ func main() {
|
||||
var a [4]string
|
||||
a[0] = source()
|
||||
alias := sliceToArray(a[:])
|
||||
sink(alias[0]) // $ taintflow
|
||||
sink(alias[0]) // $ hasTaintFlow="index expression"
|
||||
|
||||
// Compare with the standard dataflow support for arrays
|
||||
var b [4]string
|
||||
b[0] = source()
|
||||
sink(b[0]) // $ taintflow
|
||||
sink(b[0]) // $ hasTaintFlow="index expression"
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
failures
|
||||
edges
|
||||
| test.go:9:9:9:11 | selection of c [collection] | test.go:9:7:9:11 | <-... |
|
||||
| test.go:13:16:13:16 | definition of s [pointer, c, collection] | test.go:16:2:16:2 | s [pointer, c, collection] |
|
||||
|
||||
@@ -1,18 +1,10 @@
|
||||
import go
|
||||
import DataFlow::PathGraph
|
||||
import TestUtilities.InlineFlowTest
|
||||
|
||||
class TestConfig extends DataFlow::Configuration {
|
||||
TestConfig() { this = "test config" }
|
||||
module Flow = DataFlow::Global<DefaultFlowConfig>;
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source.(DataFlow::CallNode).getTarget().getName() = "source"
|
||||
}
|
||||
import Flow::PathGraph
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
sink = any(DataFlow::CallNode c | c.getTarget().getName() = "sink").getAnArgument()
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, TestConfig c
|
||||
where c.hasFlowPath(source, sink)
|
||||
from Flow::PathNode source, Flow::PathNode sink
|
||||
where Flow::flowPath(source, sink)
|
||||
select source, source, sink, "path"
|
||||
|
||||
@@ -1,58 +1,5 @@
|
||||
import go
|
||||
import semmle.go.dataflow.ExternalFlow
|
||||
import ModelValidation
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
class DataConfiguration extends DataFlow::Configuration {
|
||||
DataConfiguration() { this = "data-configuration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source = any(DataFlow::CallNode c | c.getCalleeName() = "source").getResult(0)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
sink = any(DataFlow::CallNode c | c.getCalleeName() = "sink").getArgument(0)
|
||||
}
|
||||
}
|
||||
|
||||
module DataFlowTest implements TestSig {
|
||||
string getARelevantTag() { result = "dataflow" }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
tag = "dataflow" and
|
||||
exists(DataFlow::Node sink | any(DataConfiguration c).hasFlow(_, sink) |
|
||||
element = sink.toString() and
|
||||
value = "" and
|
||||
sink.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
|
||||
location.getStartColumn(), location.getEndLine(), location.getEndColumn())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TaintConfiguration extends TaintTracking::Configuration {
|
||||
TaintConfiguration() { this = "taint-configuration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source = any(DataFlow::CallNode c | c.getCalleeName() = "source").getResult(0)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
sink = any(DataFlow::CallNode c | c.getCalleeName() = "sink").getArgument(0)
|
||||
}
|
||||
}
|
||||
|
||||
module TaintFlowTest implements TestSig {
|
||||
string getARelevantTag() { result = "taintflow" }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
tag = "taintflow" and
|
||||
exists(DataFlow::Node sink | any(TaintConfiguration c).hasFlow(_, sink) |
|
||||
element = sink.toString() and
|
||||
value = "" and
|
||||
sink.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
|
||||
location.getStartColumn(), location.getEndLine(), location.getEndColumn())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeTest<MergeTests<DataFlowTest, TaintFlowTest>>
|
||||
import TestUtilities.InlineFlowTest
|
||||
import DefaultFlowTest
|
||||
|
||||
@@ -13,26 +13,26 @@ func sink(string) {
|
||||
|
||||
func main() {
|
||||
s := source()
|
||||
sink(test.FunctionWithParameter(s)) // $ taintflow dataflow
|
||||
sink(test.FunctionWithParameter(s)) // $ hasValueFlow="call to FunctionWithParameter"
|
||||
|
||||
stringSlice := []string{source()}
|
||||
sink(stringSlice[0]) // $ taintflow dataflow
|
||||
sink(stringSlice[0]) // $ hasValueFlow="index expression"
|
||||
|
||||
s0 := ""
|
||||
s1 := source()
|
||||
sSlice := []string{s0, s1}
|
||||
sink(test.FunctionWithParameter(sSlice[1])) // $ taintflow dataflow
|
||||
sink(test.FunctionWithSliceParameter(sSlice)) // $ taintflow dataflow
|
||||
sink(test.FunctionWithVarArgsParameter(sSlice...)) // $ taintflow dataflow
|
||||
sink(test.FunctionWithVarArgsParameter(s0, s1)) // $ taintflow dataflow
|
||||
sink(test.FunctionWithParameter(sSlice[1])) // $ hasValueFlow="call to FunctionWithParameter"
|
||||
sink(test.FunctionWithSliceParameter(sSlice)) // $ hasValueFlow="call to FunctionWithSliceParameter"
|
||||
sink(test.FunctionWithVarArgsParameter(sSlice...)) // $ hasValueFlow="call to FunctionWithVarArgsParameter"
|
||||
sink(test.FunctionWithVarArgsParameter(s0, s1)) // $ hasValueFlow="call to FunctionWithVarArgsParameter"
|
||||
|
||||
sliceOfStructs := []test.A{{Field: source()}}
|
||||
sink(sliceOfStructs[0].Field) // $ taintflow dataflow
|
||||
sink(sliceOfStructs[0].Field) // $ hasValueFlow="selection of Field"
|
||||
|
||||
a0 := test.A{Field: ""}
|
||||
a1 := test.A{Field: source()}
|
||||
aSlice := []test.A{a0, a1}
|
||||
sink(test.FunctionWithSliceOfStructsParameter(aSlice)) // $ taintflow dataflow
|
||||
sink(test.FunctionWithVarArgsOfStructsParameter(aSlice...)) // $ taintflow dataflow
|
||||
sink(test.FunctionWithVarArgsOfStructsParameter(a0, a1)) // $ taintflow dataflow
|
||||
sink(test.FunctionWithSliceOfStructsParameter(aSlice)) // $ hasValueFlow="call to FunctionWithSliceOfStructsParameter"
|
||||
sink(test.FunctionWithVarArgsOfStructsParameter(aSlice...)) // $ hasValueFlow="call to FunctionWithVarArgsOfStructsParameter"
|
||||
sink(test.FunctionWithVarArgsOfStructsParameter(a0, a1)) // $ hasValueFlow="call to FunctionWithVarArgsOfStructsParameter"
|
||||
}
|
||||
|
||||
@@ -342,7 +342,7 @@ func test() {
|
||||
{
|
||||
s := source()
|
||||
if guardBool(s) {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
} else {
|
||||
sink(s)
|
||||
}
|
||||
@@ -351,7 +351,7 @@ func test() {
|
||||
{
|
||||
s := source()
|
||||
if guardBoolStmt(s) {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
} else {
|
||||
sink(s)
|
||||
}
|
||||
@@ -362,7 +362,7 @@ func test() {
|
||||
if juggleParams("other arg", s) {
|
||||
sink(s)
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -371,14 +371,14 @@ func test() {
|
||||
if guardBoolNeg(s) {
|
||||
sink(s)
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
s := source()
|
||||
if guardBoolCmp(s) {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
} else {
|
||||
sink(s)
|
||||
}
|
||||
@@ -389,14 +389,14 @@ func test() {
|
||||
if guardBoolNegCmp(s) {
|
||||
sink(s)
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
s := source()
|
||||
if guardBoolLOrLhs(s) {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
} else {
|
||||
sink(s)
|
||||
}
|
||||
@@ -405,16 +405,16 @@ func test() {
|
||||
{
|
||||
s := source()
|
||||
if guardBoolLOrNegLhs(s) {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
s := source()
|
||||
if guardBoolLOrRhs(s) {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
} else {
|
||||
sink(s)
|
||||
}
|
||||
@@ -423,18 +423,18 @@ func test() {
|
||||
{
|
||||
s := source()
|
||||
if guardBoolLOrNegRhs(s) {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
s := source()
|
||||
if guardBoolLAndLhs(s) {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -443,16 +443,16 @@ func test() {
|
||||
if guardBoolLAndNegLhs(s) {
|
||||
sink(s)
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
s := source()
|
||||
if guardBoolLAndRhs(s) {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -461,14 +461,14 @@ func test() {
|
||||
if guardBoolLAndNegRhs(s) {
|
||||
sink(s)
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
s := source()
|
||||
if guardBoolProxy(s) {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
} else {
|
||||
sink(s)
|
||||
}
|
||||
@@ -479,14 +479,14 @@ func test() {
|
||||
if guardBoolNegProxy(s) {
|
||||
sink(s)
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
s := source()
|
||||
if guardBoolCmpProxy(s) {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
} else {
|
||||
sink(s)
|
||||
}
|
||||
@@ -497,14 +497,14 @@ func test() {
|
||||
if guardBoolNegCmpProxy(s) {
|
||||
sink(s)
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
s := source()
|
||||
if guardBoolLOrLhsProxy(s) {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
} else {
|
||||
sink(s)
|
||||
}
|
||||
@@ -513,16 +513,16 @@ func test() {
|
||||
{
|
||||
s := source()
|
||||
if guardBoolLOrNegLhsProxy(s) {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
s := source()
|
||||
if guardBoolLOrRhsProxy(s) {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
} else {
|
||||
sink(s)
|
||||
}
|
||||
@@ -531,18 +531,18 @@ func test() {
|
||||
{
|
||||
s := source()
|
||||
if guardBoolLOrNegRhsProxy(s) {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
s := source()
|
||||
if guardBoolLAndLhsProxy(s) {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -551,16 +551,16 @@ func test() {
|
||||
if guardBoolLAndNegLhsProxy(s) {
|
||||
sink(s)
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
s := source()
|
||||
if guardBoolLAndRhsProxy(s) {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -569,7 +569,7 @@ func test() {
|
||||
if guardBoolLAndNegRhsProxy(s) {
|
||||
sink(s)
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -578,14 +578,14 @@ func test() {
|
||||
if guardProxyNilToBool(s) {
|
||||
sink(s)
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
s := source()
|
||||
if guardNeqProxyNilToBool(s) {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
} else {
|
||||
sink(s)
|
||||
}
|
||||
@@ -594,7 +594,7 @@ func test() {
|
||||
{
|
||||
s := source()
|
||||
if guardNotEqProxyNilToBool(s) {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
} else {
|
||||
sink(s)
|
||||
}
|
||||
@@ -603,7 +603,7 @@ func test() {
|
||||
{
|
||||
s := source()
|
||||
if guardLOrLhsProxyNilToBool(s) {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
} else {
|
||||
sink(s)
|
||||
}
|
||||
@@ -612,16 +612,16 @@ func test() {
|
||||
{
|
||||
s := source()
|
||||
if guardLOrNegLhsProxyNilToBool(s) {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
s := source()
|
||||
if guardLOrRhsProxyNilToBool(s) {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
} else {
|
||||
sink(s)
|
||||
}
|
||||
@@ -630,18 +630,18 @@ func test() {
|
||||
{
|
||||
s := source()
|
||||
if guardLOrNegRhsProxyNilToBool(s) {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
s := source()
|
||||
if guardLAndLhsProxyNilToBool(s) {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -650,16 +650,16 @@ func test() {
|
||||
if guardLAndNegLhsProxyNilToBool(s) {
|
||||
sink(s)
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
s := source()
|
||||
if guardLAndRhsProxyNilToBool(s) {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -668,7 +668,7 @@ func test() {
|
||||
if guardLAndNegRhsProxyNilToBool(s) {
|
||||
sink(s)
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -677,7 +677,7 @@ func test() {
|
||||
if guard(s) == nil {
|
||||
sink(s)
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -686,14 +686,14 @@ func test() {
|
||||
if guardBoolProxyToNil(s) == nil {
|
||||
sink(s)
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
s := source()
|
||||
if guardBoolNegProxyToNil(s) == nil {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
} else {
|
||||
sink(s)
|
||||
}
|
||||
@@ -704,14 +704,14 @@ func test() {
|
||||
if guardBoolCmpProxyToNil(s) == nil {
|
||||
sink(s)
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
s := source()
|
||||
if guardBoolNegCmpProxyToNil(s) == nil {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
} else {
|
||||
sink(s)
|
||||
}
|
||||
@@ -722,16 +722,16 @@ func test() {
|
||||
if guardBoolLOrLhsProxyToNil(s) == nil {
|
||||
sink(s)
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
s := source()
|
||||
if guardBoolLOrNegLhsProxyToNil(s) == nil {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -740,32 +740,32 @@ func test() {
|
||||
if guardBoolLOrRhsProxyToNil(s) == nil {
|
||||
sink(s)
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
s := source()
|
||||
if guardBoolLOrNegRhsProxyToNil(s) == nil {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
s := source()
|
||||
if guardBoolLAndLhsProxyToNil(s) == nil {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
s := source()
|
||||
if guardBoolLAndNegLhsProxyToNil(s) == nil {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
} else {
|
||||
sink(s)
|
||||
}
|
||||
@@ -774,16 +774,16 @@ func test() {
|
||||
{
|
||||
s := source()
|
||||
if guardBoolLAndRhsProxyToNil(s) == nil {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
s := source()
|
||||
if guardBoolLAndNegRhsProxyToNil(s) == nil {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
} else {
|
||||
sink(s)
|
||||
}
|
||||
@@ -794,7 +794,7 @@ func test() {
|
||||
if directProxyNil(s) == nil {
|
||||
sink(s)
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -803,7 +803,7 @@ func test() {
|
||||
if deeplyNestedConditionalLeft(s) {
|
||||
sink(s)
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -812,7 +812,7 @@ func test() {
|
||||
if deeplyNestedConditionalMiddle(s) {
|
||||
sink(s)
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -821,7 +821,7 @@ func test() {
|
||||
if deeplyNestedConditionalRight(s) {
|
||||
sink(s)
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -832,7 +832,7 @@ func test() {
|
||||
s := source()
|
||||
isInvalid := guardBool(s)
|
||||
if isInvalid {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
} else {
|
||||
sink(s)
|
||||
}
|
||||
@@ -842,9 +842,9 @@ func test() {
|
||||
s := source()
|
||||
isValid := !guardBool(s)
|
||||
if isValid {
|
||||
sink(s) // $ SPURIOUS: dataflow=s
|
||||
sink(s) // $ SPURIOUS: hasValueFlow="s"
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasValueFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import go
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
import TestUtilities.InlineFlowTest
|
||||
|
||||
predicate isBad(DataFlow::Node g, Expr e, boolean branch) {
|
||||
g.(DataFlow::CallNode).getTarget().getName() = "isBad" and
|
||||
@@ -7,34 +7,16 @@ predicate isBad(DataFlow::Node g, Expr e, boolean branch) {
|
||||
branch = false
|
||||
}
|
||||
|
||||
class TestConfig extends DataFlow::Configuration {
|
||||
TestConfig() { this = "test config" }
|
||||
module FlowWithBarrierConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource = DefaultFlowConfig::isSource/1;
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source.(DataFlow::CallNode).getTarget().getName() = "source"
|
||||
}
|
||||
predicate isSink = DefaultFlowConfig::isSink/1;
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
sink = any(DataFlow::CallNode c | c.getTarget().getName() = "sink").getAnArgument()
|
||||
}
|
||||
predicate fieldFlowBranchLimit = DefaultFlowConfig::fieldFlowBranchLimit/0;
|
||||
|
||||
override predicate isBarrier(DataFlow::Node node) {
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node = DataFlow::BarrierGuard<isBad/3>::getABarrierNode()
|
||||
}
|
||||
}
|
||||
|
||||
module DataFlowTest implements TestSig {
|
||||
string getARelevantTag() { result = "dataflow" }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
tag = "dataflow" and
|
||||
exists(DataFlow::Node sink | any(TestConfig c).hasFlow(_, sink) |
|
||||
element = sink.toString() and
|
||||
value = sink.toString() and
|
||||
sink.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
|
||||
location.getStartColumn(), location.getEndLine(), location.getEndColumn())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeTest<DataFlowTest>
|
||||
import ValueFlowTest<FlowWithBarrierConfig>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
failures
|
||||
edges
|
||||
| test.go:14:8:14:15 | call to source | test.go:15:34:15:35 | fi |
|
||||
| test.go:15:2:15:44 | ... := ...[0] | test.go:16:7:16:12 | header |
|
||||
|
||||
@@ -1,22 +1,10 @@
|
||||
/**
|
||||
* @kind path-problem
|
||||
*/
|
||||
|
||||
import go
|
||||
import DataFlow::PathGraph
|
||||
import TestUtilities.InlineFlowTest
|
||||
|
||||
class Config extends TaintTracking::Configuration {
|
||||
Config() { this = "config" }
|
||||
module Flow = TaintTracking::Global<DefaultFlowConfig>;
|
||||
|
||||
override predicate isSource(DataFlow::Node n) {
|
||||
n = any(DataFlow::CallNode call | call.getTarget().getName() = "source").getResult()
|
||||
}
|
||||
import Flow::PathGraph
|
||||
|
||||
override predicate isSink(DataFlow::Node n) {
|
||||
n = any(DataFlow::CallNode call | call.getTarget().getName() = "sink").getAnArgument()
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, Config c
|
||||
where c.hasFlowPath(source, sink)
|
||||
from Flow::PathNode source, Flow::PathNode sink
|
||||
where Flow::flowPath(source, sink)
|
||||
select source, source, sink, "Path"
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
import go
|
||||
|
||||
class MyConfiguration extends DataFlow::Configuration {
|
||||
MyConfiguration() { this = "MyConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node nd) {
|
||||
module Config implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node nd) {
|
||||
exists(ValueEntity v, Write w |
|
||||
v.getName().matches("source%") and
|
||||
w.writes(v, nd)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node nd) {
|
||||
predicate isSink(DataFlow::Node nd) {
|
||||
exists(ValueEntity v, Write w |
|
||||
v.getName().matches("sink%") and
|
||||
w.writes(v, nd)
|
||||
@@ -18,6 +16,8 @@ class MyConfiguration extends DataFlow::Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
from MyConfiguration cfg, DataFlow::Node source, DataFlow::Node sink
|
||||
where cfg.hasFlow(source, sink)
|
||||
module Flow = DataFlow::Global<Config>;
|
||||
|
||||
from DataFlow::Node source, DataFlow::Node sink
|
||||
where Flow::flow(source, sink)
|
||||
select source, sink
|
||||
|
||||
@@ -138,14 +138,14 @@ func main() {
|
||||
if switchStatementReturningTrueOnlyWhenConstant(s) {
|
||||
sink(s)
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasTaintFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
s := source()
|
||||
if switchStatementReturningFalseOnlyWhenConstant("", s) {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasTaintFlow="s"
|
||||
} else {
|
||||
sink(s)
|
||||
}
|
||||
@@ -157,7 +157,7 @@ func main() {
|
||||
if err != nil {
|
||||
sink(s)
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasTaintFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,7 +166,7 @@ func main() {
|
||||
if switchStatementReturningNilOnlyWhenConstant(s) == nil {
|
||||
sink(s)
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasTaintFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,25 +175,25 @@ func main() {
|
||||
if multipleSwitchStatementReturningTrueOnlyWhenConstant(s, getRandomString()) {
|
||||
sink(s)
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasTaintFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
s := source()
|
||||
if switchStatementWithoutUsefulInfo(s) {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasTaintFlow="s"
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasTaintFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
s := source()
|
||||
if switchStatementOverRandomString(s) {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasTaintFlow="s"
|
||||
} else {
|
||||
sink(s) // $ dataflow=s
|
||||
sink(s) // $ hasTaintFlow="s"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,30 +1,3 @@
|
||||
import go
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
class TestConfig extends TaintTracking::Configuration {
|
||||
TestConfig() { this = "test config" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source.(DataFlow::CallNode).getTarget().getName() = "source"
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
sink = any(DataFlow::CallNode c | c.getTarget().getName() = "sink").getAnArgument()
|
||||
}
|
||||
}
|
||||
|
||||
module DataFlowTest implements TestSig {
|
||||
string getARelevantTag() { result = "dataflow" }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
tag = "dataflow" and
|
||||
exists(DataFlow::Node sink | any(TestConfig c).hasFlow(_, sink) |
|
||||
element = sink.toString() and
|
||||
value = sink.toString() and
|
||||
sink.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
|
||||
location.getStartColumn(), location.getEndLine(), location.getEndColumn())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeTest<DataFlowTest>
|
||||
import TestUtilities.InlineFlowTest
|
||||
import TaintFlowTest<DefaultFlowConfig>
|
||||
|
||||
@@ -1,39 +1,3 @@
|
||||
import go
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
class SourceFunction extends Function {
|
||||
SourceFunction() { this.getName() = "source" }
|
||||
}
|
||||
|
||||
class SinkFunction extends Function {
|
||||
SinkFunction() { this.getName() = "sink" }
|
||||
}
|
||||
|
||||
class TestConfig extends DataFlow::Configuration {
|
||||
TestConfig() { this = "testconfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source = any(SourceFunction f).getACall().getAResult()
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
sink = any(SinkFunction f).getACall().getAnArgument()
|
||||
}
|
||||
}
|
||||
|
||||
module PromotedFieldsTest implements TestSig {
|
||||
string getARelevantTag() { result = "promotedfields" }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(TestConfig config, DataFlow::PathNode sink |
|
||||
config.hasFlowPath(_, sink) and
|
||||
sink.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
|
||||
location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and
|
||||
element = sink.toString() and
|
||||
value = "" and
|
||||
tag = "promotedfields"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeTest<PromotedFieldsTest>
|
||||
import TestUtilities.InlineFlowTest
|
||||
import ValueFlowTest<DefaultFlowConfig>
|
||||
|
||||
@@ -22,130 +22,130 @@ func testPromotedFieldNamedInitialization() {
|
||||
outer := Outer{
|
||||
Middle: Middle{Inner: Inner{source()}},
|
||||
}
|
||||
sink(outer.field) // $ promotedfields
|
||||
sink(outer.Inner.field) // $ promotedfields
|
||||
sink(outer.Middle.field) // $ promotedfields
|
||||
sink(outer.Middle.Inner.field) // $ promotedfields
|
||||
sink(outer.field) // $ hasValueFlow="selection of field"
|
||||
sink(outer.Inner.field) // $ hasValueFlow="selection of field"
|
||||
sink(outer.Middle.field) // $ hasValueFlow="selection of field"
|
||||
sink(outer.Middle.Inner.field) // $ hasValueFlow="selection of field"
|
||||
|
||||
outerp := &Outer{
|
||||
Middle: Middle{Inner: Inner{source()}},
|
||||
}
|
||||
sink(outerp.field) // $ promotedfields
|
||||
sink(outerp.Inner.field) // $ promotedfields
|
||||
sink(outerp.Middle.field) // $ promotedfields
|
||||
sink(outerp.Middle.Inner.field) // $ promotedfields
|
||||
sink(outerp.field) // $ hasValueFlow="selection of field"
|
||||
sink(outerp.Inner.field) // $ hasValueFlow="selection of field"
|
||||
sink(outerp.Middle.field) // $ hasValueFlow="selection of field"
|
||||
sink(outerp.Middle.Inner.field) // $ hasValueFlow="selection of field"
|
||||
}
|
||||
|
||||
func testPromotedFieldUnnamedInitialization() {
|
||||
outer := Outer{Middle{Inner{source()}}}
|
||||
sink(outer.field) // $ promotedfields
|
||||
sink(outer.Inner.field) // $ promotedfields
|
||||
sink(outer.Middle.field) // $ promotedfields
|
||||
sink(outer.Middle.Inner.field) // $ promotedfields
|
||||
sink(outer.field) // $ hasValueFlow="selection of field"
|
||||
sink(outer.Inner.field) // $ hasValueFlow="selection of field"
|
||||
sink(outer.Middle.field) // $ hasValueFlow="selection of field"
|
||||
sink(outer.Middle.Inner.field) // $ hasValueFlow="selection of field"
|
||||
|
||||
outerp := &Outer{Middle{Inner{source()}}}
|
||||
sink(outerp.field) // $ promotedfields
|
||||
sink(outerp.Inner.field) // $ promotedfields
|
||||
sink(outerp.Middle.field) // $ promotedfields
|
||||
sink(outerp.Middle.Inner.field) // $ promotedfields
|
||||
sink(outerp.field) // $ hasValueFlow="selection of field"
|
||||
sink(outerp.Inner.field) // $ hasValueFlow="selection of field"
|
||||
sink(outerp.Middle.field) // $ hasValueFlow="selection of field"
|
||||
sink(outerp.Middle.Inner.field) // $ hasValueFlow="selection of field"
|
||||
}
|
||||
|
||||
func testPromotedFieldUnnamedInitializationFromVariable() {
|
||||
inner := Inner{source()}
|
||||
middle := Middle{inner}
|
||||
outer := Outer{middle}
|
||||
sink(outer.field) // $ promotedfields
|
||||
sink(outer.Inner.field) // $ promotedfields
|
||||
sink(outer.Middle.field) // $ promotedfields
|
||||
sink(outer.Middle.Inner.field) // $ promotedfields
|
||||
sink(outer.field) // $ hasValueFlow="selection of field"
|
||||
sink(outer.Inner.field) // $ hasValueFlow="selection of field"
|
||||
sink(outer.Middle.field) // $ hasValueFlow="selection of field"
|
||||
sink(outer.Middle.Inner.field) // $ hasValueFlow="selection of field"
|
||||
|
||||
innerp := Inner{source()}
|
||||
middlep := Middle{innerp}
|
||||
outerp := Outer{middlep}
|
||||
sink(outerp.field) // $ promotedfields
|
||||
sink(outerp.Inner.field) // $ promotedfields
|
||||
sink(outerp.Middle.field) // $ promotedfields
|
||||
sink(outerp.Middle.Inner.field) // $ promotedfields
|
||||
sink(outerp.field) // $ hasValueFlow="selection of field"
|
||||
sink(outerp.Inner.field) // $ hasValueFlow="selection of field"
|
||||
sink(outerp.Middle.field) // $ hasValueFlow="selection of field"
|
||||
sink(outerp.Middle.Inner.field) // $ hasValueFlow="selection of field"
|
||||
}
|
||||
|
||||
func testPromotedFieldNamedInitializationFromVariable() {
|
||||
inner := Inner{source()}
|
||||
middle := Middle{Inner: inner}
|
||||
outer := Outer{Middle: middle}
|
||||
sink(outer.field) // $ promotedfields
|
||||
sink(outer.Inner.field) // $ promotedfields
|
||||
sink(outer.Middle.field) // $ promotedfields
|
||||
sink(outer.Middle.Inner.field) // $ promotedfields
|
||||
sink(outer.field) // $ hasValueFlow="selection of field"
|
||||
sink(outer.Inner.field) // $ hasValueFlow="selection of field"
|
||||
sink(outer.Middle.field) // $ hasValueFlow="selection of field"
|
||||
sink(outer.Middle.Inner.field) // $ hasValueFlow="selection of field"
|
||||
|
||||
innerp := Inner{source()}
|
||||
middlep := Middle{Inner: innerp}
|
||||
outerp := Outer{Middle: middlep}
|
||||
sink(outerp.field) // $ promotedfields
|
||||
sink(outerp.Inner.field) // $ promotedfields
|
||||
sink(outerp.Middle.field) // $ promotedfields
|
||||
sink(outerp.Middle.Inner.field) // $ promotedfields
|
||||
sink(outerp.field) // $ hasValueFlow="selection of field"
|
||||
sink(outerp.Inner.field) // $ hasValueFlow="selection of field"
|
||||
sink(outerp.Middle.field) // $ hasValueFlow="selection of field"
|
||||
sink(outerp.Middle.Inner.field) // $ hasValueFlow="selection of field"
|
||||
}
|
||||
|
||||
func testPromotedFieldDirectAssignment() {
|
||||
var outer Outer
|
||||
outer.field = source()
|
||||
sink(outer.field) // $ promotedfields
|
||||
sink(outer.Inner.field) // $ promotedfields
|
||||
sink(outer.Middle.field) // $ promotedfields
|
||||
sink(outer.Middle.Inner.field) // $ promotedfields
|
||||
sink(outer.field) // $ hasValueFlow="selection of field"
|
||||
sink(outer.Inner.field) // $ hasValueFlow="selection of field"
|
||||
sink(outer.Middle.field) // $ hasValueFlow="selection of field"
|
||||
sink(outer.Middle.Inner.field) // $ hasValueFlow="selection of field"
|
||||
|
||||
var outerp Outer
|
||||
outerp.field = source()
|
||||
sink(outerp.field) // $ promotedfields
|
||||
sink(outerp.Inner.field) // $ promotedfields
|
||||
sink(outerp.Middle.field) // $ promotedfields
|
||||
sink(outerp.Middle.Inner.field) // $ promotedfields
|
||||
sink(outerp.field) // $ hasValueFlow="selection of field"
|
||||
sink(outerp.Inner.field) // $ hasValueFlow="selection of field"
|
||||
sink(outerp.Middle.field) // $ hasValueFlow="selection of field"
|
||||
sink(outerp.Middle.Inner.field) // $ hasValueFlow="selection of field"
|
||||
}
|
||||
|
||||
func testPromotedFieldIndirectAssignment1() {
|
||||
var outer Outer
|
||||
outer.Inner.field = source()
|
||||
sink(outer.field) // $ promotedfields
|
||||
sink(outer.Inner.field) // $ promotedfields
|
||||
sink(outer.Middle.field) // $ promotedfields
|
||||
sink(outer.Middle.Inner.field) // $ promotedfields
|
||||
sink(outer.field) // $ hasValueFlow="selection of field"
|
||||
sink(outer.Inner.field) // $ hasValueFlow="selection of field"
|
||||
sink(outer.Middle.field) // $ hasValueFlow="selection of field"
|
||||
sink(outer.Middle.Inner.field) // $ hasValueFlow="selection of field"
|
||||
|
||||
var outerp Outer
|
||||
outerp.Inner.field = source()
|
||||
sink(outerp.field) // $ promotedfields
|
||||
sink(outerp.Inner.field) // $ promotedfields
|
||||
sink(outerp.Middle.field) // $ promotedfields
|
||||
sink(outerp.Middle.Inner.field) // $ promotedfields
|
||||
sink(outerp.field) // $ hasValueFlow="selection of field"
|
||||
sink(outerp.Inner.field) // $ hasValueFlow="selection of field"
|
||||
sink(outerp.Middle.field) // $ hasValueFlow="selection of field"
|
||||
sink(outerp.Middle.Inner.field) // $ hasValueFlow="selection of field"
|
||||
}
|
||||
|
||||
func testPromotedFieldIndirectAssignment2() {
|
||||
var outer Outer
|
||||
outer.Middle.field = source()
|
||||
sink(outer.field) // $ promotedfields
|
||||
sink(outer.Inner.field) // $ promotedfields
|
||||
sink(outer.Middle.field) // $ promotedfields
|
||||
sink(outer.Middle.Inner.field) // $ promotedfields
|
||||
sink(outer.field) // $ hasValueFlow="selection of field"
|
||||
sink(outer.Inner.field) // $ hasValueFlow="selection of field"
|
||||
sink(outer.Middle.field) // $ hasValueFlow="selection of field"
|
||||
sink(outer.Middle.Inner.field) // $ hasValueFlow="selection of field"
|
||||
|
||||
var outerp Outer
|
||||
outerp.Middle.field = source()
|
||||
sink(outerp.field) // $ promotedfields
|
||||
sink(outerp.Inner.field) // $ promotedfields
|
||||
sink(outerp.Middle.field) // $ promotedfields
|
||||
sink(outerp.Middle.Inner.field) // $ promotedfields
|
||||
sink(outerp.field) // $ hasValueFlow="selection of field"
|
||||
sink(outerp.Inner.field) // $ hasValueFlow="selection of field"
|
||||
sink(outerp.Middle.field) // $ hasValueFlow="selection of field"
|
||||
sink(outerp.Middle.Inner.field) // $ hasValueFlow="selection of field"
|
||||
}
|
||||
|
||||
func testPromotedFieldIndirectAssignment3() {
|
||||
var outer Outer
|
||||
outer.Middle.Inner.field = source()
|
||||
sink(outer.field) // $ promotedfields
|
||||
sink(outer.Inner.field) // $ promotedfields
|
||||
sink(outer.Middle.field) // $ promotedfields
|
||||
sink(outer.Middle.Inner.field) // $ promotedfields
|
||||
sink(outer.field) // $ hasValueFlow="selection of field"
|
||||
sink(outer.Inner.field) // $ hasValueFlow="selection of field"
|
||||
sink(outer.Middle.field) // $ hasValueFlow="selection of field"
|
||||
sink(outer.Middle.Inner.field) // $ hasValueFlow="selection of field"
|
||||
|
||||
var outerp Outer
|
||||
outerp.Middle.Inner.field = source()
|
||||
sink(outerp.field) // $ promotedfields
|
||||
sink(outerp.Inner.field) // $ promotedfields
|
||||
sink(outerp.Middle.field) // $ promotedfields
|
||||
sink(outerp.Middle.Inner.field) // $ promotedfields
|
||||
sink(outerp.field) // $ hasValueFlow="selection of field"
|
||||
sink(outerp.Inner.field) // $ hasValueFlow="selection of field"
|
||||
sink(outerp.Middle.field) // $ hasValueFlow="selection of field"
|
||||
sink(outerp.Middle.Inner.field) // $ hasValueFlow="selection of field"
|
||||
}
|
||||
|
||||
@@ -1,33 +1,13 @@
|
||||
import go
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
import TestUtilities.InlineFlowTest
|
||||
|
||||
class SourceFunction extends Function {
|
||||
SourceFunction() { this.getName() = "source" }
|
||||
}
|
||||
|
||||
class SinkFunction extends Function {
|
||||
SinkFunction() { this.getName() = "sink" }
|
||||
}
|
||||
|
||||
class TestConfig extends DataFlow::Configuration {
|
||||
TestConfig() { this = "testconfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source = any(SourceFunction f).getACall().getAResult()
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
sink = any(SinkFunction f).getACall().getAnArgument()
|
||||
}
|
||||
}
|
||||
module ValueFlow = DataFlow::Global<DefaultFlowConfig>;
|
||||
|
||||
module PromotedMethodsTest implements TestSig {
|
||||
string getARelevantTag() { result = "promotedmethods" }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(TestConfig config, DataFlow::Node source, DataFlow::Node sink |
|
||||
config.hasFlow(source, sink)
|
||||
|
|
||||
exists(DataFlow::Node source, DataFlow::Node sink | ValueFlow::flow(source, sink) |
|
||||
sink.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
|
||||
location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and
|
||||
element = sink.toString() and
|
||||
|
||||
@@ -1,30 +1,3 @@
|
||||
import go
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
class Configuration extends DataFlow::Configuration {
|
||||
Configuration() { this = "test-configuration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source = any(DataFlow::CallNode c | c.getCalleeName() = "src").getResult(0)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
sink = any(DataFlow::CallNode c | c.getCalleeName() = "sink").getArgument(0)
|
||||
}
|
||||
}
|
||||
|
||||
module DataFlowTest implements TestSig {
|
||||
string getARelevantTag() { result = "dataflow" }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
tag = "dataflow" and
|
||||
exists(DataFlow::Node sink | any(Configuration c).hasFlow(_, sink) |
|
||||
element = sink.toString() and
|
||||
value = sink.toString() and
|
||||
sink.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
|
||||
location.getStartColumn(), location.getEndLine(), location.getEndColumn())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeTest<DataFlowTest>
|
||||
import TestUtilities.InlineFlowTest
|
||||
import DefaultFlowTest
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
package main
|
||||
|
||||
func src() interface{} {
|
||||
func source() interface{} {
|
||||
return "hi"
|
||||
}
|
||||
|
||||
func sink(p interface{}) {}
|
||||
|
||||
func test() (bool, *string) {
|
||||
ptr := src()
|
||||
sink(ptr) // $ dataflow=ptr
|
||||
ptr := source()
|
||||
sink(ptr) // $ hasValueFlow="ptr"
|
||||
cast := ptr.(*string)
|
||||
sink(cast) // $ dataflow=cast
|
||||
sink(cast) // $ hasValueFlow="cast"
|
||||
cast2, ok := ptr.(*string)
|
||||
if !ok {
|
||||
return true, nil
|
||||
}
|
||||
sink(cast2) // $ dataflow=cast2
|
||||
sink(cast2) // $ hasValueFlow="cast2"
|
||||
var cast3, ok2 = ptr.(*string)
|
||||
if !ok2 {
|
||||
return true, nil
|
||||
}
|
||||
sink(cast3) // $ dataflow=cast3
|
||||
sink(cast3) // $ hasValueFlow="cast3"
|
||||
cast2, ok = ptr.(*string)
|
||||
if !ok {
|
||||
return true, nil
|
||||
}
|
||||
sink(cast2) // $ dataflow=cast2
|
||||
sink(cast2) // $ hasValueFlow="cast2"
|
||||
return true, nil
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user