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:
Owen Mansel-Chan
2023-08-11 10:49:51 +01:00
committed by GitHub
138 changed files with 2468 additions and 2524 deletions

View File

@@ -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"
]
}
}

View File

@@ -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
(

View File

@@ -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
}

View File

@@ -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;

View File

@@ -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>;
}

View File

@@ -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>;
}

View File

@@ -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>;
}

View File

@@ -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 */

View File

@@ -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)
}

View File

@@ -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>;
}

View File

@@ -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>;
}

View File

@@ -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>;
}

View File

@@ -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>;
}

View File

@@ -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>;
}

View File

@@ -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>;
}

View File

@@ -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>;
}

View File

@@ -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>;
}

View File

@@ -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>;
}

View File

@@ -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>;
}

View File

@@ -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>;
}

View File

@@ -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>;
}

View File

@@ -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>;
}

View File

@@ -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>;
}

View File

@@ -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)

View File

@@ -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"

View File

@@ -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

View File

@@ -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"

View File

@@ -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()

View File

@@ -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()

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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()

View File

@@ -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)

View File

@@ -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."

View File

@@ -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()]

View File

@@ -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, _, _, _)
|

View File

@@ -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)

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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>;
}

View File

@@ -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"

View File

@@ -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()

View File

@@ -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"

View File

@@ -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"

View File

@@ -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>;

View File

@@ -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>;

View File

@@ -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."

View File

@@ -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"

View File

@@ -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."

View File

@@ -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"

View File

@@ -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>;
}

View File

@@ -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"

View File

@@ -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>;
}

View File

@@ -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."

View File

@@ -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"

View File

@@ -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() {

View File

@@ -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"

View File

@@ -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"

View File

@@ -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,

View File

@@ -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>;

View File

@@ -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"

View File

@@ -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."

View File

@@ -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 { }

View File

@@ -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())
)

View File

@@ -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

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -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"
}
}
}

View File

@@ -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

View File

@@ -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"
}
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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"
}

View File

@@ -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] |

View File

@@ -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"

View File

@@ -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

View File

@@ -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"
}

View File

@@ -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"
}
}

View File

@@ -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>

View File

@@ -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 |

View File

@@ -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"

View File

@@ -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

View File

@@ -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"
}
}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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"
}

View File

@@ -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

View File

@@ -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

View File

@@ -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