Merge pull request #17535 from asgerf/jss/use-use-flow

JS: Follow use-use flow after a post-update
This commit is contained in:
Asger F 2024-11-18 12:48:58 +01:00 коммит произвёл GitHub
Родитель 443987b484 80ee372ddf
Коммит 33b7ba41ca
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
38 изменённых файлов: 1216 добавлений и 624 удалений

Просмотреть файл

@ -9,6 +9,7 @@ dependencies:
codeql/dataflow: ${workspace}
codeql/mad: ${workspace}
codeql/regex: ${workspace}
codeql/ssa: ${workspace}
codeql/tutorial: ${workspace}
codeql/util: ${workspace}
codeql/xml: ${workspace}

Просмотреть файл

@ -3,356 +3,4 @@
* liveness information for local variables.
*/
import javascript
private import internal.StmtContainers
private import semmle.javascript.internal.CachedStages
/**
* Holds if `nd` starts a new basic block.
*/
private predicate startsBB(ControlFlowNode nd) {
not exists(nd.getAPredecessor()) and exists(nd.getASuccessor())
or
nd.isJoin()
or
nd.getAPredecessor().isBranch()
}
/**
* Holds if the first node of basic block `succ` is a control flow
* successor of the last node of basic block `bb`.
*/
private predicate succBB(BasicBlock bb, BasicBlock succ) { succ = bb.getLastNode().getASuccessor() }
/**
* Holds if the first node of basic block `bb` is a control flow
* successor of the last node of basic block `pre`.
*/
private predicate predBB(BasicBlock bb, BasicBlock pre) { succBB(pre, bb) }
/** Holds if `bb` is an entry basic block. */
private predicate entryBB(BasicBlock bb) { bb.getFirstNode() instanceof ControlFlowEntryNode }
/** Holds if `bb` is an exit basic block. */
private predicate exitBB(BasicBlock bb) { bb.getLastNode() instanceof ControlFlowExitNode }
cached
private module Internal {
/**
* Holds if `succ` is a control flow successor of `nd` within the same basic block.
*/
private predicate intraBBSucc(ControlFlowNode nd, ControlFlowNode succ) {
succ = nd.getASuccessor() and
not succ instanceof BasicBlock
}
/**
* Holds if `nd` is the `i`th node in basic block `bb`.
*
* In other words, `i` is the shortest distance from a node `bb`
* that starts a basic block to `nd` along the `intraBBSucc` relation.
*/
cached
predicate bbIndex(BasicBlock bb, ControlFlowNode nd, int i) =
shortestDistances(startsBB/1, intraBBSucc/2)(bb, nd, i)
cached
int bbLength(BasicBlock bb) { result = strictcount(ControlFlowNode nd | bbIndex(bb, nd, _)) }
cached
predicate useAt(BasicBlock bb, int i, Variable v, VarUse u) {
Stages::BasicBlocks::ref() and
v = u.getVariable() and
bbIndex(bb, u, i)
}
cached
predicate defAt(BasicBlock bb, int i, Variable v, VarDef d) {
exists(VarRef lhs |
lhs = d.getTarget().(BindingPattern).getABindingVarRef() and
v = lhs.getVariable()
|
lhs = d.getTarget() and
bbIndex(bb, d, i)
or
exists(PropertyPattern pp |
lhs = pp.getValuePattern() and
bbIndex(bb, pp, i)
)
or
exists(ObjectPattern op |
lhs = op.getRest() and
bbIndex(bb, lhs, i)
)
or
exists(ArrayPattern ap |
lhs = ap.getAnElement() and
bbIndex(bb, lhs, i)
)
)
}
cached
predicate reachableBB(BasicBlock bb) {
entryBB(bb)
or
exists(BasicBlock predBB | succBB(predBB, bb) | reachableBB(predBB))
}
}
private import Internal
/** Holds if `dom` is an immediate dominator of `bb`. */
cached
private predicate bbIDominates(BasicBlock dom, BasicBlock bb) =
idominance(entryBB/1, succBB/2)(_, dom, bb)
/** Holds if `dom` is an immediate post-dominator of `bb`. */
cached
private predicate bbIPostDominates(BasicBlock dom, BasicBlock bb) =
idominance(exitBB/1, predBB/2)(_, dom, bb)
/**
* A basic block, that is, a maximal straight-line sequence of control flow nodes
* without branches or joins.
*
* At the database level, a basic block is represented by its first control flow node.
*/
class BasicBlock extends @cfg_node, NodeInStmtContainer {
cached
BasicBlock() { Stages::BasicBlocks::ref() and startsBB(this) }
/** Gets a basic block succeeding this one. */
BasicBlock getASuccessor() { succBB(this, result) }
/** Gets a basic block preceding this one. */
BasicBlock getAPredecessor() { result.getASuccessor() = this }
/** Gets a node in this block. */
ControlFlowNode getANode() { result = this.getNode(_) }
/** Gets the node at the given position in this block. */
ControlFlowNode getNode(int pos) { bbIndex(this, result, pos) }
/** Gets the first node in this block. */
ControlFlowNode getFirstNode() { result = this }
/** Gets the last node in this block. */
ControlFlowNode getLastNode() { result = this.getNode(this.length() - 1) }
/** Gets the length of this block. */
int length() { result = bbLength(this) }
/** Holds if this basic block uses variable `v` in its `i`th node `u`. */
predicate useAt(int i, Variable v, VarUse u) { useAt(this, i, v, u) }
/** Holds if this basic block defines variable `v` in its `i`th node `d`. */
predicate defAt(int i, Variable v, VarDef d) { defAt(this, i, v, d) }
/**
* Holds if `v` is live at entry to this basic block and `u` is a use of `v`
* witnessing the liveness.
*
* In other words, `u` is a use of `v` that is reachable from the
* entry node of this basic block without going through a redefinition
* of `v`. The use `u` may either be in this basic block, or in another
* basic block reachable from this one.
*/
predicate isLiveAtEntry(Variable v, VarUse u) {
// restrict `u` to be reachable from this basic block
u = this.getASuccessor*().getANode() and
(
// shortcut: if `v` is never defined, then it must be live
this.isDefinedInSameContainer(v)
implies
// otherwise, do full liveness computation
this.isLiveAtEntryImpl(v, u)
)
}
/**
* Holds if `v` is live at entry to this basic block and `u` is a use of `v`
* witnessing the liveness, where `v` is defined at least once in the enclosing
* function or script.
*/
private predicate isLiveAtEntryImpl(Variable v, VarUse u) {
this.isLocallyLiveAtEntry(v, u)
or
this.isDefinedInSameContainer(v) and
not this.defAt(_, v, _) and
this.getASuccessor().isLiveAtEntryImpl(v, u)
}
/**
* Holds if `v` is defined at least once in the function or script to which
* this basic block belongs.
*/
private predicate isDefinedInSameContainer(Variable v) {
exists(VarDef def | def.getAVariable() = v and def.getContainer() = this.getContainer())
}
/**
* Holds if `v` is a variable that is live at entry to this basic block.
*
* Note that this is equivalent to `bb.isLiveAtEntry(v, _)`, but may
* be more efficient on large databases.
*/
predicate isLiveAtEntry(Variable v) {
this.isLocallyLiveAtEntry(v, _)
or
not this.defAt(_, v, _) and this.getASuccessor().isLiveAtEntry(v)
}
/**
* Holds if local variable `v` is live at entry to this basic block and
* `u` is a use of `v` witnessing the liveness.
*/
predicate localIsLiveAtEntry(LocalVariable v, VarUse u) {
this.isLocallyLiveAtEntry(v, u)
or
not this.defAt(_, v, _) and this.getASuccessor().localIsLiveAtEntry(v, u)
}
/**
* Holds if local variable `v` is live at entry to this basic block.
*/
predicate localIsLiveAtEntry(LocalVariable v) {
this.isLocallyLiveAtEntry(v, _)
or
not this.defAt(_, v, _) and this.getASuccessor().localIsLiveAtEntry(v)
}
/**
* Holds if `d` is a definition of `v` that is reachable from the beginning of
* this basic block without going through a redefinition of `v`.
*/
predicate localMayBeOverwritten(LocalVariable v, VarDef d) {
this.isLocallyOverwritten(v, d)
or
not this.defAt(_, v, _) and this.getASuccessor().localMayBeOverwritten(v, d)
}
/**
* Gets the next index after `i` in this basic block at which `v` is
* defined or used, provided that `d` is a definition of `v` at index `i`.
* If there are no further uses or definitions of `v` after `i`, the
* result is the length of this basic block.
*/
private int nextDefOrUseAfter(PurelyLocalVariable v, int i, VarDef d) {
this.defAt(i, v, d) and
result =
min(int j |
(this.defAt(j, v, _) or this.useAt(j, v, _) or j = this.length()) and
j > i
)
}
/**
* Holds if `d` defines variable `v` at the `i`th node of this basic block, and
* the definition is live, that is, the variable may be read after this
* definition and before a re-definition.
*/
predicate localLiveDefAt(PurelyLocalVariable v, int i, VarDef d) {
exists(int j | j = this.nextDefOrUseAfter(v, i, d) |
this.useAt(j, v, _)
or
j = this.length() and this.getASuccessor().localIsLiveAtEntry(v)
)
}
/**
* Holds if `u` is a use of `v` in this basic block, and there are
* no definitions of `v` before it.
*/
private predicate isLocallyLiveAtEntry(Variable v, VarUse u) {
exists(int n | this.useAt(n, v, u) | not exists(int m | m < n | this.defAt(m, v, _)))
}
/**
* Holds if `d` is a definition of `v` in this basic block, and there are
* no other definitions of `v` before it.
*/
private predicate isLocallyOverwritten(Variable v, VarDef d) {
exists(int n | this.defAt(n, v, d) | not exists(int m | m < n | this.defAt(m, v, _)))
}
/**
* Gets the basic block that immediately dominates this basic block.
*/
ReachableBasicBlock getImmediateDominator() { bbIDominates(result, this) }
}
/**
* An unreachable basic block, that is, a basic block
* whose first node is unreachable.
*/
class UnreachableBlock extends BasicBlock {
UnreachableBlock() { this.getFirstNode().isUnreachable() }
}
/**
* An entry basic block, that is, a basic block
* whose first node is the entry node of a statement container.
*/
class EntryBasicBlock extends BasicBlock {
EntryBasicBlock() { entryBB(this) }
}
/**
* A basic block that is reachable from an entry basic block.
*/
class ReachableBasicBlock extends BasicBlock {
ReachableBasicBlock() { reachableBB(this) }
/**
* Holds if this basic block strictly dominates `bb`.
*/
pragma[inline]
predicate strictlyDominates(ReachableBasicBlock bb) { bbIDominates+(this, bb) }
/**
* Holds if this basic block dominates `bb`.
*
* This predicate is reflexive: each reachable basic block dominates itself.
*/
pragma[inline]
predicate dominates(ReachableBasicBlock bb) { bbIDominates*(this, bb) }
/**
* Holds if this basic block strictly post-dominates `bb`.
*/
pragma[inline]
predicate strictlyPostDominates(ReachableBasicBlock bb) { bbIPostDominates+(this, bb) }
/**
* Holds if this basic block post-dominates `bb`.
*
* This predicate is reflexive: each reachable basic block post-dominates itself.
*/
pragma[inline]
predicate postDominates(ReachableBasicBlock bb) { bbIPostDominates*(this, bb) }
}
/**
* A reachable basic block with more than one predecessor.
*/
class ReachableJoinBlock extends ReachableBasicBlock {
ReachableJoinBlock() { this.getFirstNode().isJoin() }
/**
* Holds if this basic block belongs to the dominance frontier of `b`, that is
* `b` dominates a predecessor of this block, but not this block itself.
*
* Algorithm from Cooper et al., "A Simple, Fast Dominance Algorithm" (Figure 5),
* who in turn attribute it to Ferrante et al., "The program dependence graph and
* its use in optimization".
*/
predicate inDominanceFrontierOf(ReachableBasicBlock b) {
b = this.getAPredecessor() and not b = this.getImmediateDominator()
or
exists(ReachableBasicBlock prev | this.inDominanceFrontierOf(prev) |
b = prev.getImmediateDominator() and
not b = this.getImmediateDominator()
)
}
}
import internal.BasicBlockInternal::Public

Просмотреть файл

@ -26,6 +26,7 @@ private import internal.AnalyzedParameters
private import internal.PreCallGraphStep
private import semmle.javascript.internal.CachedStages
private import semmle.javascript.dataflow.internal.DataFlowPrivate as Private
private import semmle.javascript.dataflow.internal.VariableOrThis
module DataFlow {
/**
@ -729,9 +730,7 @@ module DataFlow {
private class ParameterFieldAsPropWrite extends PropWrite, PropNode {
override ParameterField prop;
override Node getBase() {
thisNode(result, prop.getDeclaringClass().getConstructor().getBody())
}
override Node getBase() { result = TImplicitThisUse(prop, false) }
override Expr getPropertyNameExpr() {
none() // The parameter value is not the name of the field
@ -758,9 +757,7 @@ module DataFlow {
exists(prop.getInit())
}
override Node getBase() {
thisNode(result, prop.getDeclaringClass().getConstructor().getBody())
}
override Node getBase() { result = TImplicitThisUse(prop, false) }
override Expr getPropertyNameExpr() { result = prop.getNameExpr() }
@ -1045,12 +1042,12 @@ module DataFlow {
}
/**
* A node representing the value passed as `this` argument in a `new` call or a `super` call.
* A node representing the value passed as `this` argument in a `new` call.
*/
class ConstructorThisArgumentNode extends TConstructorThisArgumentNode, DataFlow::Node {
private InvokeExpr expr;
class NewCallThisArgumentNode extends TNewCallThisArgument, DataFlow::Node {
private NewExpr expr;
ConstructorThisArgumentNode() { this = TConstructorThisArgumentNode(expr) }
NewCallThisArgumentNode() { this = TNewCallThisArgument(expr) }
override string toString() { result = "implicit 'this' argument of " + expr }
@ -1060,18 +1057,23 @@ module DataFlow {
}
/**
* A node representing the post-update node corresponding to implicit uses of `this` in a constructor.
* A node representing an implicit use of `this` or its post-update node.
*/
private class ConstructorThisPostUpdateNode extends TConstructorThisPostUpdate, DataFlow::Node {
private Function constructor;
private class ImplicitThisUseNode extends TImplicitThisUse, DataFlow::Node {
private ImplicitThisUse use;
private boolean isPost;
ConstructorThisPostUpdateNode() { this = TConstructorThisPostUpdate(constructor) }
ImplicitThisUseNode() { this = TImplicitThisUse(use, isPost) }
override string toString() { result = "[post-update] 'this' parameter of " + constructor }
override string toString() {
if isPost = false
then result = "implicit 'this'"
else result = "[post-update] implicit 'this'"
}
override StmtContainer getContainer() { result = constructor }
override StmtContainer getContainer() { result = use.getUseContainer() }
override Location getLocation() { result = constructor.getLocation() }
override Location getLocation() { result = use.getLocation() }
}
/**
@ -1682,6 +1684,12 @@ module DataFlow {
pred = TReflectiveCallNode(call, _) and
succ = TValueNode(call)
)
or
// Pass 'this' into implicit uses of 'this'
exists(ImplicitThisUse use |
pred = TThisNode(use.getBindingContainer()) and
succ = TImplicitThisUse(use, false)
)
}
pragma[nomagic]
@ -1772,12 +1780,6 @@ module DataFlow {
pred = TReflectiveParametersNode(f) and
succ = TValueNode(f.getArgumentsVariable().getAnAccess())
)
or
// Pass 'this' into super calls
exists(SuperCall call |
pred = TThisNode(call.getBinder()) and
succ = TConstructorThisArgumentNode(call)
)
}
private class ReflectiveParamsStep extends LegacyPreCallGraphStep {

Просмотреть файл

@ -6,6 +6,8 @@
private import javascript
private import semmle.javascript.dataflow.internal.AccessPaths
private import semmle.javascript.dataflow.internal.DataFlowPrivate as DataFlowPrivate
private import semmle.javascript.dataflow.internal.sharedlib.Ssa as Ssa2
private signature class BarrierGuardSig extends DataFlow::Node {
/**
@ -282,6 +284,22 @@ module MakeStateBarrierGuard<
)
}
private predicate ssa2GuardChecks(
Ssa2::SsaDataflowInput::Guard guard, Ssa2::SsaDataflowInput::Expr test, boolean branch,
FlowState state
) {
exists(BarrierGuard g |
g.asExpr() = guard and
g.blocksExpr(branch, test, state)
)
}
private module Ssa2Barrier = Ssa2::BarrierGuardWithState<FlowState, ssa2GuardChecks/4>;
private predicate ssa2BlocksNode(DataFlow::Node node, FlowState state) {
node = DataFlowPrivate::getNodeFromSsa2(Ssa2Barrier::getABarrierNode(state))
}
/** Holds if a barrier guard blocks uses of `ap` in basic blocks dominated by `cond`. */
pragma[nomagic]
private predicate barrierGuardBlocksAccessPathIn(
@ -323,6 +341,8 @@ module MakeStateBarrierGuard<
barrierGuardBlocksAccessPathUse(use, state) and
nd = DataFlow::valueNode(use)
)
or
ssa2BlocksNode(nd, state)
}
/**

Просмотреть файл

@ -1,6 +1,7 @@
private import javascript
private import semmle.javascript.frameworks.data.internal.ApiGraphModels as ApiGraphModels
private import semmle.javascript.dataflow.internal.FlowSummaryPrivate as FlowSummaryPrivate
private import semmle.javascript.dataflow.internal.VariableOrThis
private import codeql.dataflow.internal.AccessPathSyntax as AccessPathSyntax
module Private {
@ -75,7 +76,7 @@ module Private {
MkIteratorError() or
MkPromiseValue() or
MkPromiseError() or
MkCapturedContent(LocalVariable v) { v.isCaptured() }
MkCapturedContent(LocalVariableOrThis v) { v.isCaptured() }
cached
newtype TContentSet =
@ -163,7 +164,7 @@ module Public {
int asArrayIndex() { result = this.asPropertyName().(PropertyName).asArrayIndex() }
/** Gets the captured variable represented by this content, if any. */
LocalVariable asCapturedVariable() { this = MkCapturedContent(result) }
LocalVariableOrThis asCapturedVariable() { this = MkCapturedContent(result) }
/** Holds if this represents values stored at an unknown array index. */
predicate isUnknownArrayElement() { this = MkArrayElementUnknown() }

Просмотреть файл

@ -5,13 +5,16 @@
*/
private import javascript
private import codeql.util.Boolean
private import semmle.javascript.dataflow.internal.AdditionalFlowInternal
private import semmle.javascript.dataflow.internal.Contents::Private
private import semmle.javascript.dataflow.internal.sharedlib.DataFlowImplCommon as DataFlowImplCommon
private import semmle.javascript.dataflow.internal.sharedlib.Ssa as Ssa2
private import semmle.javascript.dataflow.internal.DataFlowPrivate as DataFlowPrivate
private import semmle.javascript.dataflow.internal.sharedlib.FlowSummaryImpl as FlowSummaryImpl
private import semmle.javascript.dataflow.internal.FlowSummaryPrivate as FlowSummaryPrivate
private import semmle.javascript.dataflow.internal.VariableCapture as VariableCapture
private import semmle.javascript.dataflow.internal.VariableOrThis
cached
private module Cached {
@ -27,7 +30,14 @@ private module Cached {
cached
newtype TNode =
TValueNode(AST::ValueNode nd) or
/** An SSA node from the legacy SSA library */
TSsaDefNode(SsaDefinition d) or
/** Use of a variable or 'this', with flow from a post-update node (from an earlier use) */
TSsaUseNode(ControlFlowNode use) { use = any(Ssa2::SsaConfig::SourceVariable v).getAUse() } or
/** Phi-read node (new SSA library). Ordinary phi nodes are represented by TSsaDefNode. */
TSsaPhiReadNode(Ssa2::PhiReadNode phi) or
/** Input to a phi node (new SSA library) */
TSsaInputNode(Ssa2::SsaInputNode input) or
TCapturedVariableNode(LocalVariable v) { v.isCaptured() } or
TPropNode(@property p) or
TRestPatternNode(DestructuringPattern dp, Expr rest) { rest = dp.getRest() } or
@ -80,8 +90,8 @@ private module Cached {
// The RHS of an assignment can be an argument to a setter-call, so it needs a post-update node
e = any(Assignment asn | asn.getTarget() instanceof PropAccess).getRhs()
} or
TConstructorThisArgumentNode(InvokeExpr e) { e instanceof NewExpr or e instanceof SuperCall } or
TConstructorThisPostUpdate(Constructor ctor) or
TNewCallThisArgument(NewExpr e) or
TImplicitThisUse(ImplicitThisUse use, Boolean isPost) or
TFlowSummaryNode(FlowSummaryImpl::Private::SummaryNode sn) or
TFlowSummaryDynamicParameterArrayNode(FlowSummaryImpl::Public::SummarizedCallable callable) or
TFlowSummaryIntermediateAwaitStoreNode(FlowSummaryImpl::Private::SummaryNode sn) {
@ -122,8 +132,9 @@ private class TEarlyStageNode =
TFunctionSelfReferenceNode or TDestructuredModuleImportNode or THtmlAttributeNode or
TFunctionReturnNode or TExceptionalFunctionReturnNode or TExceptionalInvocationReturnNode or
TGlobalAccessPathRoot or TTemplatePlaceholderTag or TReflectiveParametersNode or
TExprPostUpdateNode or TConstructorThisArgumentNode or TStaticArgumentArrayNode or
TDynamicArgumentArrayNode or TStaticParameterArrayNode or TDynamicParameterArrayNode;
TExprPostUpdateNode or TNewCallThisArgument or TStaticArgumentArrayNode or
TDynamicArgumentArrayNode or TStaticParameterArrayNode or TDynamicParameterArrayNode or
TImplicitThisUse;
/**
* A data-flow node that is not a flow summary node.

Просмотреть файл

@ -5,7 +5,9 @@ private import semmle.javascript.dataflow.internal.FlowSteps as FlowSteps
private import semmle.javascript.dataflow.internal.AdditionalFlowInternal
private import semmle.javascript.dataflow.internal.Contents::Private
private import semmle.javascript.dataflow.internal.VariableCapture
private import semmle.javascript.dataflow.internal.VariableOrThis
private import semmle.javascript.dataflow.internal.sharedlib.DataFlowImplCommon as DataFlowImplCommon
private import semmle.javascript.dataflow.internal.sharedlib.Ssa as Ssa2
private import semmle.javascript.internal.flow_summaries.AllFlowSummaries
private import sharedlib.FlowSummaryImpl as FlowSummaryImpl
private import semmle.javascript.dataflow.internal.FlowSummaryPrivate as FlowSummaryPrivate
@ -18,6 +20,56 @@ private class Node = DataFlow::Node;
class PostUpdateNode = DataFlow::PostUpdateNode;
// TODO: this bypasses refinement nodes, and therefore some sanitisers
class SsaUseNode extends DataFlow::Node, TSsaUseNode {
private ControlFlowNode expr;
SsaUseNode() { this = TSsaUseNode(expr) }
cached
override string toString() { result = "[ssa-use] " + expr.toString() }
cached
override StmtContainer getContainer() { result = expr.getContainer() }
cached
override Location getLocation() { result = expr.getLocation() }
}
class SsaPhiReadNode extends DataFlow::Node, TSsaPhiReadNode {
private Ssa2::PhiReadNode phi;
SsaPhiReadNode() { this = TSsaPhiReadNode(phi) }
cached
override string toString() { result = "[ssa-phi-read] " + phi.getSourceVariable().getName() }
cached
override StmtContainer getContainer() { result = phi.getSourceVariable().getDeclaringContainer() }
cached
override Location getLocation() { result = phi.getLocation() }
}
class SsaInputNode extends DataFlow::Node, TSsaInputNode {
private Ssa2::SsaInputNode input;
SsaInputNode() { this = TSsaInputNode(input) }
cached
override string toString() {
result = "[ssa-input] " + input.getDefinitionExt().getSourceVariable().getName()
}
cached
override StmtContainer getContainer() {
result = input.getDefinitionExt().getSourceVariable().getDeclaringContainer()
}
cached
override Location getLocation() { result = input.getLocation() }
}
class FlowSummaryNode extends DataFlow::Node, TFlowSummaryNode {
FlowSummaryImpl::Private::SummaryNode getSummaryNode() { this = TFlowSummaryNode(result) }
@ -282,18 +334,13 @@ predicate postUpdatePair(Node pre, Node post) {
)
or
exists(NewExpr expr |
pre = TConstructorThisArgumentNode(expr) and
pre = TNewCallThisArgument(expr) and
post = TValueNode(expr)
)
or
exists(SuperCall expr |
pre = TConstructorThisArgumentNode(expr) and
post = TConstructorThisPostUpdate(expr.getBinder())
)
or
exists(Function constructor |
pre = TThisNode(constructor) and
post = TConstructorThisPostUpdate(constructor)
exists(ImplicitThisUse use |
pre = TImplicitThisUse(use, false) and
post = TImplicitThisUse(use, true)
)
or
FlowSummaryImpl::Private::summaryPostUpdateNode(post.(FlowSummaryNode).getSummaryNode(),
@ -422,7 +469,10 @@ private predicate isArgumentNodeImpl(Node n, DataFlowCall call, ArgumentPosition
pos.isThis()
)
or
pos.isThis() and n = TConstructorThisArgumentNode(call.asOrdinaryCall().asExpr())
pos.isThis() and n = TNewCallThisArgument(call.asOrdinaryCall().asExpr())
or
pos.isThis() and
n = TImplicitThisUse(call.asOrdinaryCall().asExpr().(SuperCall).getCallee(), false)
or
// receiver of accessor call
pos.isThis() and n = call.asAccessorCall().getBase()
@ -535,6 +585,12 @@ predicate nodeIsHidden(Node node) {
node instanceof DynamicParameterArrayNode
or
node instanceof RestParameterStoreNode
or
node instanceof SsaUseNode
or
node instanceof SsaPhiReadNode
or
node instanceof SsaInputNode
}
predicate neverSkipInPathGraph(Node node) {
@ -938,12 +994,6 @@ predicate mayBenefitFromCallContext(DataFlowCall call) { none() }
*/
DataFlowCallable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) { none() }
bindingset[node1, node2]
pragma[inline_late]
private predicate sameContainer(Node node1, Node node2) {
node1.getContainer() = node2.getContainer()
}
bindingset[node, fun]
pragma[inline_late]
private predicate sameContainerAsEnclosingContainer(Node node, Function fun) {
@ -976,12 +1026,51 @@ private predicate isBlockedLegacyNode(Node node) {
// Note that some variables, such as top-level variables, are still modelled with these nodes (which will result in jump steps).
exists(LocalVariable variable |
node = TCapturedVariableNode(variable) and
variable instanceof VariableCaptureConfig::CapturedVariable
variable = any(VariableCaptureConfig::CapturedVariable v).asLocalVariable()
)
or
legacyBarrier(node)
}
/**
* Holds if `thisNode` represents a value of `this` that is being tracked by the
* variable capture library.
*
* In this case we need to suppress the default flow steps between `thisNode` and
* the `ThisExpr` nodes; especially those that would become jump steps.
*
* Note that local uses of `this` are sometimes tracked by the local SSA library, but we should
* not block local def-use flow, since we only switch to use-use flow after a post-update.
*/
pragma[nomagic]
private predicate isThisNodeTrackedByVariableCapture(DataFlow::ThisNode thisNode) {
exists(StmtContainer container | thisNode = TThisNode(container) |
any(VariableCaptureConfig::CapturedVariable v).asThisContainer() = container
)
}
/**
* Holds if there should be flow from `postUpdate` to `target` because of a variable/this value
* that is captured but not tracked precisely by the variable-capture library.
*/
pragma[nomagic]
private predicate imprecisePostUpdateStep(DataFlow::PostUpdateNode postUpdate, DataFlow::Node target) {
exists(LocalVariableOrThis var, DataFlow::Node use |
// 'var' is captured but not tracked precisely
var.isCaptured() and
not var instanceof VariableCaptureConfig::CapturedVariable and
(
use = TValueNode(var.asLocalVariable().getAnAccess())
or
use = TValueNode(var.getAThisExpr())
or
use = TImplicitThisUse(var.getAThisUse(), false)
) and
postUpdate.getPreUpdateNode() = use and
target = use.getALocalSource()
)
}
/**
* Holds if there is a value-preserving steps `node1` -> `node2` that might
* be cross function boundaries.
@ -989,7 +1078,10 @@ private predicate isBlockedLegacyNode(Node node) {
private predicate valuePreservingStep(Node node1, Node node2) {
node1.getASuccessor() = node2 and
not isBlockedLegacyNode(node1) and
not isBlockedLegacyNode(node2)
not isBlockedLegacyNode(node2) and
not isThisNodeTrackedByVariableCapture(node1)
or
imprecisePostUpdateStep(node1, node2)
or
FlowSteps::propertyFlowStep(node1, node2)
or
@ -999,20 +1091,60 @@ private predicate valuePreservingStep(Node node1, Node node2) {
or
FlowSummaryPrivate::Steps::summaryLocalStep(node1.(FlowSummaryNode).getSummaryNode(),
node2.(FlowSummaryNode).getSummaryNode(), true, _) // TODO: preserve 'model'
or
// Step from post-update nodes to local sources of the pre-update node. This emulates how JS usually tracks side effects.
exists(PostUpdateNode postUpdate |
node1 = postUpdate and
node2 = postUpdate.getPreUpdateNode().getALocalSource() and
node1 != node2 and // exclude trivial edges
sameContainer(node1, node2)
)
}
predicate knownSourceModel(Node sink, string model) { none() }
predicate knownSinkModel(Node sink, string model) { none() }
private predicate samePhi(SsaPhiNode legacyPhi, Ssa2::PhiNode newPhi) {
exists(BasicBlock bb, LocalVariableOrThis v |
newPhi.definesAt(v, bb, _) and
legacyPhi.definesAt(bb, _, v.asLocalVariable())
)
}
cached
Node getNodeFromSsa2(Ssa2::Node node) {
result = TSsaUseNode(node.(Ssa2::ExprNode).getExpr())
or
result = TExprPostUpdateNode(node.(Ssa2::ExprPostUpdateNode).getExpr())
or
exists(ImplicitThisUse use |
node.(Ssa2::ExprPostUpdateNode).getExpr() = use and
result = TImplicitThisUse(use, true)
)
or
result = TSsaPhiReadNode(node.(Ssa2::SsaDefinitionExtNode).getDefinitionExt())
or
result = TSsaInputNode(node.(Ssa2::SsaInputNode))
or
exists(SsaPhiNode legacyPhi, Ssa2::PhiNode ssaPhi |
node.(Ssa2::SsaDefinitionExtNode).getDefinitionExt() = ssaPhi and
samePhi(legacyPhi, ssaPhi) and
result = TSsaDefNode(legacyPhi)
)
}
private predicate useUseFlow(Node node1, Node node2) {
exists(Ssa2::DefinitionExt def, Ssa2::Node ssa1, Ssa2::Node ssa2 |
Ssa2::localFlowStep(def, ssa1, ssa2, _) and
node1 = getNodeFromSsa2(ssa1) and
node2 = getNodeFromSsa2(ssa2) and
not node1.getTopLevel().isExterns()
)
or
exists(Expr use |
node1 = TSsaUseNode(use) and
node2 = TValueNode(use)
)
or
exists(ImplicitThisUse use |
node1 = TSsaUseNode(use) and
node2 = TImplicitThisUse(use, false)
)
}
predicate simpleLocalFlowStep(Node node1, Node node2, string model) {
simpleLocalFlowStep(node1, node2) and model = ""
}
@ -1022,6 +1154,8 @@ predicate simpleLocalFlowStep(Node node1, Node node2) {
nodeGetEnclosingCallable(pragma[only_bind_out](node1)) =
nodeGetEnclosingCallable(pragma[only_bind_out](node2))
or
useUseFlow(node1, node2)
or
exists(FlowSummaryImpl::Private::SummaryNode input, FlowSummaryImpl::Private::SummaryNode output |
FlowSummaryPrivate::Steps::summaryStoreStep(input, MkAwaited(), output) and
node1 = TFlowSummaryNode(input) and
@ -1143,7 +1277,7 @@ predicate readStep(Node node1, ContentSet c, Node node2) {
c = ContentSet::arrayElement()
)
or
exists(LocalVariable variable |
exists(LocalVariableOrThis variable |
VariableCaptureOutput::readStep(getClosureNode(node1), variable, getClosureNode(node2)) and
c.asSingleton() = MkCapturedContent(variable)
)
@ -1203,15 +1337,34 @@ predicate readStep(Node node1, ContentSet c, Node node2) {
}
/** Gets the post-update node for which `node` is the corresponding pre-update node. */
private Node getPostUpdate(Node node) { result.(PostUpdateNode).getPreUpdateNode() = node }
/** Gets the post-update node for which node is the pre-update node, if one exists, otherwise gets `node` itself. */
pragma[inline]
private Node tryGetPostUpdate(Node node) {
result = getPostUpdate(node)
private Node getPostUpdateForStore(Node base) {
exists(Expr expr |
base = TValueNode(expr) and
result = TExprPostUpdateNode(expr)
|
// When object/array literal appears as an argument to a call, we would generally need two post-update nodes:
// - one for the stores coming from the properties or array elements (which happen before the call and must flow into the call)
// - one for the argument position, to propagate the updates that happened during the call
//
// However, the first post-update is not actually needed since we are storing into a brand new object, so in the first case
// we just target the expression directly. In the second case we use the ExprPostUpdateNode.
not expr instanceof ObjectExpr and
not expr instanceof ArrayExpr
)
or
not exists(getPostUpdate(node)) and
result = node
exists(ImplicitThisUse use |
base = TImplicitThisUse(use, false) and
result = TImplicitThisUse(use, true)
)
}
/** Gets node to target with a store to the given `base` object.. */
pragma[inline]
private Node getStoreTarget(DataFlow::Node base) {
result = getPostUpdateForStore(base)
or
not exists(getPostUpdateForStore(base)) and
result = base
}
pragma[nomagic]
@ -1229,7 +1382,7 @@ predicate storeStep(Node node1, ContentSet c, Node node2) {
node1 = write.getRhs() and
c.asPropertyName() = write.getPropertyName() and
// Target the post-update node if one exists (for object literals we do not generate post-update nodes)
node2 = tryGetPostUpdate(write.getBase())
node2 = getStoreTarget(write.getBase())
)
or
FlowSummaryPrivate::Steps::summaryStoreStep(node1.(FlowSummaryNode).getSummaryNode(), c,
@ -1244,7 +1397,7 @@ predicate storeStep(Node node1, ContentSet c, Node node2) {
c = ContentSet::promiseValue()
)
or
exists(LocalVariable variable |
exists(LocalVariableOrThis variable |
VariableCaptureOutput::storeStep(getClosureNode(node1), variable, getClosureNode(node2)) and
c.asSingleton() = MkCapturedContent(variable)
)
@ -1377,7 +1530,9 @@ predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c)
predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
call.isSummaryCall(_, receiver.(FlowSummaryNode).getSummaryNode()) and exists(kind)
or
receiver = call.asOrdinaryCall().getCalleeNode() and exists(kind)
receiver = call.asOrdinaryCall().getCalleeNode() and
exists(kind) and
receiver.getALocalSource() instanceof DataFlow::ParameterNode
}
/** Extra data-flow steps needed for lambda flow analysis. */

Просмотреть файл

@ -5,6 +5,7 @@ private import semmle.javascript.dataflow.internal.Contents::Public
private import semmle.javascript.dataflow.internal.sharedlib.FlowSummaryImpl as FlowSummaryImpl
private import semmle.javascript.dataflow.internal.FlowSummaryPrivate as FlowSummaryPrivate
private import semmle.javascript.dataflow.internal.BarrierGuards
private import semmle.javascript.dataflow.internal.sharedlib.Ssa as Ssa2
cached
predicate defaultAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
@ -44,6 +45,43 @@ private class SanitizerGuardAdapter extends DataFlow::Node instanceof TaintTrack
predicate blocksExpr(boolean outcome, Expr e) { super.sanitizes(outcome, e) }
}
bindingset[node]
pragma[inline_late]
private BasicBlock getBasicBlockFromSsa2(Ssa2::Node node) {
result = node.(Ssa2::ExprNode).getExpr().getBasicBlock()
or
node.(Ssa2::SsaInputNode).isInputInto(_, result)
}
/**
* Holds if `node` should act as a taint barrier, as it occurs after a variable has been checked to be falsy.
*
* For example:
* ```js
* if (!x) {
* use(x); // <-- 'x' is a varAccessBarrier
* }
* ```
*
* This is particularly important for ensuring that query-specific barrier guards work when they
* occur after a truthiness-check:
* ```js
* if (x && !isSafe(x)) {
* throw new Error()
* }
* use(x); // both inputs to the phi-read for 'x' are blocked (one by varAccessBarrier, one by isSafe(x))
* ```
*/
private predicate varAccessBarrier(DataFlow::Node node) {
exists(ConditionGuardNode guard, Ssa2::ExprNode nodeFrom, Ssa2::Node nodeTo |
guard.getOutcome() = false and
guard.getTest().(VarAccess) = nodeFrom.getExpr() and
Ssa2::localFlowStep(_, nodeFrom, nodeTo, true) and
guard.dominates(getBasicBlockFromSsa2(nodeTo)) and
node = getNodeFromSsa2(nodeTo)
)
}
/**
* Holds if `node` should be a sanitizer in all global taint flow configurations
* but not in local taint.
@ -51,6 +89,7 @@ private class SanitizerGuardAdapter extends DataFlow::Node instanceof TaintTrack
cached
predicate defaultTaintSanitizer(DataFlow::Node node) {
node instanceof DataFlow::VarAccessBarrier or
varAccessBarrier(node) or
node = MakeBarrierGuard<SanitizerGuardAdapter>::getABarrierNode()
}

Просмотреть файл

@ -1,5 +1,6 @@
private import javascript as js
private import semmle.javascript.dataflow.internal.DataFlowNode
private import semmle.javascript.dataflow.internal.VariableOrThis
private import codeql.dataflow.VariableCapture
private import semmle.javascript.dataflow.internal.sharedlib.DataFlowImplCommon as DataFlowImplCommon
@ -51,7 +52,7 @@ module VariableCaptureConfig implements InputSig<js::DbLocation> {
)
}
class CapturedVariable extends js::LocalVariable {
class CapturedVariable extends LocalVariableOrThis {
CapturedVariable() {
DataFlowImplCommon::forceCachingInSameStage() and
this.isCaptured() and
@ -63,7 +64,9 @@ module VariableCaptureConfig implements InputSig<js::DbLocation> {
additional predicate captures(js::Function fun, CapturedVariable variable) {
(
variable.getAnAccess().getContainer().getFunctionBoundary() = fun
variable.asLocalVariable().getAnAccess().getContainer().getFunctionBoundary() = fun
or
variable.getAThisUse().getUseContainer() = fun
or
exists(js::Function inner |
captures(inner, variable) and
@ -122,7 +125,8 @@ module VariableCaptureConfig implements InputSig<js::DbLocation> {
private predicate isCapturedByOwnInitializer(js::VariableDeclarator decl) {
exists(js::Function function |
function = getACapturingFunctionInTree(decl.getInit()) and
captures(function, decl.getBindingPattern().(js::VarDecl).getVariable())
captures(function,
LocalVariableOrThis::variable(decl.getBindingPattern().(js::VarDecl).getVariable()))
)
}
@ -141,7 +145,7 @@ module VariableCaptureConfig implements InputSig<js::DbLocation> {
}
class CapturedParameter extends CapturedVariable {
CapturedParameter() { this.isParameter() }
CapturedParameter() { this.asLocalVariable().isParameter() or exists(this.asThisContainer()) }
}
class Expr extends js::AST::ValueNode {
@ -152,10 +156,10 @@ module VariableCaptureConfig implements InputSig<js::DbLocation> {
}
}
class VariableRead extends Expr instanceof js::VarAccess, js::RValue {
class VariableRead extends Expr instanceof js::ControlFlowNode {
private CapturedVariable variable;
VariableRead() { this = variable.getAnAccess() }
VariableRead() { this = variable.getAUse() }
CapturedVariable getVariable() { result = variable }
}
@ -178,7 +182,7 @@ module VariableCaptureConfig implements InputSig<js::DbLocation> {
private newtype TVariableWrite =
MkExplicitVariableWrite(js::VarRef pattern) {
exists(js::DataFlow::lvalueNodeInternal(pattern)) and
pattern.getVariable() instanceof CapturedVariable
any(CapturedVariable v).asLocalVariable() = pattern.getVariable()
} or
MkImplicitVariableInit(CapturedVariable v) { not v instanceof CapturedParameter }
@ -200,7 +204,7 @@ module VariableCaptureConfig implements InputSig<js::DbLocation> {
ExplicitVariableWrite() { this = MkExplicitVariableWrite(pattern) }
override CapturedVariable getVariable() { result = pattern.getVariable() }
override CapturedVariable getVariable() { result.asLocalVariable() = pattern.getVariable() }
override string toString() { result = pattern.toString() }
@ -248,7 +252,9 @@ module VariableCaptureConfig implements InputSig<js::DbLocation> {
override predicate hasCfgNode(BasicBlock bb, int i) {
// 'i' would normally be bound to 0, but we lower it to -1 so FunctionDeclStmts can be evaluated
// at index 0.
any(js::SsaImplicitInit def).definesAt(bb, _, variable) and i = -1
any(js::SsaImplicitInit def).definesAt(bb, _, variable.asLocalVariable()) and i = -1
or
bb.(js::EntryBasicBlock).getContainer() = variable.asThisContainer() and i = -1
}
}
@ -266,7 +272,13 @@ module VariableCaptureOutput = Flow<js::DbLocation, VariableCaptureConfig>;
js::DataFlow::Node getNodeFromClosureNode(VariableCaptureOutput::ClosureNode node) {
result = TValueNode(node.(VariableCaptureOutput::ExprNode).getExpr())
or
result = TValueNode(node.(VariableCaptureOutput::ParameterNode).getParameter().getADeclaration()) // TODO: is this subsumed by the ExprNode case?
result =
TValueNode(node.(VariableCaptureOutput::ParameterNode)
.getParameter()
.asLocalVariable()
.getADeclaration()) // TODO: is this subsumed by the ExprNode case?
or
result = TThisNode(node.(VariableCaptureOutput::ParameterNode).getParameter().asThisContainer())
or
result = TExprPostUpdateNode(node.(VariableCaptureOutput::ExprPostUpdateNode).getExpr())
or

Просмотреть файл

@ -0,0 +1,130 @@
private import javascript
private import DataFlowNode
cached
private newtype TLocalVariableOrThis =
TLocalVariable(LocalVariable var) or
TThis(StmtContainer container) { not container instanceof ArrowFunctionExpr }
/** A local variable or `this` in a particular container. */
class LocalVariableOrThis extends TLocalVariableOrThis {
/** Gets the local variable represented by this newtype, if any. */
LocalVariable asLocalVariable() { this = TLocalVariable(result) }
/** If this represents `this`, gets the enclosing container */
StmtContainer asThisContainer() { this = TThis(result) }
/** Gets the name of the variable or the string `"this"`. */
string toString() { result = this.getName() }
/** Gets the name of the variable or the string `"this"`. */
string getName() {
result = this.asLocalVariable().getName()
or
this instanceof TThis and result = "this"
}
/** Gets the location of a declaration of this variable, or the declaring container if this is `this`. */
DbLocation getLocation() {
result = this.asLocalVariable().getLocation()
or
result = this.asThisContainer().getLocation()
}
/** Holds if this is a captured variable or captured `this`. */
predicate isCaptured() {
this.asLocalVariable().isCaptured()
or
hasCapturedThis(this.asThisContainer())
}
/** Gets the container declaring this variable or is the enclosing container for `this`. */
StmtContainer getDeclaringContainer() {
result = this.asLocalVariable().getDeclaringContainer()
or
result = this.asThisContainer()
}
/** Gets an explicit access to `this` represented by this value. */
ThisExpr getAThisExpr() { result.getBindingContainer() = this.asThisContainer() }
/** Gets an implicit or explicit use of the `this` represented by this value. */
ThisUse getAThisUse() { result.getBindingContainer() = this.asThisContainer() }
/** Gets an expression that accesses this variable or `this`. */
ControlFlowNode getAUse() {
result = this.asLocalVariable().getAnAccess()
or
result = this.getAThisUse()
}
}
bindingset[c1, c2]
pragma[inline_late]
private predicate sameContainer(StmtContainer c1, StmtContainer c2) { c1 = c2 }
pragma[nomagic]
private predicate hasCapturedThis(StmtContainer c) {
exists(ThisExpr expr |
expr.getBindingContainer() = c and
not sameContainer(c, expr.getContainer())
)
}
module LocalVariableOrThis {
/** Gets the representation of the given local variable. */
LocalVariableOrThis variable(LocalVariable v) { result.asLocalVariable() = v }
/** Gets the representation of `this` in the given container. */
LocalVariableOrThis thisInContainer(StmtContainer c) { result = TThis(c) }
}
/**
* An explicit or implicit use of `this`.
*
* Implicit uses include `super()` calls and instance field initializers (which includes TypeScript parameter fields).
*/
abstract class ThisUse instanceof ControlFlowNode {
/** Gets the container binding the `this` being accessed */
abstract StmtContainer getBindingContainer();
/** Get the container in which `this` is being accessed. */
abstract StmtContainer getUseContainer();
/** Gets a string representation of this element. */
string toString() { result = super.toString() }
/** Gets the location of this use of `this`. */
DbLocation getLocation() { result = super.getLocation() }
}
private predicate implicitThisUse(ControlFlowNode node, StmtContainer thisBinder) {
thisBinder = node.(SuperExpr).getBinder()
or
exists(FieldDefinition field |
not field.isStatic() and
node = field and
thisBinder = field.getDeclaringClass().getConstructor().getBody()
)
}
class ImplicitThisUse extends ThisUse {
ImplicitThisUse() { implicitThisUse(this, _) }
override StmtContainer getBindingContainer() { implicitThisUse(this, result) }
override StmtContainer getUseContainer() {
// The following differs from FieldDefinition.getContainer() which returns the container enclosing
// the class, not the class constructor.
// TODO: consider changing this in FieldDefinition.getContainer()
result = this.(FieldDefinition).getDeclaringClass().getConstructor().getBody()
or
result = this.(SuperExpr).getContainer()
}
}
private class ExplicitThisUse extends ThisUse instanceof ThisExpr {
override StmtContainer getBindingContainer() { result = ThisExpr.super.getBindingContainer() }
override StmtContainer getUseContainer() { result = ThisExpr.super.getContainer() }
}

Просмотреть файл

@ -0,0 +1,109 @@
/**
* Instantiates the shared SSA library for JavaScript, but only to establish use-use flow.
*
* JavaScript's old SSA library is still responsible for the ordinary SSA flow.
*/
private import javascript as js
private import codeql.ssa.Ssa
private import semmle.javascript.internal.BasicBlockInternal as BasicBlockInternal
private import semmle.javascript.dataflow.internal.VariableOrThis
module SsaConfig implements InputSig<js::DbLocation> {
class ControlFlowNode = js::ControlFlowNode;
class BasicBlock = js::BasicBlock;
class ExitBasicBlock extends BasicBlock {
ExitBasicBlock() { this.isExitBlock() }
}
class SourceVariable extends LocalVariableOrThis {
SourceVariable() { not this.isCaptured() }
}
pragma[nomagic]
private js::EntryBasicBlock getEntryBlock(js::StmtContainer container) {
result.getContainer() = container
}
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) {
certain = true and
(
bb.defAt(i, v.asLocalVariable(), _)
or
// Implicit initialization and function parameters
bb = getEntryBlock(v.getDeclaringContainer()) and
i = -1
)
}
predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) {
bb.useAt(i, v.asLocalVariable(), _) and certain = true
or
certain = true and
bb.getNode(i).(ThisUse).getBindingContainer() = v.asThisContainer()
}
predicate getImmediateBasicBlockDominator = BasicBlockInternal::immediateDominator/1;
pragma[inline]
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
}
import Make<js::DbLocation, SsaConfig>
module SsaDataflowInput implements DataFlowIntegrationInputSig {
class Expr extends js::ControlFlowNode {
Expr() { this = any(SsaConfig::SourceVariable v).getAUse() }
predicate hasCfgNode(js::BasicBlock bb, int i) { this = bb.getNode(i) }
}
predicate ssaDefAssigns(WriteDefinition def, Expr value) {
// This library only handles use-use flow after a post-update, there are no definitions, only uses.
none()
}
class Parameter = js::Parameter;
predicate ssaDefInitializesParam(WriteDefinition def, Parameter p) {
// This library only handles use-use flow after a post-update, there are no definitions, only uses.
none()
}
cached
Expr getARead(Definition def) {
// Copied from implementation so we can cache it here
exists(SsaConfig::SourceVariable v, js::BasicBlock bb, int i |
ssaDefReachesRead(v, def, bb, i) and
SsaConfig::variableRead(bb, i, v, true) and
result.hasCfgNode(bb, i)
)
}
class Guard extends js::ControlFlowNode {
Guard() { this = any(js::ConditionGuardNode g).getTest() }
predicate hasCfgNode(js::BasicBlock bb, int i) { this = bb.getNode(i) }
}
pragma[inline]
predicate guardControlsBlock(Guard guard, js::BasicBlock bb, boolean branch) {
exists(js::ConditionGuardNode g |
g.getTest() = guard and
g.dominates(bb) and
branch = g.getOutcome()
)
}
js::BasicBlock getAConditionalBasicBlockSuccessor(js::BasicBlock bb, boolean branch) {
exists(js::ConditionGuardNode g |
bb = g.getTest().getBasicBlock() and
result = g.getBasicBlock() and
branch = g.getOutcome()
)
}
}
import DataFlowIntegration<SsaDataflowInput>

Просмотреть файл

@ -0,0 +1,365 @@
/**
* Provides classes for working with basic blocks, and predicates for computing
* liveness information for local variables.
*/
import javascript
private import semmle.javascript.internal.StmtContainers
private import semmle.javascript.internal.CachedStages
/**
* Holds if `nd` starts a new basic block.
*/
private predicate startsBB(ControlFlowNode nd) {
not exists(nd.getAPredecessor()) and exists(nd.getASuccessor())
or
nd.isJoin()
or
nd.getAPredecessor().isBranch()
}
/**
* Holds if the first node of basic block `succ` is a control flow
* successor of the last node of basic block `bb`.
*/
private predicate succBB(BasicBlock bb, BasicBlock succ) { succ = bb.getLastNode().getASuccessor() }
/**
* Holds if the first node of basic block `bb` is a control flow
* successor of the last node of basic block `pre`.
*/
private predicate predBB(BasicBlock bb, BasicBlock pre) { succBB(pre, bb) }
/** Holds if `bb` is an entry basic block. */
private predicate entryBB(BasicBlock bb) { bb.getFirstNode() instanceof ControlFlowEntryNode }
/** Holds if `bb` is an exit basic block. */
private predicate exitBB(BasicBlock bb) { bb.getLastNode() instanceof ControlFlowExitNode }
cached
private module Cached {
/**
* Holds if `succ` is a control flow successor of `nd` within the same basic block.
*/
private predicate intraBBSucc(ControlFlowNode nd, ControlFlowNode succ) {
succ = nd.getASuccessor() and
not succ instanceof BasicBlock
}
/**
* Holds if `nd` is the `i`th node in basic block `bb`.
*
* In other words, `i` is the shortest distance from a node `bb`
* that starts a basic block to `nd` along the `intraBBSucc` relation.
*/
cached
predicate bbIndex(BasicBlock bb, ControlFlowNode nd, int i) =
shortestDistances(startsBB/1, intraBBSucc/2)(bb, nd, i)
cached
int bbLength(BasicBlock bb) { result = strictcount(ControlFlowNode nd | bbIndex(bb, nd, _)) }
cached
predicate useAt(BasicBlock bb, int i, Variable v, VarUse u) {
Stages::BasicBlocks::ref() and
v = u.getVariable() and
bbIndex(bb, u, i)
}
cached
predicate defAt(BasicBlock bb, int i, Variable v, VarDef d) {
exists(VarRef lhs |
lhs = d.getTarget().(BindingPattern).getABindingVarRef() and
v = lhs.getVariable()
|
lhs = d.getTarget() and
bbIndex(bb, d, i)
or
exists(PropertyPattern pp |
lhs = pp.getValuePattern() and
bbIndex(bb, pp, i)
)
or
exists(ObjectPattern op |
lhs = op.getRest() and
bbIndex(bb, lhs, i)
)
or
exists(ArrayPattern ap |
lhs = ap.getAnElement() and
bbIndex(bb, lhs, i)
)
)
}
cached
predicate reachableBB(BasicBlock bb) {
entryBB(bb)
or
exists(BasicBlock predBB | succBB(predBB, bb) | reachableBB(predBB))
}
}
private import Cached
/** Gets the immediate dominator of `bb`. */
cached
BasicBlock immediateDominator(BasicBlock bb) = idominance(entryBB/1, succBB/2)(_, result, bb)
/** Gets the immediate post-dominator of `bb`. */
cached
BasicBlock immediatePostDominator(BasicBlock bb) = idominance(exitBB/1, predBB/2)(_, result, bb)
import Public
module Public {
/**
* A basic block, that is, a maximal straight-line sequence of control flow nodes
* without branches or joins.
*
* At the database level, a basic block is represented by its first control flow node.
*/
class BasicBlock extends @cfg_node, NodeInStmtContainer {
cached
BasicBlock() { Stages::BasicBlocks::ref() and startsBB(this) }
/** Gets a basic block succeeding this one. */
BasicBlock getASuccessor() { succBB(this, result) }
/** Gets a basic block preceding this one. */
BasicBlock getAPredecessor() { result.getASuccessor() = this }
/** Gets a node in this block. */
ControlFlowNode getANode() { result = this.getNode(_) }
/** Gets the node at the given position in this block. */
ControlFlowNode getNode(int pos) { bbIndex(this, result, pos) }
/** Gets the first node in this block. */
ControlFlowNode getFirstNode() { result = this }
/** Gets the last node in this block. */
ControlFlowNode getLastNode() { result = this.getNode(this.length() - 1) }
/** Gets the length of this block. */
int length() { result = bbLength(this) }
/** Holds if this basic block uses variable `v` in its `i`th node `u`. */
predicate useAt(int i, Variable v, VarUse u) { useAt(this, i, v, u) }
/** Holds if this basic block defines variable `v` in its `i`th node `d`. */
predicate defAt(int i, Variable v, VarDef d) { defAt(this, i, v, d) }
/**
* Holds if `v` is live at entry to this basic block and `u` is a use of `v`
* witnessing the liveness.
*
* In other words, `u` is a use of `v` that is reachable from the
* entry node of this basic block without going through a redefinition
* of `v`. The use `u` may either be in this basic block, or in another
* basic block reachable from this one.
*/
predicate isLiveAtEntry(Variable v, VarUse u) {
// restrict `u` to be reachable from this basic block
u = this.getASuccessor*().getANode() and
(
// shortcut: if `v` is never defined, then it must be live
this.isDefinedInSameContainer(v)
implies
// otherwise, do full liveness computation
this.isLiveAtEntryImpl(v, u)
)
}
/**
* Holds if `v` is live at entry to this basic block and `u` is a use of `v`
* witnessing the liveness, where `v` is defined at least once in the enclosing
* function or script.
*/
private predicate isLiveAtEntryImpl(Variable v, VarUse u) {
this.isLocallyLiveAtEntry(v, u)
or
this.isDefinedInSameContainer(v) and
not this.defAt(_, v, _) and
this.getASuccessor().isLiveAtEntryImpl(v, u)
}
/**
* Holds if `v` is defined at least once in the function or script to which
* this basic block belongs.
*/
private predicate isDefinedInSameContainer(Variable v) {
exists(VarDef def | def.getAVariable() = v and def.getContainer() = this.getContainer())
}
/**
* Holds if `v` is a variable that is live at entry to this basic block.
*
* Note that this is equivalent to `bb.isLiveAtEntry(v, _)`, but may
* be more efficient on large databases.
*/
predicate isLiveAtEntry(Variable v) {
this.isLocallyLiveAtEntry(v, _)
or
not this.defAt(_, v, _) and this.getASuccessor().isLiveAtEntry(v)
}
/**
* Holds if local variable `v` is live at entry to this basic block and
* `u` is a use of `v` witnessing the liveness.
*/
predicate localIsLiveAtEntry(LocalVariable v, VarUse u) {
this.isLocallyLiveAtEntry(v, u)
or
not this.defAt(_, v, _) and this.getASuccessor().localIsLiveAtEntry(v, u)
}
/**
* Holds if local variable `v` is live at entry to this basic block.
*/
predicate localIsLiveAtEntry(LocalVariable v) {
this.isLocallyLiveAtEntry(v, _)
or
not this.defAt(_, v, _) and this.getASuccessor().localIsLiveAtEntry(v)
}
/**
* Holds if `d` is a definition of `v` that is reachable from the beginning of
* this basic block without going through a redefinition of `v`.
*/
predicate localMayBeOverwritten(LocalVariable v, VarDef d) {
this.isLocallyOverwritten(v, d)
or
not this.defAt(_, v, _) and this.getASuccessor().localMayBeOverwritten(v, d)
}
/**
* Gets the next index after `i` in this basic block at which `v` is
* defined or used, provided that `d` is a definition of `v` at index `i`.
* If there are no further uses or definitions of `v` after `i`, the
* result is the length of this basic block.
*/
private int nextDefOrUseAfter(PurelyLocalVariable v, int i, VarDef d) {
this.defAt(i, v, d) and
result =
min(int j |
(this.defAt(j, v, _) or this.useAt(j, v, _) or j = this.length()) and
j > i
)
}
/**
* Holds if `d` defines variable `v` at the `i`th node of this basic block, and
* the definition is live, that is, the variable may be read after this
* definition and before a re-definition.
*/
predicate localLiveDefAt(PurelyLocalVariable v, int i, VarDef d) {
exists(int j | j = this.nextDefOrUseAfter(v, i, d) |
this.useAt(j, v, _)
or
j = this.length() and this.getASuccessor().localIsLiveAtEntry(v)
)
}
/**
* Holds if `u` is a use of `v` in this basic block, and there are
* no definitions of `v` before it.
*/
private predicate isLocallyLiveAtEntry(Variable v, VarUse u) {
exists(int n | this.useAt(n, v, u) | not exists(int m | m < n | this.defAt(m, v, _)))
}
/**
* Holds if `d` is a definition of `v` in this basic block, and there are
* no other definitions of `v` before it.
*/
private predicate isLocallyOverwritten(Variable v, VarDef d) {
exists(int n | this.defAt(n, v, d) | not exists(int m | m < n | this.defAt(m, v, _)))
}
/**
* Gets the basic block that immediately dominates this basic block.
*/
ReachableBasicBlock getImmediateDominator() { result = immediateDominator(this) }
/**
* Holds if this if a basic block whose last node is an exit node.
*/
predicate isExitBlock() { exitBB(this) }
}
/**
* An unreachable basic block, that is, a basic block
* whose first node is unreachable.
*/
class UnreachableBlock extends BasicBlock {
UnreachableBlock() { this.getFirstNode().isUnreachable() }
}
/**
* An entry basic block, that is, a basic block
* whose first node is the entry node of a statement container.
*/
class EntryBasicBlock extends BasicBlock {
EntryBasicBlock() { entryBB(this) }
}
/**
* A basic block that is reachable from an entry basic block.
*/
class ReachableBasicBlock extends BasicBlock {
ReachableBasicBlock() { reachableBB(this) }
/**
* Holds if this basic block strictly dominates `bb`.
*/
pragma[inline]
predicate strictlyDominates(ReachableBasicBlock bb) { this = immediateDominator+(bb) }
/**
* Holds if this basic block dominates `bb`.
*
* This predicate is reflexive: each reachable basic block dominates itself.
*/
pragma[inline]
predicate dominates(ReachableBasicBlock bb) { this = immediateDominator*(bb) }
/**
* Holds if this basic block strictly post-dominates `bb`.
*/
pragma[inline]
predicate strictlyPostDominates(ReachableBasicBlock bb) { this = immediatePostDominator+(bb) }
/**
* Holds if this basic block post-dominates `bb`.
*
* This predicate is reflexive: each reachable basic block post-dominates itself.
*/
pragma[inline]
predicate postDominates(ReachableBasicBlock bb) { this = immediatePostDominator*(bb) }
}
/**
* A reachable basic block with more than one predecessor.
*/
class ReachableJoinBlock extends ReachableBasicBlock {
ReachableJoinBlock() { this.getFirstNode().isJoin() }
/**
* Holds if this basic block belongs to the dominance frontier of `b`, that is
* `b` dominates a predecessor of this block, but not this block itself.
*
* Algorithm from Cooper et al., "A Simple, Fast Dominance Algorithm" (Figure 5),
* who in turn attribute it to Ferrante et al., "The program dependence graph and
* its use in optimization".
*/
predicate inDominanceFrontierOf(ReachableBasicBlock b) {
b = this.getAPredecessor() and not b = this.getImmediateDominator()
or
exists(ReachableBasicBlock prev | this.inDominanceFrontierOf(prev) |
b = prev.getImmediateDominator() and
not b = this.getImmediateDominator()
)
}
}
}

Просмотреть файл

@ -83,6 +83,8 @@ module DomBasedXssConfig implements DataFlow::StateConfigSig {
node = DataFlow::MakeLabeledBarrierGuard<BarrierGuard>::getABarrierNode(lbl)
}
predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowLabel label) { isSource(node, label) }
predicate isAdditionalFlowStep(
DataFlow::Node node1, DataFlow::FlowLabel state1, DataFlow::Node node2,
DataFlow::FlowLabel state2

Просмотреть файл

@ -999,7 +999,7 @@ flowStep
| tst2.ts:13:26:13:29 | List | tst2.ts:13:26:13:37 | List<string> |
| tst2.ts:13:39:13:38 | args | tst2.ts:13:39:13:38 | args |
| tst2.ts:13:39:13:38 | args | tst2.ts:13:39:13:38 | args |
| tst2.ts:13:39:13:38 | this | tst2.ts:13:39:13:38 | implicit 'this' argument of super(...args) |
| tst2.ts:13:39:13:38 | this | tst2.ts:13:39:13:38 | implicit 'this' |
| tst2.ts:15:11:15:13 | A.x | tst2.ts:15:11:15:30 | A.x satisfies number |
| tst.js:1:1:1:1 | x | tst.js:3:5:3:5 | x |
| tst.js:1:10:1:11 | fs | tst.js:1:10:1:11 | fs |
@ -1080,7 +1080,7 @@ flowStep
| tst.js:46:10:46:11 | "" | tst.js:46:1:46:11 | global = "" |
| tst.js:49:1:54:1 | A | tst.js:55:1:55:1 | A |
| tst.js:49:1:54:1 | class A ... `\\n }\\n} | tst.js:49:1:54:1 | A |
| tst.js:50:14:50:13 | this | tst.js:51:5:51:13 | implicit 'this' argument of super(42) |
| tst.js:50:14:50:13 | this | tst.js:51:5:51:9 | implicit 'this' |
| tst.js:64:1:67:1 | functio ... lysed\\n} | tst.js:64:11:64:11 | h |
| tst.js:64:11:64:11 | h | tst.js:68:12:68:12 | h |
| tst.js:68:5:68:14 | iter | tst.js:69:1:69:4 | iter |
@ -1187,6 +1187,7 @@ getImmediatePredecessor
| tst2.ts:13:26:13:29 | List | tst2.ts:13:26:13:37 | List<string> |
| tst2.ts:13:39:13:38 | args | tst2.ts:13:39:13:38 | args |
| tst2.ts:13:39:13:38 | args | tst2.ts:13:39:13:38 | args |
| tst2.ts:13:39:13:38 | this | tst2.ts:13:39:13:38 | implicit 'this' |
| tst2.ts:15:11:15:13 | A.x | tst2.ts:15:11:15:30 | A.x satisfies number |
| tst.js:1:10:1:11 | fs | tst.js:1:10:1:11 | fs |
| tst.js:1:10:1:11 | fs | tst.js:7:1:7:2 | fs |
@ -1249,6 +1250,7 @@ getImmediatePredecessor
| tst.js:46:10:46:11 | "" | tst.js:46:1:46:11 | global = "" |
| tst.js:49:1:54:1 | A | tst.js:55:1:55:1 | A |
| tst.js:49:1:54:1 | class A ... `\\n }\\n} | tst.js:49:1:54:1 | A |
| tst.js:50:14:50:13 | this | tst.js:51:5:51:9 | implicit 'this' |
| tst.js:64:1:67:1 | functio ... lysed\\n} | tst.js:64:11:64:11 | h |
| tst.js:64:11:64:11 | h | tst.js:68:12:68:12 | h |
| tst.js:68:5:68:14 | iter | tst.js:69:1:69:4 | iter |

Просмотреть файл

@ -33,14 +33,6 @@ postWithInFlow
| file://:0:0:0:0 | [summary] to write: Argument[this] in Array#forEach / Map#forEach / Set#forEach | PostUpdateNode should not be the target of local flow. |
| file://:0:0:0:0 | [summary] to write: Argument[this] in Array#map | PostUpdateNode should not be the target of local flow. |
| file://:0:0:0:0 | [summary] to write: Argument[this] in Array#reduce / Array#reduceRight | PostUpdateNode should not be the target of local flow. |
| tst.js:97:24:97:74 | new Pro ... rce())) | PostUpdateNode should not be the target of local flow. |
| tst.js:100:3:100:53 | new Pro ... rce())) | PostUpdateNode should not be the target of local flow. |
| tst.js:101:3:101:53 | new Pro ... rce())) | PostUpdateNode should not be the target of local flow. |
| tst.js:102:3:102:52 | new Pro ... rce())) | PostUpdateNode should not be the target of local flow. |
| tst.js:103:3:103:52 | new Pro ... rce())) | PostUpdateNode should not be the target of local flow. |
| tst.js:250:15:250:23 | new Map() | PostUpdateNode should not be the target of local flow. |
| tst.js:258:16:258:24 | new Map() | PostUpdateNode should not be the target of local flow. |
| tst.js:264:16:264:24 | new Map() | PostUpdateNode should not be the target of local flow. |
viableImplInCallContextTooLarge
uniqueParameterNodeAtPosition
uniqueParameterNodePosition

Просмотреть файл

@ -67,10 +67,10 @@ test_PropWriteRhs
| tst.js:41:18:41:24 | ...arr3 | tst.js:41:18:41:24 | ...arr3 |
| tst.js:41:27:41:29 | "d" | tst.js:41:27:41:29 | "d" |
test_PropWriteBase
| classes.ts:4:3:4:24 | instanc ... foo(); | classes.ts:3:21:3:20 | this |
| classes.ts:8:15:8:35 | public ... erField | classes.ts:8:3:8:2 | this |
| classes.ts:12:17:12:37 | public ... erField | classes.ts:12:5:12:4 | this |
| classes.ts:16:17:16:37 | public ... erField | classes.ts:16:5:16:4 | this |
| classes.ts:4:3:4:24 | instanc ... foo(); | classes.ts:4:3:4:24 | implicit 'this' |
| classes.ts:8:15:8:35 | public ... erField | classes.ts:8:15:8:35 | implicit 'this' |
| classes.ts:12:17:12:37 | public ... erField | classes.ts:12:17:12:37 | implicit 'this' |
| classes.ts:16:17:16:37 | public ... erField | classes.ts:16:17:16:37 | implicit 'this' |
| tst.js:2:5:2:8 | x: 4 | tst.js:1:11:9:1 | {\\n x ... }\\n} |
| tst.js:3:5:5:5 | func: f ... ;\\n } | tst.js:1:11:9:1 | {\\n x ... }\\n} |
| tst.js:6:5:8:5 | f() {\\n ... ;\\n } | tst.js:1:11:9:1 | {\\n x ... }\\n} |

Просмотреть файл

@ -17,9 +17,6 @@ legacyDataFlowDifference
| callbacks.js:44:17:44:24 | source() | callbacks.js:38:35:38:35 | x | only flow with NEW data flow library |
| capture-flow.js:89:13:89:20 | source() | capture-flow.js:89:6:89:21 | test3c(source()) | only flow with NEW data flow library |
| capture-flow.js:101:12:101:19 | source() | capture-flow.js:102:6:102:20 | test5("safe")() | only flow with OLD data flow library |
| capture-flow.js:274:33:274:40 | source() | capture-flow.js:272:10:272:17 | this.foo | only flow with OLD data flow library |
| capture-flow.js:274:33:274:40 | source() | capture-flow.js:274:6:274:45 | new Cap ... ()).foo | only flow with OLD data flow library |
| capture-flow.js:283:34:283:41 | source() | capture-flow.js:284:6:284:44 | new Cap ... e').foo | only flow with NEW data flow library |
| constructor-calls.js:4:18:4:25 | source() | constructor-calls.js:40:8:40:14 | e.taint | only flow with NEW data flow library |
| constructor-calls.js:4:18:4:25 | source() | constructor-calls.js:44:8:44:19 | f_safe.taint | only flow with NEW data flow library |
| constructor-calls.js:20:15:20:22 | source() | constructor-calls.js:39:8:39:14 | e.param | only flow with NEW data flow library |
@ -36,6 +33,7 @@ legacyDataFlowDifference
| sanitizer-guards.js:57:11:57:18 | source() | sanitizer-guards.js:64:8:64:8 | x | only flow with NEW data flow library |
| spread.js:4:15:4:22 | source() | spread.js:18:8:18:8 | y | only flow with NEW data flow library |
| spread.js:4:15:4:22 | source() | spread.js:24:8:24:8 | y | only flow with NEW data flow library |
| tst.js:2:13:2:20 | source() | tst.js:17:10:17:10 | a | only flow with OLD data flow library |
| use-use-after-implicit-read.js:7:17:7:24 | source() | use-use-after-implicit-read.js:15:10:15:10 | x | only flow with NEW data flow library |
consistencyIssue
| nested-props.js:20 | expected an alert, but found none | NOT OK - but not found | Consistency |
@ -125,8 +123,9 @@ flow
| capture-flow.js:259:23:259:30 | source() | capture-flow.js:252:14:252:36 | objectW ... s.field |
| capture-flow.js:259:23:259:30 | source() | capture-flow.js:253:14:253:23 | this.field |
| capture-flow.js:262:16:262:23 | source() | capture-flow.js:264:14:264:21 | this.foo |
| capture-flow.js:274:33:274:40 | source() | capture-flow.js:272:10:272:17 | this.foo |
| capture-flow.js:274:33:274:40 | source() | capture-flow.js:274:6:274:45 | new Cap ... ()).foo |
| capture-flow.js:283:34:283:41 | source() | capture-flow.js:283:6:283:46 | new Cap ... ()).foo |
| capture-flow.js:283:34:283:41 | source() | capture-flow.js:284:6:284:44 | new Cap ... e').foo |
| captured-sanitizer.js:25:3:25:10 | source() | captured-sanitizer.js:15:10:15:10 | x |
| case.js:2:16:2:23 | source() | case.js:5:8:5:35 | changeC ... source) |
| case.js:2:16:2:23 | source() | case.js:8:8:8:24 | camelCase(source) |
@ -280,7 +279,6 @@ flow
| tst.js:2:13:2:20 | source() | tst.js:4:10:4:10 | x |
| tst.js:2:13:2:20 | source() | tst.js:5:10:5:22 | "/" + x + "!" |
| tst.js:2:13:2:20 | source() | tst.js:14:10:14:17 | x.sort() |
| tst.js:2:13:2:20 | source() | tst.js:17:10:17:10 | a |
| tst.js:2:13:2:20 | source() | tst.js:19:10:19:10 | a |
| tst.js:2:13:2:20 | source() | tst.js:23:10:23:10 | b |
| tst.js:2:13:2:20 | source() | tst.js:25:10:25:16 | x.pop() |

Просмотреть файл

@ -11,8 +11,6 @@ legacyDataFlowDifference
| callbacks.js:44:17:44:24 | source() | callbacks.js:38:35:38:35 | x | only flow with NEW data flow library |
| capture-flow.js:89:13:89:20 | source() | capture-flow.js:89:6:89:21 | test3c(source()) | only flow with NEW data flow library |
| capture-flow.js:101:12:101:19 | source() | capture-flow.js:102:6:102:20 | test5("safe")() | only flow with OLD data flow library |
| capture-flow.js:274:33:274:40 | source() | capture-flow.js:272:10:272:17 | this.foo | only flow with OLD data flow library |
| capture-flow.js:274:33:274:40 | source() | capture-flow.js:274:6:274:45 | new Cap ... ()).foo | only flow with OLD data flow library |
| constructor-calls.js:4:18:4:25 | source() | constructor-calls.js:40:8:40:14 | e.taint | only flow with NEW data flow library |
| constructor-calls.js:4:18:4:25 | source() | constructor-calls.js:44:8:44:19 | f_safe.taint | only flow with NEW data flow library |
| constructor-calls.js:20:15:20:22 | source() | constructor-calls.js:39:8:39:14 | e.param | only flow with NEW data flow library |
@ -100,6 +98,8 @@ flow
| capture-flow.js:259:23:259:30 | source() | capture-flow.js:252:14:252:36 | objectW ... s.field |
| capture-flow.js:259:23:259:30 | source() | capture-flow.js:253:14:253:23 | this.field |
| capture-flow.js:262:16:262:23 | source() | capture-flow.js:264:14:264:21 | this.foo |
| capture-flow.js:274:33:274:40 | source() | capture-flow.js:272:10:272:17 | this.foo |
| capture-flow.js:274:33:274:40 | source() | capture-flow.js:274:6:274:45 | new Cap ... ()).foo |
| capture-flow.js:283:34:283:41 | source() | capture-flow.js:283:6:283:46 | new Cap ... ()).foo |
| captured-sanitizer.js:25:3:25:10 | source() | captured-sanitizer.js:15:10:15:10 | x |
| constructor-calls.js:4:18:4:25 | source() | constructor-calls.js:24:8:24:14 | c.taint |

Просмотреть файл

@ -269,9 +269,9 @@ function CaptureThisWithoutJump(x) {
[1].forEach(() => {
this.foo = x;
});
sink(this.foo); // NOT OK [INCONSISTENCY]
sink(this.foo); // NOT OK
}
sink(new CaptureThisWithoutJump(source()).foo); // NOT OK [INCONSISTENCY]
sink(new CaptureThisWithoutJump(source()).foo); // NOT OK
sink(new CaptureThisWithoutJump('safe').foo); // OK
function CaptureThisWithoutJump2(x) {
@ -281,4 +281,4 @@ function CaptureThisWithoutJump2(x) {
return y;
}
sink(new CaptureThisWithoutJump2(source()).foo); // NOT OK
sink(new CaptureThisWithoutJump2('safe').foo); // OK [INCONSISTENCY]
sink(new CaptureThisWithoutJump2('safe').foo); // OK

Просмотреть файл

@ -14,7 +14,7 @@ function test() {
sink(x.sort()); // NOT OK
var a = [];
sink(a); // NOT OK (flow-insensitive treatment of `a`)
sink(a); // OK
a.push(x);
sink(a); // NOT OK

Просмотреть файл

@ -0,0 +1,177 @@
import 'dummy';
function t1() {
const obj = {};
sink(obj.field);
obj.field = source('t1.1');
sink(obj.field); // $ hasValueFlow=t1.1
obj.field = "safe";
sink(obj.field); // $ SPURIOUS: hasValueFlow=t1.1
obj.field = source('t1.2');
sink(obj.field); // $ hasValueFlow=t1.2 SPURIOUS: hasValueFlow=t1.1
}
function t2() {
let obj;
if (Math.random()) {
obj = {};
sink(obj.field);
} else {
obj = {};
obj.field = source('t2.1');
sink(obj.field); // $ hasValueFlow=t2.1
}
sink(obj.field); // $ hasValueFlow=t2.1
}
function t3() {
function inner(obj) {
sink(obj.foo); // $ hasValueFlow=t3.2 hasValueFlow=t3.1
}
inner({foo: source('t3.1')});
let obj = {};
obj.foo = source('t3.2');
inner(obj);
}
function t4() {
class C {
constructor(x) {
this.foo = x;
sink(this.foo); // $ hasValueFlow=t4.1
}
}
const c = new C(source('t4.1'));
sink(c.foo); // $ hasValueFlow=t4.1
}
function t5() {
class C {
field = source('t5.1')
constructor() {
sink(this.field); // $ hasValueFlow=t5.1
}
}
const c = new C();
sink(c.field); // $ hasValueFlow=t5.1
}
function t6() {
function invoke(fn) {
fn();
}
class C {
constructor(x, y) {
this.x = x;
invoke(() => {
this.y = y;
});
sink(this.x); // $ hasValueFlow=t6.1
sink(this.y); // $ hasValueFlow=t6.2
invoke(() => {
sink(this.x); // $ hasValueFlow=t6.1
sink(this.y); // $ hasValueFlow=t6.2
});
this.methodLike = function() {
sink(this.x); // $ hasValueFlow=t6.1
sink(this.y); // $ hasValueFlow=t6.2
}
}
}
const c = new C(source('t6.1'), source('t6.2'));
sink(c.x); // $ hasValueFlow=t6.1
sink(c.y); // $ hasValueFlow=t6.2
c.methodLike();
}
function t7() {
class Base {
constructor(x) {
this.field = x;
sink(this.field); // $ hasTaintFlow=t7.1
}
}
class Sub extends Base {
constructor(x) {
super(x + '!');
sink(this.field); // $ hasTaintFlow=t7.1
}
}
const c = new Sub(source('t7.1'));
sink(c.field); // $ hasTaintFlow=t7.1
}
function t8() {
function foo(x) {
const obj = {};
obj.field = x;
sink(obj.field); // $ hasTaintFlow=t8.1
if (obj) {
sink(obj.field); // $ hasTaintFlow=t8.1
} else {
sink(obj.field);
}
if (!obj) {
sink(obj.field);
} else {
sink(obj.field); // $ hasTaintFlow=t8.1
}
if (!obj || !obj) {
sink(obj.field);
} else {
sink(obj.field); // $ hasTaintFlow=t8.1
}
}
// The guards used above are specific to taint-tracking, to ensure only taint flows in
const taint = source('t8.1') + ' taint';
foo(taint);
}
function t9() { // same as t8 but with a SanitizerGuard that isn't just a variable access
function foo(x) {
const obj = {};
obj.field = x;
sink(obj.field); // $ hasTaintFlow=t9.1
if (typeof obj !== "undefined") {
sink(obj.field); // $ hasTaintFlow=t9.1
} else {
sink(obj.field);
}
if (typeof obj === "undefined") {
sink(obj.field);
} else {
sink(obj.field); // $ hasTaintFlow=t9.1
}
if (typeof obj === "undefined" || typeof obj === "undefined") {
// The shared SSA library expects short-circuiting operators be pre-order in the CFG,
// but in JS they are post-order (as per evaluation order).
sink(obj.field); // $ SPURIOUS: hasTaintFlow=t9.1
} else {
sink(obj.field); // $ hasTaintFlow=t9.1
}
}
// The guards used above are specific to taint-tracking, to ensure only taint flows in
const taint = source('t9.1') + ' taint';
foo(taint);
}

Просмотреть файл

@ -55,4 +55,7 @@ Set.of(source()).filter(x => true).toList().forEach(x => sink(x)); // NOT OK
Set([source()]).filter(x => true).toList().forEach(x => sink(x)); // NOT OK
OrderedSet([source()]).filter(x => true).toList().forEach(x => sink(x)); // NOT OK
OrderedSet([source()]).filter(x => true).toList().forEach(x => sink(x)); // NOT OK
x.d; // ensure 'd' property exists
x.f; // ensure 'f' property exists

Просмотреть файл

@ -100,7 +100,7 @@ test_ReactComponent_ref
| es5.js:18:33:22:1 | {\\n ren ... ;\\n }\\n} | es5.js:18:33:22:1 | {\\n ren ... ;\\n }\\n} |
| es5.js:18:33:22:1 | {\\n ren ... ;\\n }\\n} | es5.js:19:11:19:10 | this |
| es5.js:18:33:22:1 | {\\n ren ... ;\\n }\\n} | es5.js:20:24:20:27 | this |
| es6.js:1:1:8:1 | class H ... ;\\n }\\n} | es6.js:1:37:1:36 | implicit 'this' argument of super(...args) |
| es6.js:1:1:8:1 | class H ... ;\\n }\\n} | es6.js:1:37:1:36 | implicit 'this' |
| es6.js:1:1:8:1 | class H ... ;\\n }\\n} | es6.js:1:37:1:36 | this |
| es6.js:1:1:8:1 | class H ... ;\\n }\\n} | es6.js:2:9:2:8 | this |
| es6.js:1:1:8:1 | class H ... ;\\n }\\n} | es6.js:3:24:3:27 | this |
@ -111,31 +111,31 @@ test_ReactComponent_ref
| es6.js:14:1:20:1 | class H ... }\\n} | es6.js:18:9:18:12 | this |
| exportedComponent.jsx:1:8:3:1 | functio ... r}}/>\\n} | exportedComponent.jsx:1:8:1:7 | this |
| importedComponent.jsx:3:8:5:1 | functio ... or}/>\\n} | importedComponent.jsx:3:8:3:7 | this |
| namedImport.js:3:1:3:28 | class C ... nent {} | namedImport.js:3:27:3:26 | implicit 'this' argument of super(...args) |
| namedImport.js:3:1:3:28 | class C ... nent {} | namedImport.js:3:27:3:26 | implicit 'this' |
| namedImport.js:3:1:3:28 | class C ... nent {} | namedImport.js:3:27:3:26 | this |
| namedImport.js:5:1:5:20 | class D extends C {} | namedImport.js:5:19:5:18 | implicit 'this' argument of super(...args) |
| namedImport.js:5:1:5:20 | class D extends C {} | namedImport.js:5:19:5:18 | implicit 'this' |
| namedImport.js:5:1:5:20 | class D extends C {} | namedImport.js:5:19:5:18 | this |
| plainfn.js:1:1:3:1 | functio ... div>;\\n} | plainfn.js:1:1:1:0 | this |
| plainfn.js:5:1:7:1 | functio ... iv");\\n} | plainfn.js:5:1:5:0 | this |
| plainfn.js:9:1:12:1 | functio ... rn x;\\n} | plainfn.js:9:1:9:0 | this |
| plainfn.js:20:1:24:1 | functio ... n 42;\\n} | plainfn.js:20:1:20:0 | this |
| preact.js:1:1:7:1 | class H ... }\\n} | preact.js:1:38:1:37 | implicit 'this' argument of super(...args) |
| preact.js:1:1:7:1 | class H ... }\\n} | preact.js:1:38:1:37 | implicit 'this' |
| preact.js:1:1:7:1 | class H ... }\\n} | preact.js:1:38:1:37 | this |
| preact.js:1:1:7:1 | class H ... }\\n} | preact.js:2:11:2:10 | this |
| preact.js:9:1:11:1 | class H ... nt {\\n\\n} | preact.js:9:38:9:37 | implicit 'this' argument of super(...args) |
| preact.js:9:1:11:1 | class H ... nt {\\n\\n} | preact.js:9:38:9:37 | implicit 'this' |
| preact.js:9:1:11:1 | class H ... nt {\\n\\n} | preact.js:9:38:9:37 | this |
| probably-a-component.js:1:1:6:1 | class H ... }\\n} | probably-a-component.js:1:31:1:30 | implicit 'this' argument of super(...args) |
| probably-a-component.js:1:1:6:1 | class H ... }\\n} | probably-a-component.js:1:31:1:30 | implicit 'this' |
| probably-a-component.js:1:1:6:1 | class H ... }\\n} | probably-a-component.js:1:31:1:30 | this |
| probably-a-component.js:1:1:6:1 | class H ... }\\n} | probably-a-component.js:2:11:2:10 | this |
| probably-a-component.js:1:1:6:1 | class H ... }\\n} | probably-a-component.js:3:9:3:12 | this |
| props.js:2:5:3:5 | class C ... {\\n } | props.js:2:37:2:36 | implicit 'this' argument of super(...args) |
| props.js:2:5:3:5 | class C ... {\\n } | props.js:2:37:2:36 | implicit 'this' |
| props.js:2:5:3:5 | class C ... {\\n } | props.js:2:37:2:36 | this |
| props.js:2:5:3:5 | class C ... {\\n } | props.js:9:5:9:55 | new C({ ... ctor"}) |
| props.js:13:31:17:5 | {\\n ... }\\n } | props.js:13:31:17:5 | {\\n ... }\\n } |
| props.js:13:31:17:5 | {\\n ... }\\n } | props.js:14:24:14:23 | this |
| props.js:26:5:28:5 | functio ... ;\\n } | props.js:26:5:26:4 | this |
| props.js:26:5:28:5 | functio ... ;\\n } | props.js:34:5:34:55 | new C({ ... ctor"}) |
| rare-lifecycle-methods.js:1:1:11:1 | class C ... }\\n} | rare-lifecycle-methods.js:1:33:1:32 | implicit 'this' argument of super(...args) |
| rare-lifecycle-methods.js:1:1:11:1 | class C ... }\\n} | rare-lifecycle-methods.js:1:33:1:32 | implicit 'this' |
| rare-lifecycle-methods.js:1:1:11:1 | class C ... }\\n} | rare-lifecycle-methods.js:1:33:1:32 | this |
| rare-lifecycle-methods.js:1:1:11:1 | class C ... }\\n} | rare-lifecycle-methods.js:2:36:2:35 | this |
| rare-lifecycle-methods.js:1:1:11:1 | class C ... }\\n} | rare-lifecycle-methods.js:5:26:5:25 | this |
@ -155,6 +155,7 @@ test_ReactComponent_ref
| statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:18:9:18:11 | cmp |
| statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:22:9:22:11 | cmp |
| statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:25:20:25:19 | this |
| statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:31:5:33:6 | implicit 'this' |
| statePropertyWrites.js:36:19:45:1 | {\\n ren ... ;\\n }\\n} | statePropertyWrites.js:36:19:45:1 | {\\n ren ... ;\\n }\\n} |
| statePropertyWrites.js:36:19:45:1 | {\\n ren ... ;\\n }\\n} | statePropertyWrites.js:37:11:37:10 | this |
| statePropertyWrites.js:36:19:45:1 | {\\n ren ... ;\\n }\\n} | statePropertyWrites.js:38:24:38:27 | this |

Просмотреть файл

@ -16,15 +16,15 @@ edges
| tst-UntrustedDataToExternalAPI.js:10:19:10:27 | untrusted | tst-UntrustedDataToExternalAPI.js:10:13:10:33 | ['x', u ... d, 'y'] | provenance | |
| tst-UntrustedDataToExternalAPI.js:14:12:16:9 | {\\n ... } [z] | tst-UntrustedDataToExternalAPI.js:13:8:17:5 | {\\n ... }\\n } | provenance | |
| tst-UntrustedDataToExternalAPI.js:15:16:15:24 | untrusted | tst-UntrustedDataToExternalAPI.js:14:12:16:9 | {\\n ... } [z] | provenance | |
| tst-UntrustedDataToExternalAPI.js:41:11:45:1 | [post update] {\\n x ... usted\\n} [x] | tst-UntrustedDataToExternalAPI.js:41:7:41:8 | {} | provenance | |
| tst-UntrustedDataToExternalAPI.js:41:11:45:1 | [post update] {\\n x ... usted\\n} [x] | tst-UntrustedDataToExternalAPI.js:41:11:45:1 | {\\n x ... usted\\n} | provenance | |
| tst-UntrustedDataToExternalAPI.js:41:11:45:1 | [post update] {\\n x ... usted\\n} [y] | tst-UntrustedDataToExternalAPI.js:41:7:41:8 | {} | provenance | |
| tst-UntrustedDataToExternalAPI.js:41:11:45:1 | [post update] {\\n x ... usted\\n} [y] | tst-UntrustedDataToExternalAPI.js:41:11:45:1 | {\\n x ... usted\\n} | provenance | |
| tst-UntrustedDataToExternalAPI.js:41:11:45:1 | [post update] {\\n x ... usted\\n} [z] | tst-UntrustedDataToExternalAPI.js:41:7:41:8 | {} | provenance | |
| tst-UntrustedDataToExternalAPI.js:41:11:45:1 | [post update] {\\n x ... usted\\n} [z] | tst-UntrustedDataToExternalAPI.js:41:11:45:1 | {\\n x ... usted\\n} | provenance | |
| tst-UntrustedDataToExternalAPI.js:42:8:42:16 | untrusted | tst-UntrustedDataToExternalAPI.js:41:11:45:1 | [post update] {\\n x ... usted\\n} [x] | provenance | |
| tst-UntrustedDataToExternalAPI.js:43:8:43:16 | untrusted | tst-UntrustedDataToExternalAPI.js:41:11:45:1 | [post update] {\\n x ... usted\\n} [y] | provenance | |
| tst-UntrustedDataToExternalAPI.js:44:8:44:16 | untrusted | tst-UntrustedDataToExternalAPI.js:41:11:45:1 | [post update] {\\n x ... usted\\n} [z] | provenance | |
| tst-UntrustedDataToExternalAPI.js:41:11:45:1 | {\\n x ... usted\\n} [x] | tst-UntrustedDataToExternalAPI.js:41:7:41:8 | {} | provenance | |
| tst-UntrustedDataToExternalAPI.js:41:11:45:1 | {\\n x ... usted\\n} [y] | tst-UntrustedDataToExternalAPI.js:41:7:41:8 | {} | provenance | |
| tst-UntrustedDataToExternalAPI.js:41:11:45:1 | {\\n x ... usted\\n} [z] | tst-UntrustedDataToExternalAPI.js:41:7:41:8 | {} | provenance | |
| tst-UntrustedDataToExternalAPI.js:42:8:42:16 | untrusted | tst-UntrustedDataToExternalAPI.js:41:11:45:1 | {\\n x ... usted\\n} | provenance | |
| tst-UntrustedDataToExternalAPI.js:42:8:42:16 | untrusted | tst-UntrustedDataToExternalAPI.js:41:11:45:1 | {\\n x ... usted\\n} [x] | provenance | |
| tst-UntrustedDataToExternalAPI.js:43:8:43:16 | untrusted | tst-UntrustedDataToExternalAPI.js:41:11:45:1 | {\\n x ... usted\\n} | provenance | |
| tst-UntrustedDataToExternalAPI.js:43:8:43:16 | untrusted | tst-UntrustedDataToExternalAPI.js:41:11:45:1 | {\\n x ... usted\\n} [y] | provenance | |
| tst-UntrustedDataToExternalAPI.js:44:8:44:16 | untrusted | tst-UntrustedDataToExternalAPI.js:41:11:45:1 | {\\n x ... usted\\n} | provenance | |
| tst-UntrustedDataToExternalAPI.js:44:8:44:16 | untrusted | tst-UntrustedDataToExternalAPI.js:41:11:45:1 | {\\n x ... usted\\n} [z] | provenance | |
nodes
| tst-UntrustedDataToExternalAPI.js:3:5:3:27 | untrusted | semmle.label | untrusted |
| tst-UntrustedDataToExternalAPI.js:3:17:3:27 | window.name | semmle.label | window.name |
@ -42,10 +42,10 @@ nodes
| tst-UntrustedDataToExternalAPI.js:33:14:33:22 | untrusted | semmle.label | untrusted |
| tst-UntrustedDataToExternalAPI.js:34:34:34:42 | untrusted | semmle.label | untrusted |
| tst-UntrustedDataToExternalAPI.js:41:7:41:8 | {} | semmle.label | {} |
| tst-UntrustedDataToExternalAPI.js:41:11:45:1 | [post update] {\\n x ... usted\\n} [x] | semmle.label | [post update] {\\n x ... usted\\n} [x] |
| tst-UntrustedDataToExternalAPI.js:41:11:45:1 | [post update] {\\n x ... usted\\n} [y] | semmle.label | [post update] {\\n x ... usted\\n} [y] |
| tst-UntrustedDataToExternalAPI.js:41:11:45:1 | [post update] {\\n x ... usted\\n} [z] | semmle.label | [post update] {\\n x ... usted\\n} [z] |
| tst-UntrustedDataToExternalAPI.js:41:11:45:1 | {\\n x ... usted\\n} | semmle.label | {\\n x ... usted\\n} |
| tst-UntrustedDataToExternalAPI.js:41:11:45:1 | {\\n x ... usted\\n} [x] | semmle.label | {\\n x ... usted\\n} [x] |
| tst-UntrustedDataToExternalAPI.js:41:11:45:1 | {\\n x ... usted\\n} [y] | semmle.label | {\\n x ... usted\\n} [y] |
| tst-UntrustedDataToExternalAPI.js:41:11:45:1 | {\\n x ... usted\\n} [z] | semmle.label | {\\n x ... usted\\n} [z] |
| tst-UntrustedDataToExternalAPI.js:42:8:42:16 | untrusted | semmle.label | untrusted |
| tst-UntrustedDataToExternalAPI.js:43:8:43:16 | untrusted | semmle.label | untrusted |
| tst-UntrustedDataToExternalAPI.js:44:8:44:16 | untrusted | semmle.label | untrusted |

Просмотреть файл

@ -27,8 +27,7 @@ edges
| child_process-test.js:6:15:6:49 | url.par ... ry.path | child_process-test.js:6:9:6:49 | cmd | provenance | |
| child_process-test.js:6:25:6:31 | req.url | child_process-test.js:6:15:6:38 | url.par ... , true) | provenance | |
| child_process-test.js:25:21:25:23 | cmd | child_process-test.js:25:13:25:31 | "foo" + cmd + "bar" | provenance | |
| child_process-test.js:46:9:46:17 | args [1] | child_process-test.js:49:15:49:18 | args [1] | provenance | |
| child_process-test.js:48:5:48:8 | [post update] args [1] | child_process-test.js:46:9:46:17 | args [1] | provenance | |
| child_process-test.js:48:5:48:8 | [post update] args [1] | child_process-test.js:49:15:49:18 | args [1] | provenance | |
| child_process-test.js:48:15:48:17 | cmd | child_process-test.js:48:5:48:8 | [post update] args [1] | provenance | |
| child_process-test.js:49:15:49:18 | args [1] | child_process-test.js:66:19:66:22 | args | provenance | |
| child_process-test.js:56:46:56:57 | ["bar", cmd] [1] | child_process-test.js:56:25:56:58 | ['/C', ... , cmd]) | provenance | |
@ -121,7 +120,6 @@ nodes
| child_process-test.js:25:21:25:23 | cmd | semmle.label | cmd |
| child_process-test.js:39:26:39:28 | cmd | semmle.label | cmd |
| child_process-test.js:43:15:43:17 | cmd | semmle.label | cmd |
| child_process-test.js:46:9:46:17 | args [1] | semmle.label | args [1] |
| child_process-test.js:48:5:48:8 | [post update] args [1] | semmle.label | [post update] args [1] |
| child_process-test.js:48:15:48:17 | cmd | semmle.label | cmd |
| child_process-test.js:48:15:48:17 | cmd | semmle.label | cmd |

Просмотреть файл

@ -89,10 +89,8 @@ edges
| lib/lib.js:414:40:414:43 | name | lib/lib.js:426:11:426:14 | name | provenance | |
| lib/lib.js:414:40:414:43 | name | lib/lib.js:426:11:426:14 | name | provenance | |
| lib/lib.js:414:40:414:43 | name | lib/lib.js:428:36:428:39 | name | provenance | |
| lib/lib.js:425:6:425:13 | arr | lib/lib.js:427:14:427:16 | arr | provenance | |
| lib/lib.js:425:6:425:13 | arr [ArrayElement] | lib/lib.js:427:14:427:16 | arr | provenance | |
| lib/lib.js:426:2:426:4 | [post update] arr | lib/lib.js:425:6:425:13 | arr | provenance | |
| lib/lib.js:426:2:426:4 | [post update] arr [ArrayElement] | lib/lib.js:425:6:425:13 | arr [ArrayElement] | provenance | |
| lib/lib.js:426:2:426:4 | [post update] arr | lib/lib.js:427:14:427:16 | arr | provenance | |
| lib/lib.js:426:2:426:4 | [post update] arr [ArrayElement] | lib/lib.js:427:14:427:16 | arr | provenance | |
| lib/lib.js:426:11:426:14 | name | lib/lib.js:426:2:426:4 | [post update] arr | provenance | |
| lib/lib.js:426:11:426:14 | name | lib/lib.js:426:2:426:4 | [post update] arr [ArrayElement] | provenance | |
| lib/lib.js:428:28:428:57 | (name ? ... ) + '-' | lib/lib.js:428:14:428:58 | build(" ... + '-') | provenance | |
@ -100,10 +98,8 @@ edges
| lib/lib.js:428:36:428:39 | name | lib/lib.js:428:28:428:57 | (name ? ... ) + '-' | provenance | |
| lib/lib.js:431:23:431:26 | last | lib/lib.js:436:19:436:22 | last | provenance | |
| lib/lib.js:431:23:431:26 | last | lib/lib.js:436:19:436:22 | last | provenance | |
| lib/lib.js:432:6:432:13 | arr | lib/lib.js:437:9:437:11 | arr | provenance | |
| lib/lib.js:432:6:432:13 | arr [ArrayElement] | lib/lib.js:437:9:437:11 | arr [ArrayElement] | provenance | |
| lib/lib.js:436:10:436:12 | [post update] arr | lib/lib.js:432:6:432:13 | arr | provenance | |
| lib/lib.js:436:10:436:12 | [post update] arr [ArrayElement] | lib/lib.js:432:6:432:13 | arr [ArrayElement] | provenance | |
| lib/lib.js:436:10:436:12 | [post update] arr | lib/lib.js:437:9:437:11 | arr | provenance | |
| lib/lib.js:436:10:436:12 | [post update] arr [ArrayElement] | lib/lib.js:437:9:437:11 | arr [ArrayElement] | provenance | |
| lib/lib.js:436:19:436:22 | last | lib/lib.js:436:10:436:12 | [post update] arr | provenance | |
| lib/lib.js:436:19:436:22 | last | lib/lib.js:436:10:436:12 | [post update] arr [ArrayElement] | provenance | |
| lib/lib.js:441:39:441:42 | name | lib/lib.js:442:24:442:27 | name | provenance | |
@ -272,8 +268,6 @@ nodes
| lib/lib.js:419:32:419:35 | name | semmle.label | name |
| lib/lib.js:420:29:420:32 | name | semmle.label | name |
| lib/lib.js:424:24:424:27 | name | semmle.label | name |
| lib/lib.js:425:6:425:13 | arr | semmle.label | arr |
| lib/lib.js:425:6:425:13 | arr [ArrayElement] | semmle.label | arr [ArrayElement] |
| lib/lib.js:426:2:426:4 | [post update] arr | semmle.label | [post update] arr |
| lib/lib.js:426:2:426:4 | [post update] arr [ArrayElement] | semmle.label | [post update] arr [ArrayElement] |
| lib/lib.js:426:11:426:14 | name | semmle.label | name |
@ -283,8 +277,6 @@ nodes
| lib/lib.js:428:28:428:57 | (name ? ... ) + '-' | semmle.label | (name ? ... ) + '-' |
| lib/lib.js:428:36:428:39 | name | semmle.label | name |
| lib/lib.js:431:23:431:26 | last | semmle.label | last |
| lib/lib.js:432:6:432:13 | arr | semmle.label | arr |
| lib/lib.js:432:6:432:13 | arr [ArrayElement] | semmle.label | arr [ArrayElement] |
| lib/lib.js:436:10:436:12 | [post update] arr | semmle.label | [post update] arr |
| lib/lib.js:436:10:436:12 | [post update] arr [ArrayElement] | semmle.label | [post update] arr [ArrayElement] |
| lib/lib.js:436:19:436:22 | last | semmle.label | last |

Просмотреть файл

@ -258,10 +258,6 @@ nodes
| react-use-router.js:8:21:8:39 | router.query.foobar | semmle.label | router.query.foobar |
| react-use-router.js:11:24:11:35 | router.query | semmle.label | router.query |
| react-use-router.js:11:24:11:42 | router.query.foobar | semmle.label | router.query.foobar |
| react-use-router.js:23:31:23:36 | [post update] router | semmle.label | [post update] router |
| react-use-router.js:23:31:23:36 | [post update] router [ArrayElement] | semmle.label | [post update] router [ArrayElement] |
| react-use-router.js:23:43:23:48 | router | semmle.label | router |
| react-use-router.js:23:43:23:48 | router [ArrayElement] | semmle.label | router [ArrayElement] |
| react-use-router.js:23:43:23:54 | router.query | semmle.label | router.query |
| react-use-router.js:23:43:23:61 | router.query.foobar | semmle.label | router.query.foobar |
| react-use-router.js:33:21:33:32 | router.query | semmle.label | router.query |
@ -501,8 +497,6 @@ nodes
| tst.js:371:16:371:39 | documen ... .search | semmle.label | documen ... .search |
| tst.js:374:18:374:23 | target | semmle.label | target |
| tst.js:381:7:381:39 | target | semmle.label | target |
| tst.js:381:7:381:39 | target [taint3] | semmle.label | target [taint3] |
| tst.js:381:7:381:39 | target [taint8] | semmle.label | target [taint8] |
| tst.js:381:16:381:39 | documen ... .search | semmle.label | documen ... .search |
| tst.js:384:18:384:23 | target | semmle.label | target |
| tst.js:386:18:386:23 | target | semmle.label | target |
@ -824,13 +818,7 @@ edges
| react-native.js:7:17:7:33 | req.param("code") | react-native.js:7:7:7:33 | tainted | provenance | |
| react-use-router.js:8:21:8:32 | router.query | react-use-router.js:8:21:8:39 | router.query.foobar | provenance | |
| react-use-router.js:11:24:11:35 | router.query | react-use-router.js:11:24:11:42 | router.query.foobar | provenance | |
| react-use-router.js:23:31:23:36 | [post update] router | react-use-router.js:23:43:23:48 | router | provenance | |
| react-use-router.js:23:31:23:36 | [post update] router [ArrayElement] | react-use-router.js:23:43:23:48 | router [ArrayElement] | provenance | |
| react-use-router.js:23:43:23:48 | router | react-use-router.js:23:43:23:54 | router.query | provenance | |
| react-use-router.js:23:43:23:48 | router [ArrayElement] | react-use-router.js:23:43:23:54 | router.query | provenance | |
| react-use-router.js:23:43:23:54 | router.query | react-use-router.js:23:43:23:61 | router.query.foobar | provenance | |
| react-use-router.js:23:43:23:61 | router.query.foobar | react-use-router.js:23:31:23:36 | [post update] router | provenance | |
| react-use-router.js:23:43:23:61 | router.query.foobar | react-use-router.js:23:31:23:36 | [post update] router [ArrayElement] | provenance | |
| react-use-router.js:33:21:33:32 | router.query | react-use-router.js:33:21:33:39 | router.query.foobar | provenance | |
| react-use-state.js:4:9:4:49 | state | react-use-state.js:5:51:5:55 | state | provenance | |
| react-use-state.js:4:38:4:48 | window.name | react-use-state.js:4:9:4:49 | state | provenance | |
@ -1025,17 +1013,15 @@ edges
| tst.js:381:7:381:39 | target | tst.js:397:18:397:23 | target | provenance | |
| tst.js:381:7:381:39 | target | tst.js:406:18:406:23 | target | provenance | |
| tst.js:381:7:381:39 | target | tst.js:408:19:408:24 | target | provenance | |
| tst.js:381:7:381:39 | target [taint3] | tst.js:392:18:392:23 | target [taint3] | provenance | |
| tst.js:381:7:381:39 | target [taint8] | tst.js:408:19:408:24 | target [taint8] | provenance | |
| tst.js:381:7:381:39 | target [taint8] | tst.js:409:18:409:23 | target [taint8] | provenance | |
| tst.js:381:16:381:39 | documen ... .search | tst.js:381:7:381:39 | target | provenance | |
| tst.js:386:18:386:23 | target | tst.js:386:18:386:29 | target.taint | provenance | |
| tst.js:391:3:391:8 | [post update] target [taint3] | tst.js:381:7:381:39 | target [taint3] | provenance | |
| tst.js:391:3:391:8 | [post update] target [taint3] | tst.js:392:18:392:23 | target [taint3] | provenance | |
| tst.js:391:19:391:42 | documen ... .search | tst.js:391:3:391:8 | [post update] target [taint3] | provenance | |
| tst.js:392:18:392:23 | target [taint3] | tst.js:392:18:392:30 | target.taint3 | provenance | |
| tst.js:397:18:397:23 | target | tst.js:397:18:397:30 | target.taint5 | provenance | |
| tst.js:406:18:406:23 | target | tst.js:406:18:406:30 | target.taint7 | provenance | |
| tst.js:408:3:408:8 | [post update] target [taint8] | tst.js:381:7:381:39 | target [taint8] | provenance | |
| tst.js:408:3:408:8 | [post update] target [taint8] | tst.js:408:19:408:24 | target [taint8] | provenance | |
| tst.js:408:3:408:8 | [post update] target [taint8] | tst.js:409:18:409:23 | target [taint8] | provenance | |
| tst.js:408:19:408:24 | target | tst.js:408:19:408:31 | target.taint8 | provenance | |
| tst.js:408:19:408:24 | target [taint8] | tst.js:408:19:408:31 | target.taint8 | provenance | |
| tst.js:408:19:408:31 | target.taint8 | tst.js:408:3:408:8 | [post update] target [taint8] | provenance | |

Просмотреть файл

@ -263,10 +263,6 @@ nodes
| react-use-router.js:8:21:8:39 | router.query.foobar | semmle.label | router.query.foobar |
| react-use-router.js:11:24:11:35 | router.query | semmle.label | router.query |
| react-use-router.js:11:24:11:42 | router.query.foobar | semmle.label | router.query.foobar |
| react-use-router.js:23:31:23:36 | [post update] router | semmle.label | [post update] router |
| react-use-router.js:23:31:23:36 | [post update] router [ArrayElement] | semmle.label | [post update] router [ArrayElement] |
| react-use-router.js:23:43:23:48 | router | semmle.label | router |
| react-use-router.js:23:43:23:48 | router [ArrayElement] | semmle.label | router [ArrayElement] |
| react-use-router.js:23:43:23:54 | router.query | semmle.label | router.query |
| react-use-router.js:23:43:23:61 | router.query.foobar | semmle.label | router.query.foobar |
| react-use-router.js:33:21:33:32 | router.query | semmle.label | router.query |
@ -506,8 +502,6 @@ nodes
| tst.js:371:16:371:39 | documen ... .search | semmle.label | documen ... .search |
| tst.js:374:18:374:23 | target | semmle.label | target |
| tst.js:381:7:381:39 | target | semmle.label | target |
| tst.js:381:7:381:39 | target [taint3] | semmle.label | target [taint3] |
| tst.js:381:7:381:39 | target [taint8] | semmle.label | target [taint8] |
| tst.js:381:16:381:39 | documen ... .search | semmle.label | documen ... .search |
| tst.js:384:18:384:23 | target | semmle.label | target |
| tst.js:386:18:386:23 | target | semmle.label | target |
@ -848,13 +842,7 @@ edges
| react-native.js:7:17:7:33 | req.param("code") | react-native.js:7:7:7:33 | tainted | provenance | |
| react-use-router.js:8:21:8:32 | router.query | react-use-router.js:8:21:8:39 | router.query.foobar | provenance | |
| react-use-router.js:11:24:11:35 | router.query | react-use-router.js:11:24:11:42 | router.query.foobar | provenance | |
| react-use-router.js:23:31:23:36 | [post update] router | react-use-router.js:23:43:23:48 | router | provenance | |
| react-use-router.js:23:31:23:36 | [post update] router [ArrayElement] | react-use-router.js:23:43:23:48 | router [ArrayElement] | provenance | |
| react-use-router.js:23:43:23:48 | router | react-use-router.js:23:43:23:54 | router.query | provenance | |
| react-use-router.js:23:43:23:48 | router [ArrayElement] | react-use-router.js:23:43:23:54 | router.query | provenance | |
| react-use-router.js:23:43:23:54 | router.query | react-use-router.js:23:43:23:61 | router.query.foobar | provenance | |
| react-use-router.js:23:43:23:61 | router.query.foobar | react-use-router.js:23:31:23:36 | [post update] router | provenance | |
| react-use-router.js:23:43:23:61 | router.query.foobar | react-use-router.js:23:31:23:36 | [post update] router [ArrayElement] | provenance | |
| react-use-router.js:33:21:33:32 | router.query | react-use-router.js:33:21:33:39 | router.query.foobar | provenance | |
| react-use-state.js:4:9:4:49 | state | react-use-state.js:5:51:5:55 | state | provenance | |
| react-use-state.js:4:38:4:48 | window.name | react-use-state.js:4:9:4:49 | state | provenance | |
@ -1049,17 +1037,15 @@ edges
| tst.js:381:7:381:39 | target | tst.js:397:18:397:23 | target | provenance | |
| tst.js:381:7:381:39 | target | tst.js:406:18:406:23 | target | provenance | |
| tst.js:381:7:381:39 | target | tst.js:408:19:408:24 | target | provenance | |
| tst.js:381:7:381:39 | target [taint3] | tst.js:392:18:392:23 | target [taint3] | provenance | |
| tst.js:381:7:381:39 | target [taint8] | tst.js:408:19:408:24 | target [taint8] | provenance | |
| tst.js:381:7:381:39 | target [taint8] | tst.js:409:18:409:23 | target [taint8] | provenance | |
| tst.js:381:16:381:39 | documen ... .search | tst.js:381:7:381:39 | target | provenance | |
| tst.js:386:18:386:23 | target | tst.js:386:18:386:29 | target.taint | provenance | |
| tst.js:391:3:391:8 | [post update] target [taint3] | tst.js:381:7:381:39 | target [taint3] | provenance | |
| tst.js:391:3:391:8 | [post update] target [taint3] | tst.js:392:18:392:23 | target [taint3] | provenance | |
| tst.js:391:19:391:42 | documen ... .search | tst.js:391:3:391:8 | [post update] target [taint3] | provenance | |
| tst.js:392:18:392:23 | target [taint3] | tst.js:392:18:392:30 | target.taint3 | provenance | |
| tst.js:397:18:397:23 | target | tst.js:397:18:397:30 | target.taint5 | provenance | |
| tst.js:406:18:406:23 | target | tst.js:406:18:406:30 | target.taint7 | provenance | |
| tst.js:408:3:408:8 | [post update] target [taint8] | tst.js:381:7:381:39 | target [taint8] | provenance | |
| tst.js:408:3:408:8 | [post update] target [taint8] | tst.js:408:19:408:24 | target [taint8] | provenance | |
| tst.js:408:3:408:8 | [post update] target [taint8] | tst.js:409:18:409:23 | target [taint8] | provenance | |
| tst.js:408:19:408:24 | target | tst.js:408:19:408:31 | target.taint8 | provenance | |
| tst.js:408:19:408:24 | target [taint8] | tst.js:408:19:408:31 | target.taint8 | provenance | |
| tst.js:408:19:408:31 | target.taint8 | tst.js:408:3:408:8 | [post update] target [taint8] | provenance | |

Просмотреть файл

@ -44,15 +44,13 @@ edges
| ReflectedXssGood3.js:68:22:68:26 | value | ReflectedXssGood3.js:105:18:105:22 | value | provenance | |
| ReflectedXssGood3.js:77:7:77:37 | parts | ReflectedXssGood3.js:108:10:108:14 | parts | provenance | |
| ReflectedXssGood3.js:77:7:77:37 | parts [0] | ReflectedXssGood3.js:108:10:108:14 | parts [0] | provenance | |
| ReflectedXssGood3.js:77:7:77:37 | parts [ArrayElement] | ReflectedXssGood3.js:108:10:108:14 | parts [ArrayElement] | provenance | |
| ReflectedXssGood3.js:77:15:77:37 | [value. ... (0, i)] [0] | ReflectedXssGood3.js:77:7:77:37 | parts [0] | provenance | |
| ReflectedXssGood3.js:77:16:77:20 | value | ReflectedXssGood3.js:77:16:77:36 | value.s ... g(0, i) | provenance | |
| ReflectedXssGood3.js:77:16:77:36 | value.s ... g(0, i) | ReflectedXssGood3.js:77:7:77:37 | parts | provenance | |
| ReflectedXssGood3.js:77:16:77:36 | value.s ... g(0, i) | ReflectedXssGood3.js:77:15:77:37 | [value. ... (0, i)] [0] | provenance | |
| ReflectedXssGood3.js:77:16:77:36 | value.s ... g(0, i) | ReflectedXssGood3.js:108:10:108:23 | parts.join('') | provenance | |
| ReflectedXssGood3.js:105:7:105:11 | [post update] parts | ReflectedXssGood3.js:77:7:77:37 | parts | provenance | |
| ReflectedXssGood3.js:105:7:105:11 | [post update] parts | ReflectedXssGood3.js:108:10:108:23 | parts.join('') | provenance | |
| ReflectedXssGood3.js:105:7:105:11 | [post update] parts [ArrayElement] | ReflectedXssGood3.js:77:7:77:37 | parts [ArrayElement] | provenance | |
| ReflectedXssGood3.js:105:7:105:11 | [post update] parts | ReflectedXssGood3.js:108:10:108:14 | parts | provenance | |
| ReflectedXssGood3.js:105:7:105:11 | [post update] parts [ArrayElement] | ReflectedXssGood3.js:108:10:108:14 | parts [ArrayElement] | provenance | |
| ReflectedXssGood3.js:105:18:105:22 | value | ReflectedXssGood3.js:105:18:105:38 | value.s ... g(j, i) | provenance | |
| ReflectedXssGood3.js:105:18:105:38 | value.s ... g(j, i) | ReflectedXssGood3.js:105:7:105:11 | [post update] parts | provenance | |
| ReflectedXssGood3.js:105:18:105:38 | value.s ... g(j, i) | ReflectedXssGood3.js:105:7:105:11 | [post update] parts [ArrayElement] | provenance | |
@ -103,8 +101,7 @@ edges
| tst2.js:30:7:30:24 | p | tst2.js:33:11:33:11 | p | provenance | |
| tst2.js:30:7:30:24 | p | tst2.js:36:12:36:12 | p | provenance | |
| tst2.js:30:9:30:9 | p | tst2.js:30:7:30:24 | p | provenance | |
| tst2.js:32:7:32:14 | obj [p] | tst2.js:34:21:34:23 | obj [p] | provenance | |
| tst2.js:33:3:33:5 | [post update] obj [p] | tst2.js:32:7:32:14 | obj [p] | provenance | |
| tst2.js:33:3:33:5 | [post update] obj [p] | tst2.js:34:21:34:23 | obj [p] | provenance | |
| tst2.js:33:11:33:11 | p | tst2.js:33:3:33:5 | [post update] obj [p] | provenance | |
| tst2.js:34:7:34:24 | other [p] | tst2.js:37:12:37:16 | other [p] | provenance | |
| tst2.js:34:15:34:24 | clone(obj) [p] | tst2.js:34:7:34:24 | other [p] | provenance | |
@ -118,8 +115,7 @@ edges
| tst2.js:57:7:57:24 | p | tst2.js:60:11:60:11 | p | provenance | |
| tst2.js:57:7:57:24 | p | tst2.js:63:12:63:12 | p | provenance | |
| tst2.js:57:9:57:9 | p | tst2.js:57:7:57:24 | p | provenance | |
| tst2.js:59:7:59:14 | obj [p] | tst2.js:61:22:61:24 | obj [p] | provenance | |
| tst2.js:60:3:60:5 | [post update] obj [p] | tst2.js:59:7:59:14 | obj [p] | provenance | |
| tst2.js:60:3:60:5 | [post update] obj [p] | tst2.js:61:22:61:24 | obj [p] | provenance | |
| tst2.js:60:11:60:11 | p | tst2.js:60:3:60:5 | [post update] obj [p] | provenance | |
| tst2.js:61:7:61:25 | other [p] | tst2.js:64:12:64:16 | other [p] | provenance | |
| tst2.js:61:15:61:25 | fclone(obj) [p] | tst2.js:61:7:61:25 | other [p] | provenance | |
@ -128,8 +124,7 @@ edges
| tst2.js:69:7:69:24 | p | tst2.js:72:11:72:11 | p | provenance | |
| tst2.js:69:7:69:24 | p | tst2.js:75:12:75:12 | p | provenance | |
| tst2.js:69:9:69:9 | p | tst2.js:69:7:69:24 | p | provenance | |
| tst2.js:71:7:71:14 | obj [p] | tst2.js:73:40:73:42 | obj [p] | provenance | |
| tst2.js:72:3:72:5 | [post update] obj [p] | tst2.js:71:7:71:14 | obj [p] | provenance | |
| tst2.js:72:3:72:5 | [post update] obj [p] | tst2.js:73:40:73:42 | obj [p] | provenance | |
| tst2.js:72:11:72:11 | p | tst2.js:72:3:72:5 | [post update] obj [p] | provenance | |
| tst2.js:73:7:73:44 | other [p] | tst2.js:76:12:76:16 | other [p] | provenance | |
| tst2.js:73:15:73:44 | jc.retr ... e(obj)) [p] | tst2.js:73:7:73:44 | other [p] | provenance | |
@ -139,8 +134,7 @@ edges
| tst2.js:82:7:82:24 | p | tst2.js:85:11:85:11 | p | provenance | |
| tst2.js:82:7:82:24 | p | tst2.js:88:12:88:12 | p | provenance | |
| tst2.js:82:9:82:9 | p | tst2.js:82:7:82:24 | p | provenance | |
| tst2.js:84:7:84:14 | obj [p] | tst2.js:86:24:86:26 | obj [p] | provenance | |
| tst2.js:85:3:85:5 | [post update] obj [p] | tst2.js:84:7:84:14 | obj [p] | provenance | |
| tst2.js:85:3:85:5 | [post update] obj [p] | tst2.js:86:24:86:26 | obj [p] | provenance | |
| tst2.js:85:11:85:11 | p | tst2.js:85:3:85:5 | [post update] obj [p] | provenance | |
| tst2.js:86:7:86:27 | other [p] | tst2.js:89:12:89:16 | other [p] | provenance | |
| tst2.js:86:15:86:27 | sortKeys(obj) [p] | tst2.js:86:7:86:27 | other [p] | provenance | |
@ -220,7 +214,6 @@ nodes
| ReflectedXssGood3.js:68:22:68:26 | value | semmle.label | value |
| ReflectedXssGood3.js:77:7:77:37 | parts | semmle.label | parts |
| ReflectedXssGood3.js:77:7:77:37 | parts [0] | semmle.label | parts [0] |
| ReflectedXssGood3.js:77:7:77:37 | parts [ArrayElement] | semmle.label | parts [ArrayElement] |
| ReflectedXssGood3.js:77:15:77:37 | [value. ... (0, i)] [0] | semmle.label | [value. ... (0, i)] [0] |
| ReflectedXssGood3.js:77:16:77:20 | value | semmle.label | value |
| ReflectedXssGood3.js:77:16:77:36 | value.s ... g(0, i) | semmle.label | value.s ... g(0, i) |
@ -290,7 +283,6 @@ nodes
| tst2.js:21:14:21:14 | p | semmle.label | p |
| tst2.js:30:7:30:24 | p | semmle.label | p |
| tst2.js:30:9:30:9 | p | semmle.label | p |
| tst2.js:32:7:32:14 | obj [p] | semmle.label | obj [p] |
| tst2.js:33:3:33:5 | [post update] obj [p] | semmle.label | [post update] obj [p] |
| tst2.js:33:11:33:11 | p | semmle.label | p |
| tst2.js:34:7:34:24 | other [p] | semmle.label | other [p] |
@ -307,7 +299,6 @@ nodes
| tst2.js:51:12:51:17 | unsafe | semmle.label | unsafe |
| tst2.js:57:7:57:24 | p | semmle.label | p |
| tst2.js:57:9:57:9 | p | semmle.label | p |
| tst2.js:59:7:59:14 | obj [p] | semmle.label | obj [p] |
| tst2.js:60:3:60:5 | [post update] obj [p] | semmle.label | [post update] obj [p] |
| tst2.js:60:11:60:11 | p | semmle.label | p |
| tst2.js:61:7:61:25 | other [p] | semmle.label | other [p] |
@ -318,7 +309,6 @@ nodes
| tst2.js:64:12:64:18 | other.p | semmle.label | other.p |
| tst2.js:69:7:69:24 | p | semmle.label | p |
| tst2.js:69:9:69:9 | p | semmle.label | p |
| tst2.js:71:7:71:14 | obj [p] | semmle.label | obj [p] |
| tst2.js:72:3:72:5 | [post update] obj [p] | semmle.label | [post update] obj [p] |
| tst2.js:72:11:72:11 | p | semmle.label | p |
| tst2.js:73:7:73:44 | other [p] | semmle.label | other [p] |
@ -330,7 +320,6 @@ nodes
| tst2.js:76:12:76:18 | other.p | semmle.label | other.p |
| tst2.js:82:7:82:24 | p | semmle.label | p |
| tst2.js:82:9:82:9 | p | semmle.label | p |
| tst2.js:84:7:84:14 | obj [p] | semmle.label | obj [p] |
| tst2.js:85:3:85:5 | [post update] obj [p] | semmle.label | [post update] obj [p] |
| tst2.js:85:11:85:11 | p | semmle.label | p |
| tst2.js:86:7:86:27 | other [p] | semmle.label | other [p] |

Просмотреть файл

@ -17,10 +17,26 @@ edges
| unsafe-jquery-plugin.js:11:7:11:29 | target | unsafe-jquery-plugin.js:60:6:60:11 | target | provenance | |
| unsafe-jquery-plugin.js:11:16:11:22 | options | unsafe-jquery-plugin.js:11:16:11:29 | options.target | provenance | |
| unsafe-jquery-plugin.js:11:16:11:29 | options.target | unsafe-jquery-plugin.js:11:7:11:29 | target | provenance | |
| unsafe-jquery-plugin.js:65:47:65:53 | options | unsafe-jquery-plugin.js:67:37:67:43 | options | provenance | |
| unsafe-jquery-plugin.js:67:3:67:6 | [post update] this [options] | unsafe-jquery-plugin.js:68:7:68:10 | this [options] | provenance | |
| unsafe-jquery-plugin.js:67:24:67:44 | $.exten ... ptions) | unsafe-jquery-plugin.js:67:3:67:6 | [post update] this [options] | provenance | |
| unsafe-jquery-plugin.js:67:37:67:43 | options | unsafe-jquery-plugin.js:67:24:67:44 | $.exten ... ptions) | provenance | |
| unsafe-jquery-plugin.js:68:7:68:10 | this [options] | unsafe-jquery-plugin.js:68:7:68:18 | this.options | provenance | |
| unsafe-jquery-plugin.js:68:7:68:18 | this.options | unsafe-jquery-plugin.js:68:7:68:25 | this.options.parent | provenance | |
| unsafe-jquery-plugin.js:68:7:68:25 | this.options.parent | unsafe-jquery-plugin.js:68:45:68:63 | this.options.parent | provenance | Config |
| unsafe-jquery-plugin.js:71:38:71:44 | options | unsafe-jquery-plugin.js:72:5:72:11 | options | provenance | |
| unsafe-jquery-plugin.js:72:5:72:11 | options | unsafe-jquery-plugin.js:72:5:72:23 | options.foo.bar.baz | provenance | |
| unsafe-jquery-plugin.js:76:38:76:44 | options | unsafe-jquery-plugin.js:77:17:77:23 | options | provenance | |
| unsafe-jquery-plugin.js:77:17:77:23 | options | unsafe-jquery-plugin.js:77:17:77:35 | options.foo.bar.baz | provenance | |
| unsafe-jquery-plugin.js:84:38:84:44 | options | unsafe-jquery-plugin.js:92:5:92:11 | options | provenance | |
| unsafe-jquery-plugin.js:85:14:85:14 | o | unsafe-jquery-plugin.js:86:26:86:26 | o | provenance | |
| unsafe-jquery-plugin.js:86:4:86:7 | [post update] this [o] | unsafe-jquery-plugin.js:87:12:87:15 | this [o] | provenance | |
| unsafe-jquery-plugin.js:86:13:86:27 | $.extend({}, o) | unsafe-jquery-plugin.js:86:4:86:7 | [post update] this [o] | provenance | |
| unsafe-jquery-plugin.js:86:26:86:26 | o | unsafe-jquery-plugin.js:86:13:86:27 | $.extend({}, o) | provenance | |
| unsafe-jquery-plugin.js:87:8:87:24 | t | unsafe-jquery-plugin.js:90:6:90:6 | t | provenance | |
| unsafe-jquery-plugin.js:87:12:87:15 | this [o] | unsafe-jquery-plugin.js:87:12:87:17 | this.o | provenance | |
| unsafe-jquery-plugin.js:87:12:87:17 | this.o | unsafe-jquery-plugin.js:87:8:87:24 | t | provenance | |
| unsafe-jquery-plugin.js:92:5:92:11 | options | unsafe-jquery-plugin.js:85:14:85:14 | o | provenance | |
| unsafe-jquery-plugin.js:101:38:101:44 | options | unsafe-jquery-plugin.js:105:6:105:12 | options | provenance | |
| unsafe-jquery-plugin.js:102:3:105:13 | options | unsafe-jquery-plugin.js:107:5:107:11 | options | provenance | |
| unsafe-jquery-plugin.js:102:13:105:13 | $.exten ... ptions) | unsafe-jquery-plugin.js:102:3:105:13 | options | provenance | |
@ -75,12 +91,30 @@ nodes
| unsafe-jquery-plugin.js:48:6:48:11 | target | semmle.label | target |
| unsafe-jquery-plugin.js:52:6:52:11 | target | semmle.label | target |
| unsafe-jquery-plugin.js:60:6:60:11 | target | semmle.label | target |
| unsafe-jquery-plugin.js:65:47:65:53 | options | semmle.label | options |
| unsafe-jquery-plugin.js:67:3:67:6 | [post update] this [options] | semmle.label | [post update] this [options] |
| unsafe-jquery-plugin.js:67:24:67:44 | $.exten ... ptions) | semmle.label | $.exten ... ptions) |
| unsafe-jquery-plugin.js:67:37:67:43 | options | semmle.label | options |
| unsafe-jquery-plugin.js:68:7:68:10 | this [options] | semmle.label | this [options] |
| unsafe-jquery-plugin.js:68:7:68:18 | this.options | semmle.label | this.options |
| unsafe-jquery-plugin.js:68:7:68:25 | this.options.parent | semmle.label | this.options.parent |
| unsafe-jquery-plugin.js:68:45:68:63 | this.options.parent | semmle.label | this.options.parent |
| unsafe-jquery-plugin.js:71:38:71:44 | options | semmle.label | options |
| unsafe-jquery-plugin.js:72:5:72:11 | options | semmle.label | options |
| unsafe-jquery-plugin.js:72:5:72:23 | options.foo.bar.baz | semmle.label | options.foo.bar.baz |
| unsafe-jquery-plugin.js:76:38:76:44 | options | semmle.label | options |
| unsafe-jquery-plugin.js:77:17:77:23 | options | semmle.label | options |
| unsafe-jquery-plugin.js:77:17:77:35 | options.foo.bar.baz | semmle.label | options.foo.bar.baz |
| unsafe-jquery-plugin.js:84:38:84:44 | options | semmle.label | options |
| unsafe-jquery-plugin.js:85:14:85:14 | o | semmle.label | o |
| unsafe-jquery-plugin.js:86:4:86:7 | [post update] this [o] | semmle.label | [post update] this [o] |
| unsafe-jquery-plugin.js:86:13:86:27 | $.extend({}, o) | semmle.label | $.extend({}, o) |
| unsafe-jquery-plugin.js:86:26:86:26 | o | semmle.label | o |
| unsafe-jquery-plugin.js:87:8:87:24 | t | semmle.label | t |
| unsafe-jquery-plugin.js:87:12:87:15 | this [o] | semmle.label | this [o] |
| unsafe-jquery-plugin.js:87:12:87:17 | this.o | semmle.label | this.o |
| unsafe-jquery-plugin.js:90:6:90:6 | t | semmle.label | t |
| unsafe-jquery-plugin.js:92:5:92:11 | options | semmle.label | options |
| unsafe-jquery-plugin.js:101:38:101:44 | options | semmle.label | options |
| unsafe-jquery-plugin.js:102:3:105:13 | options | semmle.label | options |
| unsafe-jquery-plugin.js:102:13:105:13 | $.exten ... ptions) | semmle.label | $.exten ... ptions) |
@ -135,8 +169,10 @@ subpaths
| unsafe-jquery-plugin.js:48:6:48:11 | target | unsafe-jquery-plugin.js:2:38:2:44 | options | unsafe-jquery-plugin.js:48:6:48:11 | target | Potential XSS vulnerability in the $@. | unsafe-jquery-plugin.js:2:19:63:2 | functio ... \\t\\t}\\n\\n\\t} | '$.fn.my_plugin' plugin |
| unsafe-jquery-plugin.js:52:6:52:11 | target | unsafe-jquery-plugin.js:2:38:2:44 | options | unsafe-jquery-plugin.js:52:6:52:11 | target | Potential XSS vulnerability in the $@. | unsafe-jquery-plugin.js:2:19:63:2 | functio ... \\t\\t}\\n\\n\\t} | '$.fn.my_plugin' plugin |
| unsafe-jquery-plugin.js:60:6:60:11 | target | unsafe-jquery-plugin.js:2:38:2:44 | options | unsafe-jquery-plugin.js:60:6:60:11 | target | Potential XSS vulnerability in the $@. | unsafe-jquery-plugin.js:2:19:63:2 | functio ... \\t\\t}\\n\\n\\t} | '$.fn.my_plugin' plugin |
| unsafe-jquery-plugin.js:68:45:68:63 | this.options.parent | unsafe-jquery-plugin.js:65:47:65:53 | options | unsafe-jquery-plugin.js:68:45:68:63 | this.options.parent | Potential XSS vulnerability in the $@. | unsafe-jquery-plugin.js:65:19:69:2 | functio ... T OK\\n\\t} | '$.fn.my_plugin' plugin |
| unsafe-jquery-plugin.js:72:5:72:23 | options.foo.bar.baz | unsafe-jquery-plugin.js:71:38:71:44 | options | unsafe-jquery-plugin.js:72:5:72:23 | options.foo.bar.baz | Potential XSS vulnerability in the $@. | unsafe-jquery-plugin.js:71:19:74:2 | functio ... / OK\\n\\t} | '$.fn.my_plugin' plugin |
| unsafe-jquery-plugin.js:77:17:77:35 | options.foo.bar.baz | unsafe-jquery-plugin.js:76:38:76:44 | options | unsafe-jquery-plugin.js:77:17:77:35 | options.foo.bar.baz | Potential XSS vulnerability in the $@. | unsafe-jquery-plugin.js:76:19:78:2 | functio ... T OK\\n\\t} | '$.fn.my_plugin' plugin |
| unsafe-jquery-plugin.js:90:6:90:6 | t | unsafe-jquery-plugin.js:84:38:84:44 | options | unsafe-jquery-plugin.js:90:6:90:6 | t | Potential XSS vulnerability in the $@. | unsafe-jquery-plugin.js:84:19:93:2 | functio ... ns);\\n\\t} | '$.fn.my_plugin' plugin |
| unsafe-jquery-plugin.js:107:5:107:18 | options.target | unsafe-jquery-plugin.js:101:38:101:44 | options | unsafe-jquery-plugin.js:107:5:107:18 | options.target | Potential XSS vulnerability in the $@. | unsafe-jquery-plugin.js:101:19:108:2 | functio ... T OK\\n\\t} | '$.fn.my_plugin' plugin |
| unsafe-jquery-plugin.js:117:5:117:18 | options.target | unsafe-jquery-plugin.js:114:38:114:44 | options | unsafe-jquery-plugin.js:117:5:117:18 | options.target | Potential XSS vulnerability in the $@. | unsafe-jquery-plugin.js:114:19:118:2 | functio ... T OK\\n\\t} | '$.fn.my_plugin' plugin |
| unsafe-jquery-plugin.js:122:5:122:18 | options.target | unsafe-jquery-plugin.js:121:40:121:46 | options | unsafe-jquery-plugin.js:122:5:122:18 | options.target | Potential XSS vulnerability in the $@. | unsafe-jquery-plugin.js:121:21:123:2 | functio ... T OK\\n\\t} | '$.fn.my_plugin' plugin |

Просмотреть файл

@ -52,8 +52,6 @@ nodes
| json-schema-validator.js:61:22:61:26 | query | semmle.label | query |
| koarouter.js:5:11:5:33 | version | semmle.label | version |
| koarouter.js:5:13:5:19 | version | semmle.label | version |
| koarouter.js:11:11:11:28 | conditions | semmle.label | conditions |
| koarouter.js:11:11:11:28 | conditions [ArrayElement] | semmle.label | conditions [ArrayElement] |
| koarouter.js:14:9:14:18 | [post update] conditions | semmle.label | [post update] conditions |
| koarouter.js:14:9:14:18 | [post update] conditions [ArrayElement] | semmle.label | [post update] conditions [ArrayElement] |
| koarouter.js:14:25:14:46 | `versio ... rsion}` | semmle.label | `versio ... rsion}` |
@ -327,10 +325,8 @@ edges
| json-schema-validator.js:50:34:50:47 | req.query.data | json-schema-validator.js:50:23:50:48 | JSON.pa ... y.data) | provenance | Config |
| koarouter.js:5:11:5:33 | version | koarouter.js:14:38:14:44 | version | provenance | |
| koarouter.js:5:13:5:19 | version | koarouter.js:5:11:5:33 | version | provenance | |
| koarouter.js:11:11:11:28 | conditions | koarouter.js:17:52:17:61 | conditions | provenance | |
| koarouter.js:11:11:11:28 | conditions [ArrayElement] | koarouter.js:17:52:17:61 | conditions [ArrayElement] | provenance | |
| koarouter.js:14:9:14:18 | [post update] conditions | koarouter.js:11:11:11:28 | conditions | provenance | |
| koarouter.js:14:9:14:18 | [post update] conditions [ArrayElement] | koarouter.js:11:11:11:28 | conditions [ArrayElement] | provenance | |
| koarouter.js:14:9:14:18 | [post update] conditions | koarouter.js:17:52:17:61 | conditions | provenance | |
| koarouter.js:14:9:14:18 | [post update] conditions [ArrayElement] | koarouter.js:17:52:17:61 | conditions [ArrayElement] | provenance | |
| koarouter.js:14:25:14:46 | `versio ... rsion}` | koarouter.js:14:9:14:18 | [post update] conditions | provenance | |
| koarouter.js:14:25:14:46 | `versio ... rsion}` | koarouter.js:14:9:14:18 | [post update] conditions [ArrayElement] | provenance | |
| koarouter.js:14:38:14:44 | version | koarouter.js:14:25:14:46 | `versio ... rsion}` | provenance | |

Просмотреть файл

@ -1,10 +1,8 @@
edges
| bad-code-sanitization.js:2:12:2:90 | /^[_$a- ... key)}]` | bad-code-sanitization.js:7:31:7:43 | safeProp(key) | provenance | |
| bad-code-sanitization.js:2:69:2:87 | JSON.stringify(key) | bad-code-sanitization.js:2:12:2:90 | /^[_$a- ... key)}]` | provenance | |
| bad-code-sanitization.js:6:11:6:25 | statements | bad-code-sanitization.js:8:27:8:36 | statements | provenance | |
| bad-code-sanitization.js:6:11:6:25 | statements [ArrayElement] | bad-code-sanitization.js:8:27:8:36 | statements [ArrayElement] | provenance | |
| bad-code-sanitization.js:7:5:7:14 | [post update] statements | bad-code-sanitization.js:6:11:6:25 | statements | provenance | |
| bad-code-sanitization.js:7:5:7:14 | [post update] statements [ArrayElement] | bad-code-sanitization.js:6:11:6:25 | statements [ArrayElement] | provenance | |
| bad-code-sanitization.js:7:5:7:14 | [post update] statements | bad-code-sanitization.js:8:27:8:36 | statements | provenance | |
| bad-code-sanitization.js:7:5:7:14 | [post update] statements [ArrayElement] | bad-code-sanitization.js:8:27:8:36 | statements [ArrayElement] | provenance | |
| bad-code-sanitization.js:7:21:7:70 | `${name ... key])}` | bad-code-sanitization.js:7:5:7:14 | [post update] statements | provenance | |
| bad-code-sanitization.js:7:21:7:70 | `${name ... key])}` | bad-code-sanitization.js:7:5:7:14 | [post update] statements [ArrayElement] | provenance | |
| bad-code-sanitization.js:7:31:7:43 | safeProp(key) | bad-code-sanitization.js:7:21:7:70 | `${name ... key])}` | provenance | |
@ -15,8 +13,6 @@ edges
nodes
| bad-code-sanitization.js:2:12:2:90 | /^[_$a- ... key)}]` | semmle.label | /^[_$a- ... key)}]` |
| bad-code-sanitization.js:2:69:2:87 | JSON.stringify(key) | semmle.label | JSON.stringify(key) |
| bad-code-sanitization.js:6:11:6:25 | statements | semmle.label | statements |
| bad-code-sanitization.js:6:11:6:25 | statements [ArrayElement] | semmle.label | statements [ArrayElement] |
| bad-code-sanitization.js:7:5:7:14 | [post update] statements | semmle.label | [post update] statements |
| bad-code-sanitization.js:7:5:7:14 | [post update] statements [ArrayElement] | semmle.label | [post update] statements [ArrayElement] |
| bad-code-sanitization.js:7:21:7:70 | `${name ... key])}` | semmle.label | `${name ... key])}` |

Просмотреть файл

@ -1,8 +1,7 @@
edges
| FileAccessToHttp.js:4:5:4:47 | content | FileAccessToHttp.js:9:23:9:29 | content | provenance | |
| FileAccessToHttp.js:4:15:4:47 | fs.read ... "utf8") | FileAccessToHttp.js:4:5:4:47 | content | provenance | |
| FileAccessToHttp.js:5:11:10:1 | [post update] {\\n hos ... ent }\\n} [headers, Referer] | FileAccessToHttp.js:5:11:10:1 | {\\n hos ... ent }\\n} | provenance | |
| FileAccessToHttp.js:9:12:9:31 | { Referer: content } [Referer] | FileAccessToHttp.js:5:11:10:1 | [post update] {\\n hos ... ent }\\n} [headers, Referer] | provenance | |
| FileAccessToHttp.js:9:12:9:31 | { Referer: content } [Referer] | FileAccessToHttp.js:5:11:10:1 | {\\n hos ... ent }\\n} | provenance | |
| FileAccessToHttp.js:9:23:9:29 | content | FileAccessToHttp.js:9:12:9:31 | { Referer: content } [Referer] | provenance | |
| bufferRead.js:12:13:12:43 | buffer | bufferRead.js:13:21:13:26 | buffer | provenance | |
| bufferRead.js:12:13:12:43 | buffer | bufferRead.js:13:32:13:37 | buffer | provenance | |
@ -20,11 +19,9 @@ edges
| readStreamRead.js:13:13:13:35 | chunk | readStreamRead.js:30:19:30:23 | chunk | provenance | |
| readStreamRead.js:13:21:13:35 | readable.read() | readStreamRead.js:13:13:13:35 | chunk | provenance | |
| request.js:6:19:6:26 | jsonData | request.js:8:12:8:19 | jsonData | provenance | |
| request.js:8:11:8:20 | [post update] {jsonData} [jsonData] | request.js:8:11:8:20 | {jsonData} | provenance | |
| request.js:8:12:8:19 | jsonData | request.js:8:11:8:20 | [post update] {jsonData} [jsonData] | provenance | |
| request.js:8:12:8:19 | jsonData | request.js:8:11:8:20 | {jsonData} | provenance | |
| request.js:13:18:13:24 | xmlData | request.js:22:11:22:17 | xmlData | provenance | |
| request.js:16:11:23:3 | [post update] {\\n u ... ody\\n } [body] | request.js:16:11:23:3 | {\\n u ... ody\\n } | provenance | |
| request.js:22:11:22:17 | xmlData | request.js:16:11:23:3 | [post update] {\\n u ... ody\\n } [body] | provenance | |
| request.js:22:11:22:17 | xmlData | request.js:16:11:23:3 | {\\n u ... ody\\n } | provenance | |
| request.js:28:52:28:55 | data | request.js:35:14:35:17 | data | provenance | |
| request.js:35:14:35:17 | data | request.js:6:19:6:26 | jsonData | provenance | |
| request.js:43:51:43:54 | data | request.js:50:13:50:16 | data | provenance | |
@ -38,18 +35,15 @@ edges
| sentAsHeaders.js:12:19:12:25 | content | sentAsHeaders.js:12:19:12:74 | content ... =", "") | provenance | |
| sentAsHeaders.js:12:19:12:74 | content ... =", "") | sentAsHeaders.js:12:19:12:81 | content ... .trim() | provenance | |
| sentAsHeaders.js:12:19:12:81 | content ... .trim() | sentAsHeaders.js:12:9:12:81 | content | provenance | |
| sentAsHeaders.js:14:20:19:9 | [post update] {\\n ... } [headers, Referer] | sentAsHeaders.js:14:20:19:9 | {\\n ... } | provenance | |
| sentAsHeaders.js:18:20:18:55 | { Refer ... ntent } [Referer] | sentAsHeaders.js:14:20:19:9 | [post update] {\\n ... } [headers, Referer] | provenance | |
| sentAsHeaders.js:18:20:18:55 | { Refer ... ntent } [Referer] | sentAsHeaders.js:14:20:19:9 | {\\n ... } | provenance | |
| sentAsHeaders.js:18:31:18:53 | "http:/ ... content | sentAsHeaders.js:18:20:18:55 | { Refer ... ntent } [Referer] | provenance | |
| sentAsHeaders.js:18:47:18:53 | content | sentAsHeaders.js:18:31:18:53 | "http:/ ... content | provenance | |
| sentAsHeaders.js:20:20:25:9 | [post update] {\\n ... } [headers, Referer] | sentAsHeaders.js:20:20:25:9 | {\\n ... } | provenance | |
| sentAsHeaders.js:24:20:24:55 | { Refer ... ntent } [Referer] | sentAsHeaders.js:20:20:25:9 | [post update] {\\n ... } [headers, Referer] | provenance | |
| sentAsHeaders.js:24:20:24:55 | { Refer ... ntent } [Referer] | sentAsHeaders.js:20:20:25:9 | {\\n ... } | provenance | |
| sentAsHeaders.js:24:31:24:53 | "http:/ ... content | sentAsHeaders.js:24:20:24:55 | { Refer ... ntent } [Referer] | provenance | |
| sentAsHeaders.js:24:47:24:53 | content | sentAsHeaders.js:24:31:24:53 | "http:/ ... content | provenance | |
nodes
| FileAccessToHttp.js:4:5:4:47 | content | semmle.label | content |
| FileAccessToHttp.js:4:15:4:47 | fs.read ... "utf8") | semmle.label | fs.read ... "utf8") |
| FileAccessToHttp.js:5:11:10:1 | [post update] {\\n hos ... ent }\\n} [headers, Referer] | semmle.label | [post update] {\\n hos ... ent }\\n} [headers, Referer] |
| FileAccessToHttp.js:5:11:10:1 | {\\n hos ... ent }\\n} | semmle.label | {\\n hos ... ent }\\n} |
| FileAccessToHttp.js:9:12:9:31 | { Referer: content } [Referer] | semmle.label | { Referer: content } [Referer] |
| FileAccessToHttp.js:9:23:9:29 | content | semmle.label | content |
@ -71,11 +65,9 @@ nodes
| readStreamRead.js:13:21:13:35 | readable.read() | semmle.label | readable.read() |
| readStreamRead.js:30:19:30:23 | chunk | semmle.label | chunk |
| request.js:6:19:6:26 | jsonData | semmle.label | jsonData |
| request.js:8:11:8:20 | [post update] {jsonData} [jsonData] | semmle.label | [post update] {jsonData} [jsonData] |
| request.js:8:11:8:20 | {jsonData} | semmle.label | {jsonData} |
| request.js:8:12:8:19 | jsonData | semmle.label | jsonData |
| request.js:13:18:13:24 | xmlData | semmle.label | xmlData |
| request.js:16:11:23:3 | [post update] {\\n u ... ody\\n } [body] | semmle.label | [post update] {\\n u ... ody\\n } [body] |
| request.js:16:11:23:3 | {\\n u ... ody\\n } | semmle.label | {\\n u ... ody\\n } |
| request.js:22:11:22:17 | xmlData | semmle.label | xmlData |
| request.js:28:52:28:55 | data | semmle.label | data |
@ -90,12 +82,10 @@ nodes
| sentAsHeaders.js:12:19:12:25 | content | semmle.label | content |
| sentAsHeaders.js:12:19:12:74 | content ... =", "") | semmle.label | content ... =", "") |
| sentAsHeaders.js:12:19:12:81 | content ... .trim() | semmle.label | content ... .trim() |
| sentAsHeaders.js:14:20:19:9 | [post update] {\\n ... } [headers, Referer] | semmle.label | [post update] {\\n ... } [headers, Referer] |
| sentAsHeaders.js:14:20:19:9 | {\\n ... } | semmle.label | {\\n ... } |
| sentAsHeaders.js:18:20:18:55 | { Refer ... ntent } [Referer] | semmle.label | { Refer ... ntent } [Referer] |
| sentAsHeaders.js:18:31:18:53 | "http:/ ... content | semmle.label | "http:/ ... content |
| sentAsHeaders.js:18:47:18:53 | content | semmle.label | content |
| sentAsHeaders.js:20:20:25:9 | [post update] {\\n ... } [headers, Referer] | semmle.label | [post update] {\\n ... } [headers, Referer] |
| sentAsHeaders.js:20:20:25:9 | {\\n ... } | semmle.label | {\\n ... } |
| sentAsHeaders.js:24:20:24:55 | { Refer ... ntent } [Referer] | semmle.label | { Refer ... ntent } [Referer] |
| sentAsHeaders.js:24:31:24:53 | "http:/ ... content | semmle.label | "http:/ ... content |

Просмотреть файл

@ -1,12 +1,10 @@
edges
| PostMessageStar2.js:4:7:4:15 | data [foo] | PostMessageStar2.js:8:29:8:32 | data | provenance | |
| PostMessageStar2.js:4:7:4:15 | data [foo] | PostMessageStar2.js:9:29:9:32 | data [foo] | provenance | |
| PostMessageStar2.js:5:3:5:6 | [post update] data [foo] | PostMessageStar2.js:4:7:4:15 | data [foo] | provenance | |
| PostMessageStar2.js:5:3:5:6 | [post update] data [foo] | PostMessageStar2.js:8:29:8:32 | data | provenance | |
| PostMessageStar2.js:5:3:5:6 | [post update] data [foo] | PostMessageStar2.js:9:29:9:32 | data [foo] | provenance | |
| PostMessageStar2.js:5:14:5:21 | password | PostMessageStar2.js:5:3:5:6 | [post update] data [foo] | provenance | |
| PostMessageStar2.js:9:29:9:32 | data [foo] | PostMessageStar2.js:9:29:9:36 | data.foo | provenance | |
nodes
| PostMessageStar2.js:1:27:1:34 | password | semmle.label | password |
| PostMessageStar2.js:4:7:4:15 | data [foo] | semmle.label | data [foo] |
| PostMessageStar2.js:5:3:5:6 | [post update] data [foo] | semmle.label | [post update] data [foo] |
| PostMessageStar2.js:5:14:5:21 | password | semmle.label | password |
| PostMessageStar2.js:8:29:8:32 | data | semmle.label | data |

Просмотреть файл

@ -1,89 +1,58 @@
edges
| build-leaks.js:4:39:6:1 | [post update] { // NO ... .env)\\n} [process.env] | build-leaks.js:4:39:6:1 | { // NO ... .env)\\n} | provenance | |
| build-leaks.js:5:20:5:46 | JSON.st ... ss.env) | build-leaks.js:4:39:6:1 | [post update] { // NO ... .env)\\n} [process.env] | provenance | |
| build-leaks.js:5:20:5:46 | JSON.st ... ss.env) | build-leaks.js:4:39:6:1 | { // NO ... .env)\\n} | provenance | |
| build-leaks.js:5:35:5:45 | process.env | build-leaks.js:5:20:5:46 | JSON.st ... ss.env) | provenance | |
| build-leaks.js:13:11:19:10 | raw | build-leaks.js:22:36:22:38 | raw | provenance | |
| build-leaks.js:13:17:19:10 | Object. ... }) | build-leaks.js:13:11:19:10 | raw | provenance | |
| build-leaks.js:14:18:14:20 | env | build-leaks.js:16:20:16:22 | env | provenance | |
| build-leaks.js:14:18:14:20 | env | build-leaks.js:16:20:16:22 | env | provenance | |
| build-leaks.js:14:18:14:20 | env [Return] | build-leaks.js:17:12:19:9 | [post update] {\\n ... } | provenance | |
| build-leaks.js:15:13:15:15 | [post update] env | build-leaks.js:14:18:14:20 | env | provenance | |
| build-leaks.js:15:13:15:15 | [post update] env | build-leaks.js:14:18:14:20 | env [Return] | provenance | |
| build-leaks.js:15:13:15:15 | [post update] env | build-leaks.js:16:20:16:22 | env | provenance | |
| build-leaks.js:15:24:15:34 | process.env | build-leaks.js:15:13:15:15 | [post update] env | provenance | Config |
| build-leaks.js:16:20:16:22 | env | build-leaks.js:13:17:19:10 | Object. ... }) | provenance | |
| build-leaks.js:16:20:16:22 | env | build-leaks.js:14:18:14:20 | env | provenance | |
| build-leaks.js:16:20:16:22 | env | build-leaks.js:22:49:22:51 | env | provenance | |
| build-leaks.js:17:12:19:9 | [post update] {\\n ... } | build-leaks.js:17:12:19:9 | {\\n ... } | provenance | |
| build-leaks.js:17:12:19:9 | {\\n ... } | build-leaks.js:13:17:19:10 | Object. ... }) | provenance | |
| build-leaks.js:17:12:19:9 | {\\n ... } | build-leaks.js:14:18:14:20 | env | provenance | |
| build-leaks.js:21:11:26:5 | stringifed [process.env] | build-leaks.js:30:22:30:31 | stringifed [process.env] | provenance | |
| build-leaks.js:21:24:26:5 | {\\n ... )\\n } [process.env] | build-leaks.js:21:11:26:5 | stringifed [process.env] | provenance | |
| build-leaks.js:22:24:25:14 | Object. ... }, {}) | build-leaks.js:21:24:26:5 | {\\n ... )\\n } [process.env] | provenance | |
| build-leaks.js:22:36:22:38 | raw | build-leaks.js:22:24:25:14 | Object. ... }, {}) | provenance | Config |
| build-leaks.js:22:36:22:38 | raw | build-leaks.js:22:49:22:51 | env | provenance | Config |
| build-leaks.js:22:36:22:38 | raw | build-leaks.js:23:39:23:41 | raw | provenance | |
| build-leaks.js:22:36:22:38 | raw | build-leaks.js:25:12:25:13 | [post update] {} | provenance | Config |
| build-leaks.js:22:49:22:51 | env | build-leaks.js:24:20:24:22 | env | provenance | |
| build-leaks.js:22:49:22:51 | env | build-leaks.js:24:20:24:22 | env | provenance | |
| build-leaks.js:23:13:23:15 | [post update] env | build-leaks.js:22:49:22:51 | env | provenance | |
| build-leaks.js:23:13:23:15 | [post update] env | build-leaks.js:22:49:22:51 | env [Return] | provenance | |
| build-leaks.js:23:13:23:15 | [post update] env | build-leaks.js:24:20:24:22 | env | provenance | |
| build-leaks.js:23:39:23:41 | raw | build-leaks.js:23:13:23:15 | [post update] env | provenance | Config |
| build-leaks.js:25:12:25:13 | [post update] {} | build-leaks.js:25:12:25:13 | {} | provenance | |
| build-leaks.js:25:12:25:13 | {} | build-leaks.js:22:24:25:14 | Object. ... }, {}) | provenance | |
| build-leaks.js:25:12:25:13 | {} | build-leaks.js:22:49:22:51 | env | provenance | |
| build-leaks.js:28:12:31:5 | {\\n ... d\\n } [stringified, process.env] | build-leaks.js:34:26:34:45 | getEnv('production') [stringified, process.env] | provenance | |
| build-leaks.js:30:22:30:31 | stringifed [process.env] | build-leaks.js:28:12:31:5 | {\\n ... d\\n } [stringified, process.env] | provenance | |
| build-leaks.js:34:26:34:45 | getEnv('production') [stringified, process.env] | build-leaks.js:34:26:34:57 | getEnv( ... ngified | provenance | |
| build-leaks.js:40:9:40:60 | pw | build-leaks.js:41:82:41:83 | pw | provenance | |
| build-leaks.js:40:14:40:60 | url.par ... assword | build-leaks.js:40:9:40:60 | pw | provenance | |
| build-leaks.js:41:43:41:86 | [post update] { "proc ... y(pw) } [process.env.secret] | build-leaks.js:41:43:41:86 | { "proc ... y(pw) } | provenance | |
| build-leaks.js:41:67:41:84 | JSON.stringify(pw) | build-leaks.js:41:43:41:86 | [post update] { "proc ... y(pw) } [process.env.secret] | provenance | |
| build-leaks.js:41:67:41:84 | JSON.stringify(pw) | build-leaks.js:41:43:41:86 | { "proc ... y(pw) } | provenance | |
| build-leaks.js:41:82:41:83 | pw | build-leaks.js:41:67:41:84 | JSON.stringify(pw) | provenance | |
nodes
| build-leaks.js:4:39:6:1 | [post update] { // NO ... .env)\\n} [process.env] | semmle.label | [post update] { // NO ... .env)\\n} [process.env] |
| build-leaks.js:4:39:6:1 | { // NO ... .env)\\n} | semmle.label | { // NO ... .env)\\n} |
| build-leaks.js:5:20:5:46 | JSON.st ... ss.env) | semmle.label | JSON.st ... ss.env) |
| build-leaks.js:5:35:5:45 | process.env | semmle.label | process.env |
| build-leaks.js:13:11:19:10 | raw | semmle.label | raw |
| build-leaks.js:13:17:19:10 | Object. ... }) | semmle.label | Object. ... }) |
| build-leaks.js:14:18:14:20 | env | semmle.label | env |
| build-leaks.js:14:18:14:20 | env | semmle.label | env |
| build-leaks.js:14:18:14:20 | env [Return] | semmle.label | env [Return] |
| build-leaks.js:15:13:15:15 | [post update] env | semmle.label | [post update] env |
| build-leaks.js:15:24:15:34 | process.env | semmle.label | process.env |
| build-leaks.js:16:20:16:22 | env | semmle.label | env |
| build-leaks.js:16:20:16:22 | env | semmle.label | env |
| build-leaks.js:17:12:19:9 | [post update] {\\n ... } | semmle.label | [post update] {\\n ... } |
| build-leaks.js:17:12:19:9 | {\\n ... } | semmle.label | {\\n ... } |
| build-leaks.js:21:11:26:5 | stringifed [process.env] | semmle.label | stringifed [process.env] |
| build-leaks.js:21:24:26:5 | {\\n ... )\\n } [process.env] | semmle.label | {\\n ... )\\n } [process.env] |
| build-leaks.js:22:24:25:14 | Object. ... }, {}) | semmle.label | Object. ... }, {}) |
| build-leaks.js:22:36:22:38 | raw | semmle.label | raw |
| build-leaks.js:22:49:22:51 | env | semmle.label | env |
| build-leaks.js:22:49:22:51 | env | semmle.label | env |
| build-leaks.js:22:49:22:51 | env [Return] | semmle.label | env [Return] |
| build-leaks.js:23:13:23:15 | [post update] env | semmle.label | [post update] env |
| build-leaks.js:23:39:23:41 | raw | semmle.label | raw |
| build-leaks.js:24:20:24:22 | env | semmle.label | env |
| build-leaks.js:24:20:24:22 | env | semmle.label | env |
| build-leaks.js:25:12:25:13 | [post update] {} | semmle.label | [post update] {} |
| build-leaks.js:25:12:25:13 | {} | semmle.label | {} |
| build-leaks.js:28:12:31:5 | {\\n ... d\\n } [stringified, process.env] | semmle.label | {\\n ... d\\n } [stringified, process.env] |
| build-leaks.js:30:22:30:31 | stringifed [process.env] | semmle.label | stringifed [process.env] |
| build-leaks.js:34:26:34:45 | getEnv('production') [stringified, process.env] | semmle.label | getEnv('production') [stringified, process.env] |
| build-leaks.js:34:26:34:57 | getEnv( ... ngified | semmle.label | getEnv( ... ngified |
| build-leaks.js:40:9:40:60 | pw | semmle.label | pw |
| build-leaks.js:40:14:40:60 | url.par ... assword | semmle.label | url.par ... assword |
| build-leaks.js:41:43:41:86 | [post update] { "proc ... y(pw) } [process.env.secret] | semmle.label | [post update] { "proc ... y(pw) } [process.env.secret] |
| build-leaks.js:41:43:41:86 | { "proc ... y(pw) } | semmle.label | { "proc ... y(pw) } |
| build-leaks.js:41:67:41:84 | JSON.stringify(pw) | semmle.label | JSON.stringify(pw) |
| build-leaks.js:41:82:41:83 | pw | semmle.label | pw |
subpaths
| build-leaks.js:17:12:19:9 | {\\n ... } | build-leaks.js:14:18:14:20 | env | build-leaks.js:16:20:16:22 | env | build-leaks.js:13:17:19:10 | Object. ... }) |
| build-leaks.js:22:36:22:38 | raw | build-leaks.js:22:49:22:51 | env | build-leaks.js:24:20:24:22 | env | build-leaks.js:22:24:25:14 | Object. ... }, {}) |
| build-leaks.js:22:36:22:38 | raw | build-leaks.js:23:39:23:41 | raw | build-leaks.js:22:49:22:51 | env [Return] | build-leaks.js:25:12:25:13 | [post update] {} |
| build-leaks.js:22:36:22:38 | raw | build-leaks.js:23:39:23:41 | raw | build-leaks.js:24:20:24:22 | env | build-leaks.js:22:24:25:14 | Object. ... }, {}) |
| build-leaks.js:25:12:25:13 | {} | build-leaks.js:22:49:22:51 | env | build-leaks.js:24:20:24:22 | env | build-leaks.js:22:24:25:14 | Object. ... }, {}) |
#select
| build-leaks.js:4:39:6:1 | { // NO ... .env)\\n} | build-leaks.js:5:35:5:45 | process.env | build-leaks.js:4:39:6:1 | { // NO ... .env)\\n} | This creates a build artifact that depends on $@. | build-leaks.js:5:35:5:45 | process.env | sensitive data returned byprocess environment |
| build-leaks.js:34:26:34:57 | getEnv( ... ngified | build-leaks.js:15:24:15:34 | process.env | build-leaks.js:34:26:34:57 | getEnv( ... ngified | This creates a build artifact that depends on $@. | build-leaks.js:15:24:15:34 | process.env | sensitive data returned byprocess environment |

Просмотреть файл

@ -9,9 +9,6 @@ edges
| passwords.js:23:9:25:5 | obj2 [x] | passwords.js:26:17:26:20 | obj2 | provenance | |
| passwords.js:23:16:25:5 | {\\n ... d\\n } [x] | passwords.js:23:9:25:5 | obj2 [x] | provenance | |
| passwords.js:24:12:24:19 | password | passwords.js:23:16:25:5 | {\\n ... d\\n } [x] | provenance | |
| passwords.js:28:9:28:17 | obj3 [x] | passwords.js:29:17:29:20 | obj3 | provenance | |
| passwords.js:30:5:30:8 | [post update] obj3 [x] | passwords.js:28:9:28:17 | obj3 [x] | provenance | |
| passwords.js:30:14:30:21 | password | passwords.js:30:5:30:8 | [post update] obj3 [x] | provenance | |
| passwords.js:77:9:77:55 | temp [encryptedPassword] | passwords.js:78:17:78:20 | temp [encryptedPassword] | provenance | |
| passwords.js:77:16:77:55 | { encry ... sword } [encryptedPassword] | passwords.js:77:9:77:55 | temp [encryptedPassword] | provenance | |
| passwords.js:77:37:77:53 | req.body.password | passwords.js:77:16:77:55 | { encry ... sword } [encryptedPassword] | provenance | |
@ -97,10 +94,6 @@ nodes
| passwords.js:23:16:25:5 | {\\n ... d\\n } [x] | semmle.label | {\\n ... d\\n } [x] |
| passwords.js:24:12:24:19 | password | semmle.label | password |
| passwords.js:26:17:26:20 | obj2 | semmle.label | obj2 |
| passwords.js:28:9:28:17 | obj3 [x] | semmle.label | obj3 [x] |
| passwords.js:29:17:29:20 | obj3 | semmle.label | obj3 |
| passwords.js:30:5:30:8 | [post update] obj3 [x] | semmle.label | [post update] obj3 [x] |
| passwords.js:30:14:30:21 | password | semmle.label | password |
| passwords.js:77:9:77:55 | temp [encryptedPassword] | semmle.label | temp [encryptedPassword] |
| passwords.js:77:16:77:55 | { encry ... sword } [encryptedPassword] | semmle.label | { encry ... sword } [encryptedPassword] |
| passwords.js:77:37:77:53 | req.body.password | semmle.label | req.body.password |
@ -192,7 +185,6 @@ subpaths
| passwords.js:16:17:16:38 | `${name ... sword}` | passwords.js:16:29:16:36 | password | passwords.js:16:17:16:38 | `${name ... sword}` | This logs sensitive data returned by $@ as clear text. | passwords.js:16:29:16:36 | password | an access to password |
| passwords.js:21:17:21:20 | obj1 | passwords.js:19:19:19:19 | x | passwords.js:21:17:21:20 | obj1 | This logs sensitive data returned by $@ as clear text. | passwords.js:19:19:19:19 | x | an access to password |
| passwords.js:26:17:26:20 | obj2 | passwords.js:24:12:24:19 | password | passwords.js:26:17:26:20 | obj2 | This logs sensitive data returned by $@ as clear text. | passwords.js:24:12:24:19 | password | an access to password |
| passwords.js:29:17:29:20 | obj3 | passwords.js:30:14:30:21 | password | passwords.js:29:17:29:20 | obj3 | This logs sensitive data returned by $@ as clear text. | passwords.js:30:14:30:21 | password | an access to password |
| passwords.js:78:17:78:38 | temp.en ... assword | passwords.js:77:37:77:53 | req.body.password | passwords.js:78:17:78:38 | temp.en ... assword | This logs sensitive data returned by $@ as clear text. | passwords.js:77:37:77:53 | req.body.password | an access to password |
| passwords.js:81:17:81:31 | `pw: ${secret}` | passwords.js:80:18:80:25 | password | passwords.js:81:17:81:31 | `pw: ${secret}` | This logs sensitive data returned by $@ as clear text. | passwords.js:80:18:80:25 | password | an access to password |
| passwords.js:93:21:93:46 | "Passwo ... assword | passwords.js:93:39:93:46 | password | passwords.js:93:21:93:46 | "Passwo ... assword | This logs sensitive data returned by $@ as clear text. | passwords.js:93:39:93:46 | password | an access to password |

Просмотреть файл

@ -26,7 +26,7 @@
console.log(obj2); // NOT OK
var obj3 = {};
console.log(obj3); // OK - but still flagged due to flow-insensitive field-analysis. [INCONSISTENCY]
console.log(obj3); // OK
obj3.x = password;
var fixed_password = "123";
@ -174,4 +174,4 @@ const debug = require('debug')('test');
const myPasscode = foo();
console.log(myPasscode); // NOT OK
});
});

Просмотреть файл

@ -4,13 +4,11 @@ nodes
| angularmerge.js:2:32:2:36 | event | semmle.label | event |
| angularmerge.js:2:32:2:41 | event.data | semmle.label | event.data |
| src-vulnerable-lodash/tst.js:7:17:7:29 | req.query.foo | semmle.label | req.query.foo |
| src-vulnerable-lodash/tst.js:10:17:12:5 | [post update] {\\n ... K\\n } [value] | semmle.label | [post update] {\\n ... K\\n } [value] |
| src-vulnerable-lodash/tst.js:10:17:12:5 | {\\n ... K\\n } | semmle.label | {\\n ... K\\n } |
| src-vulnerable-lodash/tst.js:11:16:11:30 | req.query.value | semmle.label | req.query.value |
| src-vulnerable-lodash/tst.js:14:9:16:5 | opts [thing] | semmle.label | opts [thing] |
| src-vulnerable-lodash/tst.js:14:16:16:5 | {\\n ... e\\n } [thing] | semmle.label | {\\n ... e\\n } [thing] |
| src-vulnerable-lodash/tst.js:15:14:15:28 | req.query.value | semmle.label | req.query.value |
| src-vulnerable-lodash/tst.js:17:17:19:5 | [post update] {\\n ... K\\n } [value] | semmle.label | [post update] {\\n ... K\\n } [value] |
| src-vulnerable-lodash/tst.js:17:17:19:5 | {\\n ... K\\n } | semmle.label | {\\n ... K\\n } |
| src-vulnerable-lodash/tst.js:18:16:18:19 | opts [thing] | semmle.label | opts [thing] |
| src-vulnerable-lodash/tst.js:18:16:18:25 | opts.thing | semmle.label | opts.thing |
@ -32,14 +30,12 @@ edges
| angularmerge.js:1:30:1:34 | event | angularmerge.js:2:32:2:36 | event | provenance | |
| angularmerge.js:2:32:2:36 | event | angularmerge.js:2:32:2:41 | event.data | provenance | |
| angularmerge.js:2:32:2:41 | event.data | angularmerge.js:2:21:2:42 | JSON.pa ... t.data) | provenance | Config |
| src-vulnerable-lodash/tst.js:10:17:12:5 | [post update] {\\n ... K\\n } [value] | src-vulnerable-lodash/tst.js:10:17:12:5 | {\\n ... K\\n } | provenance | |
| src-vulnerable-lodash/tst.js:11:16:11:30 | req.query.value | src-vulnerable-lodash/tst.js:10:17:12:5 | [post update] {\\n ... K\\n } [value] | provenance | |
| src-vulnerable-lodash/tst.js:11:16:11:30 | req.query.value | src-vulnerable-lodash/tst.js:10:17:12:5 | {\\n ... K\\n } | provenance | |
| src-vulnerable-lodash/tst.js:14:9:16:5 | opts [thing] | src-vulnerable-lodash/tst.js:18:16:18:19 | opts [thing] | provenance | |
| src-vulnerable-lodash/tst.js:14:16:16:5 | {\\n ... e\\n } [thing] | src-vulnerable-lodash/tst.js:14:9:16:5 | opts [thing] | provenance | |
| src-vulnerable-lodash/tst.js:15:14:15:28 | req.query.value | src-vulnerable-lodash/tst.js:14:16:16:5 | {\\n ... e\\n } [thing] | provenance | |
| src-vulnerable-lodash/tst.js:17:17:19:5 | [post update] {\\n ... K\\n } [value] | src-vulnerable-lodash/tst.js:17:17:19:5 | {\\n ... K\\n } | provenance | |
| src-vulnerable-lodash/tst.js:18:16:18:19 | opts [thing] | src-vulnerable-lodash/tst.js:18:16:18:25 | opts.thing | provenance | |
| src-vulnerable-lodash/tst.js:18:16:18:25 | opts.thing | src-vulnerable-lodash/tst.js:17:17:19:5 | [post update] {\\n ... K\\n } [value] | provenance | |
| src-vulnerable-lodash/tst.js:18:16:18:25 | opts.thing | src-vulnerable-lodash/tst.js:17:17:19:5 | {\\n ... K\\n } | provenance | |
| webix/webix.html:3:34:3:38 | event | webix/webix.html:4:37:4:41 | event | provenance | |
| webix/webix.html:3:34:3:38 | event | webix/webix.html:5:35:5:39 | event | provenance | |
| webix/webix.html:4:37:4:41 | event | webix/webix.html:4:37:4:46 | event.data | provenance | |