mirror of
https://github.com/github/codeql.git
synced 2026-04-29 10:45:15 +02:00
Merge remote-tracking branch 'upstream/master' into XssDom
This commit is contained in:
@@ -1588,7 +1588,16 @@ public class TypeScriptASTConverter {
|
||||
}
|
||||
|
||||
private Node convertLiteralType(JsonObject node, SourceLocation loc) throws ParseError {
|
||||
return convertChild(node, "literal");
|
||||
Node literal = convertChild(node, "literal");
|
||||
// Convert a negated literal to a negative number
|
||||
if (literal instanceof UnaryExpression) {
|
||||
UnaryExpression unary = (UnaryExpression) literal;
|
||||
if (unary.getOperator().equals("-") && unary.getArgument() instanceof Literal) {
|
||||
Literal arg = (Literal) unary.getArgument();
|
||||
literal = new Literal(loc, arg.getTokenType(), "-" + arg.getValue());
|
||||
}
|
||||
}
|
||||
return literal;
|
||||
}
|
||||
|
||||
private Node convertMappedType(JsonObject node, SourceLocation loc) throws ParseError {
|
||||
|
||||
@@ -14,6 +14,37 @@
|
||||
|
||||
import Misspelling
|
||||
|
||||
from GlobalVarAccess gva, VarDecl lvd
|
||||
where misspelledVariableName(gva, lvd)
|
||||
select gva, "'" + gva + "' may be a typo for variable $@.", lvd, lvd.getName()
|
||||
/**
|
||||
* Gets the number of times a local variable with name `name` occurs in the program.
|
||||
*/
|
||||
bindingset[name]
|
||||
int localAcceses(string name) {
|
||||
result = count(VarAccess acc | acc.getName() = name and not acc instanceof GlobalVarAccess)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of times a global variable with name `name` occurs in the program.
|
||||
*/
|
||||
bindingset[name]
|
||||
int globalAccesses(string name) { result = count(GlobalVarAccess acc | acc.getName() = name) }
|
||||
|
||||
/**
|
||||
* Holds if our heuristic says that the local variable `lvd` seems to be a misspelling of the global variable `gva`.
|
||||
* Otherwise the global variable is likely the misspelling.
|
||||
*/
|
||||
predicate globalIsLikelyCorrect(GlobalVarAccess gva, VarDecl lvd) {
|
||||
// If there are more occurrences of the global (by a margin of at least 2), and the local is missing one letter compared to the global.
|
||||
globalAccesses(gva.getName()) >= localAcceses(lvd.getName()) + 2 and
|
||||
lvd.getName().length() = gva.getName().length() - 1
|
||||
or
|
||||
// Or if there are many more of the global.
|
||||
globalAccesses(gva.getName()) > 2 * localAcceses(lvd.getName()) + 2
|
||||
}
|
||||
|
||||
from GlobalVarAccess gva, VarDecl lvd, string msg
|
||||
where
|
||||
misspelledVariableName(gva, lvd) and
|
||||
if globalIsLikelyCorrect(gva, lvd)
|
||||
then msg = "$@ may be a typo for '" + gva + "'."
|
||||
else msg = "'" + gva + "' may be a typo for variable $@."
|
||||
select gva, msg, lvd, lvd.getName()
|
||||
|
||||
@@ -12,6 +12,7 @@ import semmle.javascript.Base64
|
||||
import semmle.javascript.CFG
|
||||
import semmle.javascript.Classes
|
||||
import semmle.javascript.Closure
|
||||
import semmle.javascript.Collections
|
||||
import semmle.javascript.Comments
|
||||
import semmle.javascript.Concepts
|
||||
import semmle.javascript.Constants
|
||||
|
||||
@@ -125,6 +125,42 @@ class ASTNode extends @ast_node, Locatable {
|
||||
/** Holds if this syntactic entity belongs to an externs file. */
|
||||
predicate inExternsFile() { getTopLevel().isExterns() }
|
||||
|
||||
/**
|
||||
* Holds if this is an ambient node that is not a `TypeExpr` and is not inside a `.d.ts` file
|
||||
*
|
||||
* Since the overwhelming majority of ambient nodes are `TypeExpr` or inside `.d.ts` files,
|
||||
* we avoid caching them.
|
||||
*/
|
||||
cached
|
||||
private predicate isAmbientInternal() {
|
||||
getParent().isAmbientInternal()
|
||||
or
|
||||
not isAmbientTopLevel(getTopLevel()) and
|
||||
(
|
||||
this instanceof ExternalModuleDeclaration
|
||||
or
|
||||
this instanceof GlobalAugmentationDeclaration
|
||||
or
|
||||
this instanceof ExportAsNamespaceDeclaration
|
||||
or
|
||||
this instanceof TypeAliasDeclaration
|
||||
or
|
||||
this instanceof InterfaceDeclaration
|
||||
or
|
||||
hasDeclareKeyword(this)
|
||||
or
|
||||
hasTypeKeyword(this)
|
||||
or
|
||||
// An export such as `export declare function f()` should be seen as ambient.
|
||||
hasDeclareKeyword(this.(ExportNamedDeclaration).getOperand())
|
||||
or
|
||||
exists(Function f |
|
||||
this = f and
|
||||
not f.hasBody()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this is part of an ambient declaration or type annotation in a TypeScript file.
|
||||
*
|
||||
@@ -134,9 +170,22 @@ class ASTNode extends @ast_node, Locatable {
|
||||
* The TypeScript compiler emits no code for ambient declarations, but they
|
||||
* can affect name resolution and type checking at compile-time.
|
||||
*/
|
||||
predicate isAmbient() { getParent().isAmbient() }
|
||||
pragma[inline]
|
||||
predicate isAmbient() {
|
||||
isAmbientInternal()
|
||||
or
|
||||
isAmbientTopLevel(getTopLevel())
|
||||
or
|
||||
this instanceof TypeExpr
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the given file is a `.d.ts` file.
|
||||
*/
|
||||
cached
|
||||
private predicate isAmbientTopLevel(TopLevel tl) { tl.getFile().getBaseName().matches("%.d.ts") }
|
||||
|
||||
/**
|
||||
* A toplevel syntactic unit; that is, a stand-alone script, an inline script
|
||||
* embedded in an HTML `<script>` tag, a code snippet assigned to an HTML event
|
||||
@@ -197,11 +246,6 @@ class TopLevel extends @toplevel, StmtContainer {
|
||||
override ControlFlowNode getFirstControlFlowNode() { result = getEntry() }
|
||||
|
||||
override string toString() { result = "<toplevel>" }
|
||||
|
||||
override predicate isAmbient() {
|
||||
getFile().getFileType().isTypeScript() and
|
||||
getFile().getBaseName().matches("%.d.ts")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -96,10 +96,55 @@ module ArrayTaintTracking {
|
||||
* Classes and predicates for modelling data-flow for arrays.
|
||||
*/
|
||||
private module ArrayDataFlow {
|
||||
private import DataFlow::PseudoProperties
|
||||
|
||||
/**
|
||||
* Gets a pseudo-field representing an element inside an array.
|
||||
* A step modelling the creation of an Array using the `Array.from(x)` method.
|
||||
* The step copies the elements of the argument (set, array, or iterator elements) into the resulting array.
|
||||
*/
|
||||
private string arrayElement() { result = "$arrayElement$" }
|
||||
private class ArrayFrom extends DataFlow::AdditionalFlowStep, DataFlow::CallNode {
|
||||
ArrayFrom() { this = DataFlow::globalVarRef("Array").getAMemberCall("from") }
|
||||
|
||||
override predicate loadStoreStep(
|
||||
DataFlow::Node pred, DataFlow::Node succ, string fromProp, string toProp
|
||||
) {
|
||||
pred = this.getArgument(0) and
|
||||
succ = this and
|
||||
fromProp = arrayLikeElement() and
|
||||
toProp = arrayElement()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A step modelling an array copy where the spread operator is used.
|
||||
* The result is essentially array concatenation.
|
||||
*
|
||||
* Such a step can occur both with the `push` and `unshift` methods, or when creating a new array.
|
||||
*/
|
||||
private class ArrayCopySpread extends DataFlow::AdditionalFlowStep {
|
||||
DataFlow::Node spreadArgument; // the spread argument containing the elements to be copied.
|
||||
DataFlow::Node base; // the object where the elements should be copied to.
|
||||
|
||||
ArrayCopySpread() {
|
||||
exists(DataFlow::MethodCallNode mcn | mcn = this |
|
||||
mcn.getMethodName() = ["push", "unshift"] and
|
||||
spreadArgument = mcn.getASpreadArgument() and
|
||||
base = mcn.getReceiver().getALocalSource()
|
||||
)
|
||||
or
|
||||
spreadArgument = this.(DataFlow::ArrayCreationNode).getASpreadArgument() and
|
||||
base = this
|
||||
}
|
||||
|
||||
override predicate loadStoreStep(
|
||||
DataFlow::Node pred, DataFlow::Node succ, string fromProp, string toProp
|
||||
) {
|
||||
pred = spreadArgument and
|
||||
succ = base and
|
||||
fromProp = arrayLikeElement() and
|
||||
toProp = arrayElement()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A step for storing an element on an array using `arr.push(e)` or `arr.unshift(e)`.
|
||||
@@ -110,10 +155,10 @@ private module ArrayDataFlow {
|
||||
this.getMethodName() = "unshift"
|
||||
}
|
||||
|
||||
override predicate storeStep(DataFlow::Node element, DataFlow::Node obj, string prop) {
|
||||
override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) {
|
||||
prop = arrayElement() and
|
||||
(element = this.getAnArgument() or element = this.getASpreadArgument()) and
|
||||
obj = this.getReceiver().getALocalSource()
|
||||
element = this.getAnArgument() and
|
||||
obj.getAMethodCall() = this
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,10 +188,10 @@ private module ArrayDataFlow {
|
||||
element = this
|
||||
}
|
||||
|
||||
override predicate storeStep(DataFlow::Node element, DataFlow::Node obj, string prop) {
|
||||
override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) {
|
||||
prop = arrayElement() and
|
||||
element = this.(DataFlow::PropWrite).getRhs() and
|
||||
this = obj.(DataFlow::SourceNode).getAPropertyWrite()
|
||||
this = obj.getAPropertyWrite()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,7 +234,7 @@ private module ArrayDataFlow {
|
||||
element = getCallback(0).getParameter(0)
|
||||
}
|
||||
|
||||
override predicate storeStep(DataFlow::Node element, DataFlow::Node obj, string prop) {
|
||||
override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) {
|
||||
this.getMethodName() = "map" and
|
||||
prop = arrayElement() and
|
||||
element = this.getCallback(0).getAReturn() and
|
||||
@@ -209,7 +254,7 @@ private module ArrayDataFlow {
|
||||
private class ArrayCreationStep extends DataFlow::AdditionalFlowStep, DataFlow::Node {
|
||||
ArrayCreationStep() { this instanceof DataFlow::ArrayCreationNode }
|
||||
|
||||
override predicate storeStep(DataFlow::Node element, DataFlow::Node obj, string prop) {
|
||||
override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) {
|
||||
prop = arrayElement() and
|
||||
element = this.(DataFlow::ArrayCreationNode).getAnElement() and
|
||||
obj = this
|
||||
@@ -223,10 +268,10 @@ private module ArrayDataFlow {
|
||||
private class ArraySpliceStep extends DataFlow::AdditionalFlowStep, DataFlow::MethodCallNode {
|
||||
ArraySpliceStep() { this.getMethodName() = "splice" }
|
||||
|
||||
override predicate storeStep(DataFlow::Node element, DataFlow::Node obj, string prop) {
|
||||
override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) {
|
||||
prop = arrayElement() and
|
||||
element = getArgument(2) and
|
||||
obj = this.getReceiver().getALocalSource()
|
||||
this = obj.getAMethodCall()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,4 +305,20 @@ private module ArrayDataFlow {
|
||||
succ = this
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A step for modelling `for of` iteration on arrays.
|
||||
*/
|
||||
private class ForOfStep extends DataFlow::AdditionalFlowStep, DataFlow::ValueNode {
|
||||
ForOfStmt forOf;
|
||||
DataFlow::Node element;
|
||||
|
||||
ForOfStep() { this.asExpr() = forOf.getIterationDomain() }
|
||||
|
||||
override predicate loadStep(DataFlow::Node obj, DataFlow::Node e, string prop) {
|
||||
obj = this and
|
||||
e = DataFlow::lvalueNode(forOf.getLValue()) and
|
||||
prop = arrayElement()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1059,12 +1059,6 @@ class FieldDeclaration extends MemberDeclaration, @field {
|
||||
|
||||
/** Holds if this is a TypeScript field marked as definitely assigned with the `!` operator. */
|
||||
predicate hasDefiniteAssignmentAssertion() { hasDefiniteAssignmentAssertion(this) }
|
||||
|
||||
override predicate isAmbient() {
|
||||
hasDeclareKeyword(this)
|
||||
or
|
||||
getParent().isAmbient()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
278
javascript/ql/src/semmle/javascript/Collections.qll
Normal file
278
javascript/ql/src/semmle/javascript/Collections.qll
Normal file
@@ -0,0 +1,278 @@
|
||||
/**
|
||||
* Provides predicates and classes for working with the standard library collection implementations.
|
||||
* Currently [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) and
|
||||
* [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) are implemented.
|
||||
*/
|
||||
|
||||
import javascript
|
||||
private import semmle.javascript.dataflow.internal.StepSummary
|
||||
private import DataFlow::PseudoProperties
|
||||
|
||||
/**
|
||||
* A pseudo-property used in a data-flow/type-tracking step for collections.
|
||||
*
|
||||
* By extending `TypeTrackingPseudoProperty` the class enables the use of the collection related pseudo-properties in type-tracking predicates.
|
||||
*/
|
||||
private class PseudoProperty extends TypeTrackingPseudoProperty {
|
||||
PseudoProperty() {
|
||||
this = [arrayLikeElement(), "1"] or // the "1" is required for the `ForOfStep`.
|
||||
this = any(CollectionDataFlow::MapSet step).getAPseudoProperty()
|
||||
}
|
||||
|
||||
override PseudoProperty getLoadStoreToProp() {
|
||||
exists(CollectionFlowStep step | step.loadStore(_, _, this, result))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An `AdditionalFlowStep` used to model a data-flow step related to standard library collections.
|
||||
*
|
||||
* The `loadStep`/`storeStep`/`loadStoreStep` methods are overloaded such that the new predicates
|
||||
* `load`/`store`/`loadStore` can be used in the `CollectionsTypeTracking` module.
|
||||
* (Thereby avoiding naming conflicts with a "cousin" `AdditionalFlowStep` implementation.)
|
||||
*/
|
||||
abstract private class CollectionFlowStep extends DataFlow::AdditionalFlowStep {
|
||||
final override predicate step(DataFlow::Node pred, DataFlow::Node succ) { none() }
|
||||
|
||||
final override predicate step(
|
||||
DataFlow::Node p, DataFlow::Node s, DataFlow::FlowLabel pl, DataFlow::FlowLabel sl
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the property `prop` of the object `pred` should be loaded into `succ`.
|
||||
*/
|
||||
predicate load(DataFlow::Node pred, DataFlow::Node succ, PseudoProperty prop) { none() }
|
||||
|
||||
final override predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
this.load(pred, succ, prop)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `pred` should be stored in the object `succ` under the property `prop`.
|
||||
*/
|
||||
predicate store(DataFlow::Node pred, DataFlow::SourceNode succ, PseudoProperty prop) { none() }
|
||||
|
||||
final override predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
|
||||
this.store(pred, succ, prop)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the property `prop` should be copied from the object `pred` to the object `succ`.
|
||||
*/
|
||||
predicate loadStore(DataFlow::Node pred, DataFlow::Node succ, PseudoProperty prop) { none() }
|
||||
|
||||
final override predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
this.loadStore(pred, succ, prop, prop)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the property `loadProp` should be copied from the object `pred` to the property `storeProp` of object `succ`.
|
||||
*/
|
||||
predicate loadStore(
|
||||
DataFlow::Node pred, DataFlow::Node succ, PseudoProperty loadProp, PseudoProperty storeProp
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
final override predicate loadStoreStep(
|
||||
DataFlow::Node pred, DataFlow::Node succ, string loadProp, string storeProp
|
||||
) {
|
||||
this.loadStore(pred, succ, loadProp, storeProp)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides predicates and clases for type-tracking collections.
|
||||
*/
|
||||
module CollectionsTypeTracking {
|
||||
/**
|
||||
* Gets the result from a single step through a collection, from `pred` to `result` summarized by `summary`.
|
||||
*/
|
||||
pragma[inline]
|
||||
DataFlow::SourceNode collectionStep(DataFlow::Node pred, StepSummary summary) {
|
||||
exists(CollectionFlowStep step, PseudoProperty field |
|
||||
summary = LoadStep(field) and
|
||||
step.load(pred, result, field) and
|
||||
not field = mapValueUnknownKey() // prune unknown reads in type-tracking
|
||||
or
|
||||
summary = StoreStep(field) and
|
||||
step.store(pred, result, field)
|
||||
or
|
||||
summary = CopyStep(field) and
|
||||
step.loadStore(pred, result, field)
|
||||
or
|
||||
exists(PseudoProperty toField | summary = LoadStoreStep(field, toField) |
|
||||
step.loadStore(pred, result, field, toField)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the result from a single step through a collection, from `pred` with tracker `t2` to `result` with tracker `t`.
|
||||
*/
|
||||
pragma[inline]
|
||||
DataFlow::SourceNode collectionStep(
|
||||
DataFlow::SourceNode pred, DataFlow::TypeTracker t, DataFlow::TypeTracker t2
|
||||
) {
|
||||
exists(DataFlow::Node mid, StepSummary summary | pred.flowsTo(mid) and t = t2.append(summary) |
|
||||
result = collectionStep(mid, summary)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A module for data-flow steps related standard library collection implementations.
|
||||
*/
|
||||
private module CollectionDataFlow {
|
||||
/**
|
||||
* A step for `Set.add()` method, which adds an element to a Set.
|
||||
*/
|
||||
private class SetAdd extends CollectionFlowStep, DataFlow::MethodCallNode {
|
||||
SetAdd() { this.getMethodName() = "add" }
|
||||
|
||||
override predicate store(DataFlow::Node element, DataFlow::SourceNode obj, PseudoProperty prop) {
|
||||
this = obj.getAMethodCall() and
|
||||
element = this.getArgument(0) and
|
||||
prop = setElement()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A step for the `Set` constructor, which copies any elements from the first argument into the resulting set.
|
||||
*/
|
||||
private class SetConstructor extends CollectionFlowStep, DataFlow::NewNode {
|
||||
SetConstructor() { this = DataFlow::globalVarRef("Set").getAnInstantiation() }
|
||||
|
||||
override predicate loadStore(
|
||||
DataFlow::Node pred, DataFlow::Node succ, PseudoProperty fromProp, PseudoProperty toProp
|
||||
) {
|
||||
pred = this.getArgument(0) and
|
||||
succ = this and
|
||||
fromProp = arrayLikeElement() and
|
||||
toProp = setElement()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A step for a `for of` statement on a Map, Set, or Iterator.
|
||||
* For Sets and iterators the l-value are the elements of the set/iterator.
|
||||
* For Maps the l-value is a tuple containing a key and a value.
|
||||
*/
|
||||
// This is partially duplicated behavior with the `for of` step for Arrays (`ArrayDataFlow::ForOfStep`).
|
||||
// This duplication is required for the type-tracking steps defined in `CollectionsTypeTracking`.
|
||||
private class ForOfStep extends CollectionFlowStep, DataFlow::ValueNode {
|
||||
ForOfStmt forOf;
|
||||
DataFlow::Node element;
|
||||
|
||||
ForOfStep() {
|
||||
this.asExpr() = forOf.getIterationDomain() and
|
||||
element = DataFlow::lvalueNode(forOf.getLValue())
|
||||
}
|
||||
|
||||
override predicate load(DataFlow::Node obj, DataFlow::Node e, PseudoProperty prop) {
|
||||
obj = this and
|
||||
e = element and
|
||||
prop = arrayLikeElement()
|
||||
}
|
||||
|
||||
override predicate loadStore(
|
||||
DataFlow::Node pred, DataFlow::Node succ, PseudoProperty fromProp, PseudoProperty toProp
|
||||
) {
|
||||
pred = this and
|
||||
succ = element and
|
||||
fromProp = mapValueAll() and
|
||||
toProp = "1"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A step for a call to `forEach` on a Set or Map.
|
||||
*/
|
||||
private class SetMapForEach extends CollectionFlowStep, DataFlow::MethodCallNode {
|
||||
SetMapForEach() { this.getMethodName() = "forEach" }
|
||||
|
||||
override predicate load(DataFlow::Node obj, DataFlow::Node element, PseudoProperty prop) {
|
||||
obj = this.getReceiver() and
|
||||
element = this.getCallback(0).getParameter(0) and
|
||||
prop = [setElement(), mapValueAll()]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to the `get` method on a Map.
|
||||
* If the key of the call to `get` has a known string value, then only the value corresponding to that key will be retrieved. (The known string value is encoded as part of the pseudo-property)
|
||||
*/
|
||||
private class MapGet extends CollectionFlowStep, DataFlow::MethodCallNode {
|
||||
MapGet() { this.getMethodName() = "get" }
|
||||
|
||||
override predicate load(DataFlow::Node obj, DataFlow::Node element, PseudoProperty prop) {
|
||||
obj = this.getReceiver() and
|
||||
element = this and
|
||||
// reading the join of known and unknown values
|
||||
(prop = mapValue(this.getArgument(0)) or prop = mapValueUnknownKey())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to the `set` method on a Map.
|
||||
*
|
||||
* If the key of the call to `set` has a known string value,
|
||||
* then the value will be stored into a pseudo-property corresponding to the known string value.
|
||||
* Otherwise the value will be stored into a pseudo-property corresponding to values with unknown keys.
|
||||
* The value will additionally be stored into a pseudo-property corresponding to all values.
|
||||
*/
|
||||
class MapSet extends CollectionFlowStep, DataFlow::MethodCallNode {
|
||||
MapSet() { this.getMethodName() = "set" }
|
||||
|
||||
override predicate store(DataFlow::Node element, DataFlow::SourceNode obj, PseudoProperty prop) {
|
||||
this = obj.getAMethodCall() and
|
||||
element = this.getArgument(1) and
|
||||
prop = getAPseudoProperty()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a pseudo-property used to store an element in a map.
|
||||
* The pseudo-property represents both values where the key is a known string value (which is encoded in the pseudo-property),
|
||||
* and values where the key is unknown.
|
||||
*
|
||||
* Additionally, all elements are stored into the pseudo-property `mapValueAll()`.
|
||||
*
|
||||
* The return-type is `string` as this predicate is used to define which pseudo-properties exist.
|
||||
*/
|
||||
string getAPseudoProperty() { result = [mapValue(this.getArgument(0)), mapValueAll()] }
|
||||
}
|
||||
|
||||
/**
|
||||
* A step for a call to `values` on a Map or a Set.
|
||||
*/
|
||||
private class MapAndSetValues extends CollectionFlowStep, DataFlow::MethodCallNode {
|
||||
MapAndSetValues() { this.getMethodName() = "values" }
|
||||
|
||||
override predicate loadStore(
|
||||
DataFlow::Node pred, DataFlow::Node succ, PseudoProperty fromProp, PseudoProperty toProp
|
||||
) {
|
||||
pred = this.getReceiver() and
|
||||
succ = this and
|
||||
fromProp = [mapValueAll(), setElement()] and
|
||||
toProp = iteratorElement()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A step for a call to `keys` on a Set.
|
||||
*/
|
||||
private class SetKeys extends CollectionFlowStep, DataFlow::MethodCallNode {
|
||||
SetKeys() { this.getMethodName() = "keys" }
|
||||
|
||||
override predicate loadStore(
|
||||
DataFlow::Node pred, DataFlow::Node succ, PseudoProperty fromProp, PseudoProperty toProp
|
||||
) {
|
||||
pred = this.getReceiver() and
|
||||
succ = this and
|
||||
fromProp = setElement() and
|
||||
toProp = iteratorElement()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,11 +79,6 @@ class ImportDeclaration extends Stmt, Import, @importdeclaration {
|
||||
|
||||
/** Holds if this is declared with the `type` keyword, so it only imports types. */
|
||||
predicate isTypeOnly() { hasTypeKeyword(this) }
|
||||
|
||||
override predicate isAmbient() {
|
||||
Stmt.super.isAmbient() or
|
||||
isTypeOnly()
|
||||
}
|
||||
}
|
||||
|
||||
/** A literal path expression appearing in an `import` declaration. */
|
||||
@@ -267,11 +262,6 @@ abstract class ExportDeclaration extends Stmt, @exportdeclaration {
|
||||
|
||||
/** Holds if is declared with the `type` keyword, so only types are exported. */
|
||||
predicate isTypeOnly() { hasTypeKeyword(this) }
|
||||
|
||||
override predicate isAmbient() {
|
||||
Stmt.super.isAmbient() or
|
||||
isTypeOnly()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -422,11 +412,6 @@ class ExportNamedDeclaration extends ExportDeclaration, @exportnameddeclaration
|
||||
|
||||
/** Gets an export specifier of this declaration. */
|
||||
ExportSpecifier getASpecifier() { result = getSpecifier(_) }
|
||||
|
||||
override predicate isAmbient() {
|
||||
// An export such as `export declare function f()` should be seen as ambient.
|
||||
hasDeclareKeyword(getOperand()) or getParent().isAmbient()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -397,8 +397,6 @@ class Function extends @function, Parameterized, TypeParameterized, StmtContaine
|
||||
*/
|
||||
predicate isAbstract() { exists(MethodDeclaration md | this = md.getBody() | md.isAbstract()) }
|
||||
|
||||
override predicate isAmbient() { getParent().isAmbient() or not hasBody() }
|
||||
|
||||
/**
|
||||
* Holds if this function cannot be invoked using `new` because it
|
||||
* is of the given `kind`.
|
||||
|
||||
@@ -176,7 +176,7 @@ module PromiseTypeTracking {
|
||||
summary = StoreStep(field) and
|
||||
step.store(pred, result, field)
|
||||
or
|
||||
summary = LoadStoreStep(field) and
|
||||
summary = CopyStep(field) and
|
||||
step.loadStore(pred, result, field)
|
||||
)
|
||||
}
|
||||
@@ -232,9 +232,9 @@ abstract private class PromiseFlowStep extends DataFlow::AdditionalFlowStep {
|
||||
/**
|
||||
* Holds if `pred` should be stored in the object `succ` under the property `prop`.
|
||||
*/
|
||||
predicate store(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() }
|
||||
predicate store(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { none() }
|
||||
|
||||
final override predicate storeStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
final override predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
|
||||
this.store(pred, succ, prop)
|
||||
}
|
||||
|
||||
@@ -246,6 +246,12 @@ abstract private class PromiseFlowStep extends DataFlow::AdditionalFlowStep {
|
||||
final override predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
this.loadStore(pred, succ, prop)
|
||||
}
|
||||
|
||||
final override predicate loadStoreStep(
|
||||
DataFlow::Node pred, DataFlow::Node succ, string loadProp, string storeProp
|
||||
) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -267,7 +273,7 @@ private module PromiseFlow {
|
||||
|
||||
PromiseDefitionStep() { this = promise }
|
||||
|
||||
override predicate store(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
override predicate store(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
|
||||
prop = valueProp() and
|
||||
pred = promise.getResolveParameter().getACall().getArgument(0) and
|
||||
succ = this
|
||||
@@ -296,7 +302,7 @@ private module PromiseFlow {
|
||||
|
||||
CreationStep() { this = promise }
|
||||
|
||||
override predicate store(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
override predicate store(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
|
||||
prop = valueProp() and
|
||||
pred = promise.getValue() and
|
||||
succ = this
|
||||
@@ -362,7 +368,7 @@ private module PromiseFlow {
|
||||
succ = this
|
||||
}
|
||||
|
||||
override predicate store(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
override predicate store(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
|
||||
prop = valueProp() and
|
||||
pred = getCallback([0 .. 1]).getAReturn() and
|
||||
succ = this
|
||||
@@ -396,7 +402,7 @@ private module PromiseFlow {
|
||||
succ = this
|
||||
}
|
||||
|
||||
override predicate store(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
override predicate store(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
|
||||
prop = errorProp() and
|
||||
pred = getCallback(0).getExceptionalReturn() and
|
||||
succ = this
|
||||
@@ -424,7 +430,7 @@ private module PromiseFlow {
|
||||
succ = this
|
||||
}
|
||||
|
||||
override predicate store(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
override predicate store(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
|
||||
prop = errorProp() and
|
||||
pred = getCallback(0).getExceptionalReturn() and
|
||||
succ = this
|
||||
|
||||
@@ -54,8 +54,6 @@ class Stmt extends @stmt, ExprOrStmt, Documentable {
|
||||
getContainer().(Expr).getEnclosingStmt().nestedIn(outer)
|
||||
}
|
||||
|
||||
override predicate isAmbient() { hasDeclareKeyword(this) or getParent().isAmbient() }
|
||||
|
||||
/**
|
||||
* Gets the `try` statement with a catch block containing this statement without
|
||||
* crossing function boundaries or other `try ` statements with catch blocks.
|
||||
@@ -931,8 +929,6 @@ class DebuggerStmt extends @debuggerstmt, Stmt {
|
||||
*/
|
||||
class FunctionDeclStmt extends @functiondeclstmt, Stmt, Function {
|
||||
override Stmt getEnclosingStmt() { result = this }
|
||||
|
||||
override predicate isAmbient() { Function.super.isAmbient() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -155,8 +155,6 @@ class ExternalModuleDeclaration extends Stmt, StmtContainer, @externalmoduledecl
|
||||
int getNumStmt() { result = count(getAStmt()) }
|
||||
|
||||
override StmtContainer getEnclosingContainer() { result = this.getContainer() }
|
||||
|
||||
override predicate isAmbient() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -176,8 +174,6 @@ class GlobalAugmentationDeclaration extends Stmt, StmtContainer, @globalaugmenta
|
||||
int getNumStmt() { result = count(getAStmt()) }
|
||||
|
||||
override StmtContainer getEnclosingContainer() { result = this.getContainer() }
|
||||
|
||||
override predicate isAmbient() { any() }
|
||||
}
|
||||
|
||||
/** A TypeScript "import-equals" declaration. */
|
||||
@@ -237,8 +233,6 @@ class ExportAsNamespaceDeclaration extends Stmt, @exportasnamespacedeclaration {
|
||||
* Gets the `X` in `export as namespace X`.
|
||||
*/
|
||||
Identifier getIdentifier() { result = getChildExpr(0) }
|
||||
|
||||
override predicate isAmbient() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -259,8 +253,6 @@ class TypeAliasDeclaration extends @typealiasdeclaration, TypeParameterized, Stm
|
||||
|
||||
override string describe() { result = "type alias " + getName() }
|
||||
|
||||
override predicate isAmbient() { any() }
|
||||
|
||||
/**
|
||||
* Gets the canonical name of the type being defined.
|
||||
*/
|
||||
@@ -286,8 +278,6 @@ class InterfaceDeclaration extends Stmt, InterfaceDefinition, @interfacedeclarat
|
||||
|
||||
override StmtContainer getContainer() { result = Stmt.super.getContainer() }
|
||||
|
||||
override predicate isAmbient() { any() }
|
||||
|
||||
override string describe() { result = "interface " + getName() }
|
||||
|
||||
/**
|
||||
@@ -533,8 +523,6 @@ class LocalNamespaceName extends @local_namespace_name, LexicalName {
|
||||
class TypeExpr extends ExprOrType, @typeexpr, TypeAnnotation {
|
||||
override string toString() { typeexprs(this, _, _, _, result) }
|
||||
|
||||
override predicate isAmbient() { any() }
|
||||
|
||||
/**
|
||||
* Gets the static type expressed by this type annotation.
|
||||
*
|
||||
@@ -1410,8 +1398,6 @@ class EnumDeclaration extends NamespaceDefinition, @enumdeclaration, AST::ValueN
|
||||
/** Holds if this enumeration is declared with the `const` keyword. */
|
||||
predicate isConst() { isConstEnum(this) }
|
||||
|
||||
override predicate isAmbient() { hasDeclareKeyword(this) or getParent().isAmbient() }
|
||||
|
||||
override ControlFlowNode getFirstControlFlowNode() { result = getIdentifier() }
|
||||
}
|
||||
|
||||
|
||||
@@ -244,8 +244,11 @@ abstract class Configuration extends string {
|
||||
* EXPERIMENTAL. This API may change in the future.
|
||||
*
|
||||
* Holds if `pred` should be stored in the object `succ` under the property `prop`.
|
||||
* The object `succ` must be a `DataFlow::SourceNode` for the object wherein the value is stored.
|
||||
*/
|
||||
predicate isAdditionalStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() }
|
||||
predicate isAdditionalStoreStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL. This API may change in the future.
|
||||
@@ -540,9 +543,10 @@ abstract class AdditionalFlowStep extends DataFlow::Node {
|
||||
* EXPERIMENTAL. This API may change in the future.
|
||||
*
|
||||
* Holds if `pred` should be stored in the object `succ` under the property `prop`.
|
||||
* The object `succ` must be a `DataFlow::SourceNode` for the object wherein the value is stored.
|
||||
*/
|
||||
cached
|
||||
predicate storeStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() }
|
||||
predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { none() }
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL. This API may change in the future.
|
||||
@@ -574,6 +578,71 @@ abstract class AdditionalFlowStep extends DataFlow::Node {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A collection of pseudo-properties that are used in multiple files.
|
||||
*
|
||||
* A pseudo-property represents the location where some value is stored in an object.
|
||||
*
|
||||
* For use with load/store steps in `DataFlow::AdditionalFlowStep` and TypeTracking.
|
||||
*/
|
||||
module PseudoProperties {
|
||||
bindingset[s]
|
||||
private string pseudoProperty(string s) { result = "$" + s + "$" }
|
||||
|
||||
bindingset[s, v]
|
||||
private string pseudoProperty(string s, string v) { result = "$" + s + "|" + v + "$" }
|
||||
|
||||
/**
|
||||
* Gets a pseudo-property for the location of elements in a `Set`
|
||||
*/
|
||||
string setElement() { result = pseudoProperty("setElement") }
|
||||
|
||||
/**
|
||||
* Gets a pseudo-property for the location of elements in a JavaScript iterator.
|
||||
*/
|
||||
string iteratorElement() { result = pseudoProperty("iteratorElement") }
|
||||
|
||||
/**
|
||||
* Gets a pseudo-property for the location of elements in an `Array`.
|
||||
*/
|
||||
string arrayElement() { result = pseudoProperty("arrayElement") }
|
||||
|
||||
/**
|
||||
* Gets a pseudo-property for the location of elements in some array-like object. (Set, Array, or Iterator).
|
||||
*/
|
||||
string arrayLikeElement() { result = [setElement(), iteratorElement(), arrayElement()] }
|
||||
|
||||
/**
|
||||
* Gets a pseudo-property for the location of map values, where the key is unknown.
|
||||
*/
|
||||
string mapValueUnknownKey() { result = pseudoProperty("mapValueUnknownKey") }
|
||||
|
||||
/**
|
||||
* Gets a pseudo-property for the location of all the values in a map.
|
||||
*/
|
||||
string mapValueAll() { result = pseudoProperty("allMapValues") }
|
||||
|
||||
/**
|
||||
* Gets a pseudo-property for the location of a map value where the key is `key`.
|
||||
* The string value of the `key` is encoded in the result, and there is only a result if the string value of `key` is known.
|
||||
*/
|
||||
pragma[inline]
|
||||
string mapValueKnownKey(DataFlow::Node key) {
|
||||
result = pseudoProperty("mapValue", any(string s | key.mayHaveStringValue(s)))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a pseudo-property for the location of a map value where the key is `key`.
|
||||
*/
|
||||
pragma[inline]
|
||||
string mapValue(DataFlow::Node key) {
|
||||
result = mapValueKnownKey(key)
|
||||
or
|
||||
not exists(mapValueKnownKey(key)) and
|
||||
result = mapValueUnknownKey()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow node that should be considered a source for some specific configuration,
|
||||
* in addition to any other sources that configuration may recognize.
|
||||
|
||||
@@ -620,6 +620,16 @@ class ArrayCreationNode extends DataFlow::ValueNode, DataFlow::SourceNode {
|
||||
result = this.(ArrayLiteralNode).getSize() or
|
||||
result = this.(ArrayConstructorInvokeNode).getSize()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a data flow node corresponding to an array of values being passed as
|
||||
* individual arguments to this array creation.
|
||||
*/
|
||||
DataFlow::Node getASpreadArgument() {
|
||||
exists(SpreadElement arg | arg = getAnElement().getEnclosingExpr() |
|
||||
result = DataFlow::valueNode(arg.getOperand())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -39,11 +39,7 @@ class SourceNode extends DataFlow::Node {
|
||||
* Holds if this node flows into `sink` in zero or more local (that is,
|
||||
* intra-procedural) steps.
|
||||
*/
|
||||
cached
|
||||
predicate flowsTo(DataFlow::Node sink) {
|
||||
sink = this or
|
||||
flowsTo(sink.getAPredecessor())
|
||||
}
|
||||
predicate flowsTo(DataFlow::Node sink) { hasLocalSource(sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if this node flows into `sink` in zero or more local (that is,
|
||||
@@ -195,6 +191,24 @@ class SourceNode extends DataFlow::Node {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `source` is a `SourceNode` that can reach `sink` via local flow steps.
|
||||
*
|
||||
* The slightly backwards parametering ordering is to force correct indexing.
|
||||
*/
|
||||
cached
|
||||
private predicate hasLocalSource(DataFlow::Node sink, DataFlow::Node source) {
|
||||
// Declaring `source` to be a `SourceNode` currently causes a redundant check in the
|
||||
// recursive case, so instead we check it explicitly here.
|
||||
source = sink and
|
||||
source instanceof DataFlow::SourceNode
|
||||
or
|
||||
exists(DataFlow::Node mid |
|
||||
hasLocalSource(mid, source) and
|
||||
DataFlow::localFlowStep(mid, sink)
|
||||
)
|
||||
}
|
||||
|
||||
module SourceNode {
|
||||
/**
|
||||
* A data flow node that should be considered a source node.
|
||||
|
||||
@@ -603,15 +603,10 @@ module TaintTracking {
|
||||
* 3) A `URLSearchParams` object (either `url.searchParams` or `new URLSearchParams(input)`) has a tainted value,
|
||||
* which can be accessed using a `get` or `getAll` call. (See getableUrlPseudoProperty())
|
||||
*/
|
||||
override predicate storeStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
override predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
|
||||
succ = this and
|
||||
(
|
||||
(
|
||||
prop = "searchParams" or
|
||||
prop = "hash" or
|
||||
prop = "search" or
|
||||
prop = hiddenUrlPseudoProperty()
|
||||
) and
|
||||
prop = ["searchParams", "hash", "search", hiddenUrlPseudoProperty()] and
|
||||
exists(DataFlow::NewNode newUrl | succ = newUrl |
|
||||
newUrl = DataFlow::globalVarRef("URL").getAnInstantiation() and
|
||||
pred = newUrl.getArgument(0)
|
||||
|
||||
@@ -53,7 +53,11 @@ class TypeTracker extends TTypeTracker {
|
||||
TypeTracker append(StepSummary step) {
|
||||
step = LevelStep() and result = this
|
||||
or
|
||||
step = LoadStoreStep(prop) and result = this
|
||||
exists(string toProp | step = LoadStoreStep(prop, toProp) |
|
||||
result = MkTypeTracker(hasCall, toProp)
|
||||
)
|
||||
or
|
||||
step = CopyStep(prop) and result = this
|
||||
or
|
||||
step = CallStep() and result = MkTypeTracker(true, prop)
|
||||
or
|
||||
@@ -213,7 +217,11 @@ class TypeBackTracker extends TTypeBackTracker {
|
||||
TypeBackTracker prepend(StepSummary step) {
|
||||
step = LevelStep() and result = this
|
||||
or
|
||||
step = LoadStoreStep(prop) and result = this
|
||||
exists(string fromProp | step = LoadStoreStep(fromProp, prop) |
|
||||
result = MkTypeBackTracker(hasReturn, fromProp)
|
||||
)
|
||||
or
|
||||
step = CopyStep(prop) and result = this
|
||||
or
|
||||
step = CallStep() and hasReturn = false and result = this
|
||||
or
|
||||
|
||||
@@ -24,6 +24,11 @@ class OptionalPropertyName extends string {
|
||||
abstract class TypeTrackingPseudoProperty extends string {
|
||||
bindingset[this]
|
||||
TypeTrackingPseudoProperty() { any() }
|
||||
|
||||
/**
|
||||
* Gets a property name that `this` can be copied to in a `LoadStoreStep(this, result)`.
|
||||
*/
|
||||
string getLoadStoreToProp() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -35,7 +40,10 @@ newtype TStepSummary =
|
||||
ReturnStep() or
|
||||
StoreStep(PropertyName prop) or
|
||||
LoadStep(PropertyName prop) or
|
||||
LoadStoreStep(PropertyName prop)
|
||||
CopyStep(PropertyName prop) or
|
||||
LoadStoreStep(PropertyName fromProp, PropertyName toProp) {
|
||||
exists(TypeTrackingPseudoProperty prop | fromProp = prop and toProp = prop.getLoadStoreToProp())
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: Use `TypeTracker` or `TypeBackTracker` instead.
|
||||
@@ -55,7 +63,11 @@ class StepSummary extends TStepSummary {
|
||||
or
|
||||
exists(string prop | this = LoadStep(prop) | result = "load " + prop)
|
||||
or
|
||||
exists(string prop | this = LoadStoreStep(prop) | result = "in " + prop)
|
||||
exists(string prop | this = CopyStep(prop) | result = "copy " + prop)
|
||||
or
|
||||
exists(string fromProp, string toProp | this = LoadStoreStep(fromProp, toProp) |
|
||||
result = "load " + fromProp + " and store to " + toProp
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -459,7 +459,7 @@ module NodeJSLib {
|
||||
private class NodeJSFileSystemAccess extends FileSystemAccess, DataFlow::CallNode {
|
||||
string methodName;
|
||||
|
||||
NodeJSFileSystemAccess() { this = fsModuleMember(methodName).getACall() }
|
||||
NodeJSFileSystemAccess() { this = maybePromisified(fsModuleMember(methodName)).getACall() }
|
||||
|
||||
/**
|
||||
* Gets the name of the called method.
|
||||
@@ -586,6 +586,19 @@ module NodeJSLib {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a possibly promisified (using `util.promisify`) version of the input `callback`.
|
||||
*/
|
||||
private DataFlow::SourceNode maybePromisified(DataFlow::SourceNode callback) {
|
||||
result = callback
|
||||
or
|
||||
exists(DataFlow::CallNode promisify |
|
||||
promisify = DataFlow::moduleMember("util", "promisify").getACall()
|
||||
|
|
||||
result = promisify and promisify.getArgument(0).getALocalSource() = callback
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to a method from module `child_process`.
|
||||
*/
|
||||
@@ -593,7 +606,7 @@ module NodeJSLib {
|
||||
string methodName;
|
||||
|
||||
ChildProcessMethodCall() {
|
||||
this = DataFlow::moduleMember("child_process", methodName).getACall()
|
||||
this = maybePromisified(DataFlow::moduleMember("child_process", methodName)).getACall()
|
||||
}
|
||||
|
||||
private DataFlow::Node getACommandArgument(boolean shell) {
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:15:27:15:27 | e |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:16:23:16:23 | e |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:20:8:20:16 | arr.pop() |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:52:10:52:10 | x |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:56:10:56:10 | x |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:60:10:60:10 | x |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:66:10:66:10 | x |
|
||||
| arrays.js:18:22:18:29 | "source" | arrays.js:18:50:18:50 | e |
|
||||
| arrays.js:22:15:22:22 | "source" | arrays.js:23:8:23:17 | arr2.pop() |
|
||||
| arrays.js:25:15:25:22 | "source" | arrays.js:26:8:26:17 | arr3.pop() |
|
||||
|
||||
@@ -47,4 +47,22 @@
|
||||
});
|
||||
|
||||
sink(arr[0]); // OK - tuple like usage.
|
||||
|
||||
for (const x of arr) {
|
||||
sink(x); // NOT OK
|
||||
}
|
||||
|
||||
for (const x of Array.from(arr)) {
|
||||
sink(x); // NOT OK
|
||||
}
|
||||
|
||||
for (const x of [...arr]) {
|
||||
sink(x); // NOT OK
|
||||
}
|
||||
|
||||
var arr7 = [];
|
||||
arr7.push(...arr);
|
||||
for (const x of arr7) {
|
||||
sink(x); // NOT OK
|
||||
}
|
||||
});
|
||||
|
||||
@@ -222,135 +222,135 @@ flow
|
||||
exclusiveTaintFlow
|
||||
| interflow.js:3:18:3:25 | "source" | interflow.js:18:10:18:14 | error |
|
||||
typetrack
|
||||
| flow.js:20:2:20:43 | Promise ... ink(x)) | flow.js:20:36:20:42 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:20:2:20:43 | Promise ... ink(x)) | flow.js:20:36:20:42 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:20:2:20:43 | Promise ... ink(x)) | flow.js:20:36:20:42 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:20:31:20:31 | x | flow.js:20:2:20:24 | Promise ... source) | load $PromiseResolveField$ |
|
||||
| flow.js:22:2:22:56 | Promise ... ink(y)) | flow.js:22:36:22:41 | foo(x) | in $PromiseResolveField$ |
|
||||
| flow.js:22:2:22:56 | Promise ... ink(y)) | flow.js:22:36:22:41 | foo(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:22:2:22:56 | Promise ... ink(y)) | flow.js:22:36:22:41 | foo(x) | store $PromiseResolveField$ |
|
||||
| flow.js:22:2:22:56 | Promise ... ink(y)) | flow.js:22:49:22:55 | sink(y) | in $PromiseResolveField$ |
|
||||
| flow.js:22:2:22:56 | Promise ... ink(y)) | flow.js:22:49:22:55 | sink(y) | copy $PromiseResolveField$ |
|
||||
| flow.js:22:2:22:56 | Promise ... ink(y)) | flow.js:22:49:22:55 | sink(y) | store $PromiseResolveField$ |
|
||||
| flow.js:22:31:22:31 | x | flow.js:22:2:22:24 | Promise ... source) | load $PromiseResolveField$ |
|
||||
| flow.js:24:2:24:68 | new Pro ... ink(x)) | flow.js:24:61:24:67 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:24:2:24:68 | new Pro ... ink(x)) | flow.js:24:61:24:67 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:24:2:24:68 | new Pro ... ink(x)) | flow.js:24:61:24:67 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:24:56:24:56 | x | flow.js:24:2:24:49 | new Pro ... ource)) | load $PromiseResolveField$ |
|
||||
| flow.js:26:2:26:81 | new Pro ... ink(y)) | flow.js:26:61:26:66 | foo(x) | in $PromiseResolveField$ |
|
||||
| flow.js:26:2:26:81 | new Pro ... ink(y)) | flow.js:26:61:26:66 | foo(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:26:2:26:81 | new Pro ... ink(y)) | flow.js:26:61:26:66 | foo(x) | store $PromiseResolveField$ |
|
||||
| flow.js:26:2:26:81 | new Pro ... ink(y)) | flow.js:26:74:26:80 | sink(y) | in $PromiseResolveField$ |
|
||||
| flow.js:26:2:26:81 | new Pro ... ink(y)) | flow.js:26:74:26:80 | sink(y) | copy $PromiseResolveField$ |
|
||||
| flow.js:26:2:26:81 | new Pro ... ink(y)) | flow.js:26:74:26:80 | sink(y) | store $PromiseResolveField$ |
|
||||
| flow.js:26:56:26:56 | x | flow.js:26:2:26:49 | new Pro ... ource)) | load $PromiseResolveField$ |
|
||||
| flow.js:28:2:28:60 | Promise ... ink(z)) | flow.js:28:53:28:59 | sink(z) | in $PromiseResolveField$ |
|
||||
| flow.js:28:2:28:60 | Promise ... ink(z)) | flow.js:28:53:28:59 | sink(z) | copy $PromiseResolveField$ |
|
||||
| flow.js:28:2:28:60 | Promise ... ink(z)) | flow.js:28:53:28:59 | sink(z) | store $PromiseResolveField$ |
|
||||
| flow.js:28:30:28:30 | x | flow.js:28:2:28:23 | Promise ... ("foo") | load $PromiseResolveField$ |
|
||||
| flow.js:28:48:28:48 | z | flow.js:28:2:28:41 | Promise ... source) | load $PromiseResolveField$ |
|
||||
| flow.js:30:2:30:60 | Promise ... ink(z)) | flow.js:30:53:30:59 | sink(z) | in $PromiseResolveField$ |
|
||||
| flow.js:30:2:30:60 | Promise ... ink(z)) | flow.js:30:53:30:59 | sink(z) | copy $PromiseResolveField$ |
|
||||
| flow.js:30:2:30:60 | Promise ... ink(z)) | flow.js:30:53:30:59 | sink(z) | store $PromiseResolveField$ |
|
||||
| flow.js:30:31:30:31 | x | flow.js:30:2:30:24 | Promise ... source) | load $PromiseResolveField$ |
|
||||
| flow.js:30:48:30:48 | z | flow.js:30:2:30:41 | Promise ... "foo") | load $PromiseResolveField$ |
|
||||
| flow.js:32:2:32:69 | new Pro ... ink(x)) | flow.js:32:2:32:49 | new Pro ... ource)) | in $PromiseResolveField$ |
|
||||
| flow.js:32:2:32:69 | new Pro ... ink(x)) | flow.js:32:62:32:68 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:32:2:32:69 | new Pro ... ink(x)) | flow.js:32:2:32:49 | new Pro ... ource)) | copy $PromiseResolveField$ |
|
||||
| flow.js:32:2:32:69 | new Pro ... ink(x)) | flow.js:32:62:32:68 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:32:2:32:69 | new Pro ... ink(x)) | flow.js:32:62:32:68 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:34:2:34:41 | Promise ... => { }) | flow.js:34:2:34:24 | Promise ... source) | in $PromiseResolveField$ |
|
||||
| flow.js:34:2:34:60 | Promise ... ink(a)) | flow.js:34:53:34:59 | sink(a) | in $PromiseResolveField$ |
|
||||
| flow.js:34:2:34:41 | Promise ... => { }) | flow.js:34:2:34:24 | Promise ... source) | copy $PromiseResolveField$ |
|
||||
| flow.js:34:2:34:60 | Promise ... ink(a)) | flow.js:34:53:34:59 | sink(a) | copy $PromiseResolveField$ |
|
||||
| flow.js:34:2:34:60 | Promise ... ink(a)) | flow.js:34:53:34:59 | sink(a) | store $PromiseResolveField$ |
|
||||
| flow.js:34:48:34:48 | a | flow.js:34:2:34:41 | Promise ... => { }) | load $PromiseResolveField$ |
|
||||
| flow.js:37:11:37:29 | p5.catch(() => { }) | flow.js:36:11:36:33 | Promise ... source) | in $PromiseResolveField$ |
|
||||
| flow.js:38:11:38:31 | p6.then ... ink(a)) | flow.js:38:24:38:30 | sink(a) | in $PromiseResolveField$ |
|
||||
| flow.js:37:11:37:29 | p5.catch(() => { }) | flow.js:36:11:36:33 | Promise ... source) | copy $PromiseResolveField$ |
|
||||
| flow.js:38:11:38:31 | p6.then ... ink(a)) | flow.js:38:24:38:30 | sink(a) | copy $PromiseResolveField$ |
|
||||
| flow.js:38:11:38:31 | p6.then ... ink(a)) | flow.js:38:24:38:30 | sink(a) | store $PromiseResolveField$ |
|
||||
| flow.js:40:2:40:85 | new Pro ... ink(x)) | flow.js:40:2:40:65 | new Pro ... => { }) | in $PromiseResolveField$ |
|
||||
| flow.js:40:2:40:85 | new Pro ... ink(x)) | flow.js:40:78:40:84 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:40:2:40:85 | new Pro ... ink(x)) | flow.js:40:2:40:65 | new Pro ... => { }) | copy $PromiseResolveField$ |
|
||||
| flow.js:40:2:40:85 | new Pro ... ink(x)) | flow.js:40:78:40:84 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:40:2:40:85 | new Pro ... ink(x)) | flow.js:40:78:40:84 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:42:2:42:96 | new Pro ... ink(x)) | flow.js:42:2:42:76 | new Pro ... => { }) | in $PromiseResolveField$ |
|
||||
| flow.js:42:2:42:96 | new Pro ... ink(x)) | flow.js:42:89:42:95 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:42:2:42:96 | new Pro ... ink(x)) | flow.js:42:2:42:76 | new Pro ... => { }) | copy $PromiseResolveField$ |
|
||||
| flow.js:42:2:42:96 | new Pro ... ink(x)) | flow.js:42:89:42:95 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:42:2:42:96 | new Pro ... ink(x)) | flow.js:42:89:42:95 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:44:2:44:41 | Promise ... => { }) | flow.js:44:2:44:24 | Promise ... source) | in $PromiseResolveField$ |
|
||||
| flow.js:44:2:44:58 | Promise ... => { }) | flow.js:44:2:44:41 | Promise ... => { }) | in $PromiseResolveField$ |
|
||||
| flow.js:44:2:44:75 | Promise ... => { }) | flow.js:44:2:44:58 | Promise ... => { }) | in $PromiseResolveField$ |
|
||||
| flow.js:44:2:44:94 | Promise ... ink(a)) | flow.js:44:87:44:93 | sink(a) | in $PromiseResolveField$ |
|
||||
| flow.js:44:2:44:41 | Promise ... => { }) | flow.js:44:2:44:24 | Promise ... source) | copy $PromiseResolveField$ |
|
||||
| flow.js:44:2:44:58 | Promise ... => { }) | flow.js:44:2:44:41 | Promise ... => { }) | copy $PromiseResolveField$ |
|
||||
| flow.js:44:2:44:75 | Promise ... => { }) | flow.js:44:2:44:58 | Promise ... => { }) | copy $PromiseResolveField$ |
|
||||
| flow.js:44:2:44:94 | Promise ... ink(a)) | flow.js:44:87:44:93 | sink(a) | copy $PromiseResolveField$ |
|
||||
| flow.js:44:2:44:94 | Promise ... ink(a)) | flow.js:44:87:44:93 | sink(a) | store $PromiseResolveField$ |
|
||||
| flow.js:44:82:44:82 | a | flow.js:44:2:44:75 | Promise ... => { }) | load $PromiseResolveField$ |
|
||||
| flow.js:46:2:46:43 | Promise ... => { }) | flow.js:46:2:46:24 | Promise ... source) | in $PromiseResolveField$ |
|
||||
| flow.js:46:2:46:62 | Promise ... ink(a)) | flow.js:46:55:46:61 | sink(a) | in $PromiseResolveField$ |
|
||||
| flow.js:46:2:46:43 | Promise ... => { }) | flow.js:46:2:46:24 | Promise ... source) | copy $PromiseResolveField$ |
|
||||
| flow.js:46:2:46:62 | Promise ... ink(a)) | flow.js:46:55:46:61 | sink(a) | copy $PromiseResolveField$ |
|
||||
| flow.js:46:2:46:62 | Promise ... ink(a)) | flow.js:46:55:46:61 | sink(a) | store $PromiseResolveField$ |
|
||||
| flow.js:46:50:46:50 | a | flow.js:46:2:46:43 | Promise ... => { }) | load $PromiseResolveField$ |
|
||||
| flow.js:48:2:48:56 | new Pro ... ink(x)) | flow.js:48:2:48:36 | new Pro ... urce }) | in $PromiseResolveField$ |
|
||||
| flow.js:48:2:48:56 | new Pro ... ink(x)) | flow.js:48:49:48:55 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:48:2:48:56 | new Pro ... ink(x)) | flow.js:48:2:48:36 | new Pro ... urce }) | copy $PromiseResolveField$ |
|
||||
| flow.js:48:2:48:56 | new Pro ... ink(x)) | flow.js:48:49:48:55 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:48:2:48:56 | new Pro ... ink(x)) | flow.js:48:49:48:55 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:53:2:53:41 | createP ... ink(v)) | flow.js:53:34:53:40 | sink(v) | in $PromiseResolveField$ |
|
||||
| flow.js:53:2:53:41 | createP ... ink(v)) | flow.js:53:34:53:40 | sink(v) | copy $PromiseResolveField$ |
|
||||
| flow.js:53:2:53:41 | createP ... ink(v)) | flow.js:53:34:53:40 | sink(v) | store $PromiseResolveField$ |
|
||||
| flow.js:53:29:53:29 | v | flow.js:53:2:53:22 | createP ... source) | load $PromiseResolveField$ |
|
||||
| flow.js:58:2:58:26 | p10.cat ... ink(x)) | flow.js:57:12:57:31 | p9.finally(() => {}) | in $PromiseResolveField$ |
|
||||
| flow.js:58:2:58:26 | p10.cat ... ink(x)) | flow.js:58:19:58:25 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:58:2:58:26 | p10.cat ... ink(x)) | flow.js:57:12:57:31 | p9.finally(() => {}) | copy $PromiseResolveField$ |
|
||||
| flow.js:58:2:58:26 | p10.cat ... ink(x)) | flow.js:58:19:58:25 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:58:2:58:26 | p10.cat ... ink(x)) | flow.js:58:19:58:25 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:62:2:62:24 | p12.cat ... ink(x)) | flow.js:61:12:61:29 | p11.then(() => {}) | in $PromiseResolveField$ |
|
||||
| flow.js:62:2:62:24 | p12.cat ... ink(x)) | flow.js:62:17:62:23 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:62:2:62:24 | p12.cat ... ink(x)) | flow.js:61:12:61:29 | p11.then(() => {}) | copy $PromiseResolveField$ |
|
||||
| flow.js:62:2:62:24 | p12.cat ... ink(x)) | flow.js:62:17:62:23 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:62:2:62:24 | p12.cat ... ink(x)) | flow.js:62:17:62:23 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:65:3:65:56 | await n ... ource)) | flow.js:65:9:65:56 | new Pro ... ource)) | load $PromiseResolveField$ |
|
||||
| flow.js:76:2:76:52 | chained ... ink(e)) | flow.js:76:2:76:32 | chained ... => {}) | in $PromiseResolveField$ |
|
||||
| flow.js:76:2:76:52 | chained ... ink(e)) | flow.js:76:45:76:51 | sink(e) | in $PromiseResolveField$ |
|
||||
| flow.js:76:2:76:52 | chained ... ink(e)) | flow.js:76:2:76:32 | chained ... => {}) | copy $PromiseResolveField$ |
|
||||
| flow.js:76:2:76:52 | chained ... ink(e)) | flow.js:76:45:76:51 | sink(e) | copy $PromiseResolveField$ |
|
||||
| flow.js:76:2:76:52 | chained ... ink(e)) | flow.js:76:45:76:51 | sink(e) | store $PromiseResolveField$ |
|
||||
| flow.js:79:3:79:22 | p.then(x => sink(x)) | flow.js:79:15:79:21 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:79:3:79:22 | p.then(x => sink(x)) | flow.js:79:15:79:21 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:79:3:79:22 | p.then(x => sink(x)) | flow.js:79:15:79:21 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:84:3:84:23 | p.catch ... ink(e)) | flow.js:83:32:83:32 | p | in $PromiseResolveField$ |
|
||||
| flow.js:84:3:84:23 | p.catch ... ink(e)) | flow.js:84:16:84:22 | sink(e) | in $PromiseResolveField$ |
|
||||
| flow.js:84:3:84:23 | p.catch ... ink(e)) | flow.js:83:32:83:32 | p | copy $PromiseResolveField$ |
|
||||
| flow.js:84:3:84:23 | p.catch ... ink(e)) | flow.js:84:16:84:22 | sink(e) | copy $PromiseResolveField$ |
|
||||
| flow.js:84:3:84:23 | p.catch ... ink(e)) | flow.js:84:16:84:22 | sink(e) | store $PromiseResolveField$ |
|
||||
| flow.js:89:3:89:47 | ("foo", ... ink(e)) | flow.js:89:3:89:27 | ("foo", ... => {}) | in $PromiseResolveField$ |
|
||||
| flow.js:89:3:89:47 | ("foo", ... ink(e)) | flow.js:89:40:89:46 | sink(e) | in $PromiseResolveField$ |
|
||||
| flow.js:89:3:89:47 | ("foo", ... ink(e)) | flow.js:89:3:89:27 | ("foo", ... => {}) | copy $PromiseResolveField$ |
|
||||
| flow.js:89:3:89:47 | ("foo", ... ink(e)) | flow.js:89:40:89:46 | sink(e) | copy $PromiseResolveField$ |
|
||||
| flow.js:89:3:89:47 | ("foo", ... ink(e)) | flow.js:89:40:89:46 | sink(e) | store $PromiseResolveField$ |
|
||||
| flow.js:103:2:103:76 | new Pro ... ource}) | flow.js:103:2:103:48 | new Pro ... "BLA")) | in $PromiseResolveField$ |
|
||||
| flow.js:103:2:103:95 | new Pro ... ink(x)) | flow.js:103:88:103:94 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:103:2:103:76 | new Pro ... ource}) | flow.js:103:2:103:48 | new Pro ... "BLA")) | copy $PromiseResolveField$ |
|
||||
| flow.js:103:2:103:95 | new Pro ... ink(x)) | flow.js:103:88:103:94 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:103:2:103:95 | new Pro ... ink(x)) | flow.js:103:88:103:94 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:103:83:103:83 | x | flow.js:103:2:103:76 | new Pro ... ource}) | load $PromiseResolveField$ |
|
||||
| flow.js:105:2:105:77 | new Pro ... ource}) | flow.js:105:2:105:48 | new Pro ... "BLA")) | in $PromiseResolveField$ |
|
||||
| flow.js:105:2:105:97 | new Pro ... ink(x)) | flow.js:105:2:105:77 | new Pro ... ource}) | in $PromiseResolveField$ |
|
||||
| flow.js:105:2:105:97 | new Pro ... ink(x)) | flow.js:105:90:105:96 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:105:2:105:77 | new Pro ... ource}) | flow.js:105:2:105:48 | new Pro ... "BLA")) | copy $PromiseResolveField$ |
|
||||
| flow.js:105:2:105:97 | new Pro ... ink(x)) | flow.js:105:2:105:77 | new Pro ... ource}) | copy $PromiseResolveField$ |
|
||||
| flow.js:105:2:105:97 | new Pro ... ink(x)) | flow.js:105:90:105:96 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:105:2:105:97 | new Pro ... ink(x)) | flow.js:105:90:105:96 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:109:2:109:71 | new Pro ... jected) | flow.js:109:2:109:48 | new Pro ... "BLA")) | in $PromiseResolveField$ |
|
||||
| flow.js:109:2:109:91 | new Pro ... ink(x)) | flow.js:109:2:109:71 | new Pro ... jected) | in $PromiseResolveField$ |
|
||||
| flow.js:109:2:109:91 | new Pro ... ink(x)) | flow.js:109:84:109:90 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:109:2:109:71 | new Pro ... jected) | flow.js:109:2:109:48 | new Pro ... "BLA")) | copy $PromiseResolveField$ |
|
||||
| flow.js:109:2:109:91 | new Pro ... ink(x)) | flow.js:109:2:109:71 | new Pro ... jected) | copy $PromiseResolveField$ |
|
||||
| flow.js:109:2:109:91 | new Pro ... ink(x)) | flow.js:109:84:109:90 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:109:2:109:91 | new Pro ... ink(x)) | flow.js:109:84:109:90 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:111:2:111:69 | new Pro ... jected) | flow.js:111:2:111:48 | new Pro ... "BLA")) | in $PromiseResolveField$ |
|
||||
| flow.js:111:2:111:88 | new Pro ... ink(x)) | flow.js:111:81:111:87 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:111:2:111:69 | new Pro ... jected) | flow.js:111:2:111:48 | new Pro ... "BLA")) | copy $PromiseResolveField$ |
|
||||
| flow.js:111:2:111:88 | new Pro ... ink(x)) | flow.js:111:81:111:87 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:111:2:111:88 | new Pro ... ink(x)) | flow.js:111:81:111:87 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:111:76:111:76 | x | flow.js:111:2:111:69 | new Pro ... jected) | load $PromiseResolveField$ |
|
||||
| flow.js:113:2:113:69 | new Pro ... jected) | flow.js:113:2:113:48 | new Pro ... "BLA")) | in $PromiseResolveField$ |
|
||||
| flow.js:113:2:113:89 | new Pro ... ink(x)) | flow.js:113:2:113:69 | new Pro ... jected) | in $PromiseResolveField$ |
|
||||
| flow.js:113:2:113:89 | new Pro ... ink(x)) | flow.js:113:82:113:88 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:113:2:113:69 | new Pro ... jected) | flow.js:113:2:113:48 | new Pro ... "BLA")) | copy $PromiseResolveField$ |
|
||||
| flow.js:113:2:113:89 | new Pro ... ink(x)) | flow.js:113:2:113:69 | new Pro ... jected) | copy $PromiseResolveField$ |
|
||||
| flow.js:113:2:113:89 | new Pro ... ink(x)) | flow.js:113:82:113:88 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:113:2:113:89 | new Pro ... ink(x)) | flow.js:113:82:113:88 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:117:2:117:69 | new Pro ... solved) | flow.js:117:2:117:48 | new Pro ... "BLA")) | in $PromiseResolveField$ |
|
||||
| flow.js:117:2:117:89 | new Pro ... ink(x)) | flow.js:117:2:117:69 | new Pro ... solved) | in $PromiseResolveField$ |
|
||||
| flow.js:117:2:117:89 | new Pro ... ink(x)) | flow.js:117:82:117:88 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:117:2:117:69 | new Pro ... solved) | flow.js:117:2:117:48 | new Pro ... "BLA")) | copy $PromiseResolveField$ |
|
||||
| flow.js:117:2:117:89 | new Pro ... ink(x)) | flow.js:117:2:117:69 | new Pro ... solved) | copy $PromiseResolveField$ |
|
||||
| flow.js:117:2:117:89 | new Pro ... ink(x)) | flow.js:117:82:117:88 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:117:2:117:89 | new Pro ... ink(x)) | flow.js:117:82:117:88 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:119:2:119:69 | new Pro ... solved) | flow.js:119:2:119:48 | new Pro ... "BLA")) | in $PromiseResolveField$ |
|
||||
| flow.js:119:2:119:88 | new Pro ... ink(x)) | flow.js:119:81:119:87 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:119:2:119:69 | new Pro ... solved) | flow.js:119:2:119:48 | new Pro ... "BLA")) | copy $PromiseResolveField$ |
|
||||
| flow.js:119:2:119:88 | new Pro ... ink(x)) | flow.js:119:81:119:87 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:119:2:119:88 | new Pro ... ink(x)) | flow.js:119:81:119:87 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:119:76:119:76 | x | flow.js:119:2:119:69 | new Pro ... solved) | load $PromiseResolveField$ |
|
||||
| flow.js:121:2:121:61 | Promise ... ink(x)) | flow.js:121:2:121:41 | Promise ... solved) | in $PromiseResolveField$ |
|
||||
| flow.js:121:2:121:61 | Promise ... ink(x)) | flow.js:121:54:121:60 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:121:2:121:61 | Promise ... ink(x)) | flow.js:121:2:121:41 | Promise ... solved) | copy $PromiseResolveField$ |
|
||||
| flow.js:121:2:121:61 | Promise ... ink(x)) | flow.js:121:54:121:60 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:121:2:121:61 | Promise ... ink(x)) | flow.js:121:54:121:60 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:121:28:121:28 | x | flow.js:121:2:121:21 | Promise.resolve(123) | load $PromiseResolveField$ |
|
||||
| flow.js:123:2:123:60 | Promise ... ink(x)) | flow.js:123:53:123:59 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:123:2:123:60 | Promise ... ink(x)) | flow.js:123:53:123:59 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:123:2:123:60 | Promise ... ink(x)) | flow.js:123:53:123:59 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:123:28:123:28 | x | flow.js:123:2:123:21 | Promise.resolve(123) | load $PromiseResolveField$ |
|
||||
| flow.js:123:48:123:48 | x | flow.js:123:2:123:41 | Promise ... solved) | load $PromiseResolveField$ |
|
||||
| flow.js:125:2:125:61 | Promise ... ink(x)) | flow.js:125:2:125:41 | Promise ... jected) | in $PromiseResolveField$ |
|
||||
| flow.js:125:2:125:61 | Promise ... ink(x)) | flow.js:125:54:125:60 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:125:2:125:61 | Promise ... ink(x)) | flow.js:125:2:125:41 | Promise ... jected) | copy $PromiseResolveField$ |
|
||||
| flow.js:125:2:125:61 | Promise ... ink(x)) | flow.js:125:54:125:60 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:125:2:125:61 | Promise ... ink(x)) | flow.js:125:54:125:60 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:125:28:125:28 | x | flow.js:125:2:125:21 | Promise.resolve(123) | load $PromiseResolveField$ |
|
||||
| flow.js:127:2:127:60 | Promise ... ink(x)) | flow.js:127:53:127:59 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:127:2:127:60 | Promise ... ink(x)) | flow.js:127:53:127:59 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:127:2:127:60 | Promise ... ink(x)) | flow.js:127:53:127:59 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:127:28:127:28 | x | flow.js:127:2:127:21 | Promise.resolve(123) | load $PromiseResolveField$ |
|
||||
| flow.js:127:48:127:48 | x | flow.js:127:2:127:41 | Promise ... jected) | load $PromiseResolveField$ |
|
||||
| flow.js:129:2:129:71 | new Pro ... ink(x)) | flow.js:129:64:129:70 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:129:2:129:71 | new Pro ... ink(x)) | flow.js:129:64:129:70 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:129:2:129:71 | new Pro ... ink(x)) | flow.js:129:64:129:70 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:129:59:129:59 | x | flow.js:129:2:129:52 | new Pro ... olved)) | load $PromiseResolveField$ |
|
||||
| flow.js:131:2:131:45 | Promise ... ink(x)) | flow.js:131:38:131:44 | sink(x) | in $PromiseResolveField$ |
|
||||
| flow.js:131:2:131:45 | Promise ... ink(x)) | flow.js:131:38:131:44 | sink(x) | copy $PromiseResolveField$ |
|
||||
| flow.js:131:2:131:45 | Promise ... ink(x)) | flow.js:131:38:131:44 | sink(x) | store $PromiseResolveField$ |
|
||||
| flow.js:131:33:131:33 | x | flow.js:131:2:131:26 | Promise ... solved) | load $PromiseResolveField$ |
|
||||
| interflow.js:6:3:9:23 | loadScr ... eError) | interflow.js:6:3:8:26 | loadScr ... () { }) | in $PromiseResolveField$ |
|
||||
| promises.js:23:3:25:4 | promise ... v;\\n }) | promises.js:10:18:17:4 | new Pro ... );\\n }) | in $PromiseResolveField$ |
|
||||
| promises.js:33:19:35:6 | new Pro ... \\n }) | promises.js:34:17:34:22 | source | in $PromiseResolveField$ |
|
||||
| interflow.js:6:3:9:23 | loadScr ... eError) | interflow.js:6:3:8:26 | loadScr ... () { }) | copy $PromiseResolveField$ |
|
||||
| promises.js:23:3:25:4 | promise ... v;\\n }) | promises.js:10:18:17:4 | new Pro ... );\\n }) | copy $PromiseResolveField$ |
|
||||
| promises.js:33:19:35:6 | new Pro ... \\n }) | promises.js:34:17:34:22 | source | copy $PromiseResolveField$ |
|
||||
| promises.js:33:19:35:6 | new Pro ... \\n }) | promises.js:34:17:34:22 | source | store $PromiseResolveField$ |
|
||||
| promises.js:43:19:45:6 | Q.Promi ... \\n }) | promises.js:44:17:44:22 | source | in $PromiseResolveField$ |
|
||||
| promises.js:43:19:45:6 | Q.Promi ... \\n }) | promises.js:44:17:44:22 | source | copy $PromiseResolveField$ |
|
||||
| promises.js:43:19:45:6 | Q.Promi ... \\n }) | promises.js:44:17:44:22 | source | store $PromiseResolveField$ |
|
||||
| promises.js:71:34:71:36 | val | promises.js:71:5:71:27 | Promise ... source) | load $PromiseResolveField$ |
|
||||
| promises.js:72:48:72:50 | val | promises.js:72:5:72:41 | new Pro ... ource)) | load $PromiseResolveField$ |
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
| tst.ts:1:25:1:26 | -1 | -1 | -1 |
|
||||
@@ -0,0 +1,4 @@
|
||||
import javascript
|
||||
|
||||
from NumberLiteralTypeExpr t
|
||||
select t, t.getValue(), t.getIntValue()
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"include": ["."]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
type Foo<T> = T extends -1 ? true : false;
|
||||
@@ -0,0 +1,28 @@
|
||||
dataFlow
|
||||
| tst.js:2:16:2:23 | source() | tst.js:7:7:7:7 | e |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:11:10:11:10 | e |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:17:10:17:10 | v |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:21:10:21:14 | value |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:26:10:26:14 | value |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:30:7:30:7 | e |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:34:7:34:7 | e |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:38:7:38:7 | e |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:42:7:42:7 | e |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:46:7:46:7 | e |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:50:10:50:10 | e |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:53:8:53:21 | map.get("key") |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:59:8:59:22 | map2.get("foo") |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:64:8:64:26 | map3.get(unknown()) |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:69:8:69:26 | map3.get(unknown()) |
|
||||
typeTracking
|
||||
| tst.js:2:16:2:23 | source() | tst.js:2:16:2:23 | source() |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:6:14:6:14 | e |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:10:15:10:15 | e |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:16:15:16:15 | v |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:20:20:20:24 | value |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:25:14:25:18 | value |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:29:14:29:14 | e |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:33:14:33:14 | e |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:37:14:37:14 | e |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:45:14:45:14 | e |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:53:8:53:21 | map.get("key") |
|
||||
@@ -0,0 +1,33 @@
|
||||
import javascript
|
||||
|
||||
class Config extends DataFlow::Configuration {
|
||||
Config() { this = "Config" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source.(DataFlow::CallNode).getCalleeName() = "source"
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(DataFlow::CallNode call | call.getCalleeName() = "sink" | call.getAnArgument() = sink)
|
||||
}
|
||||
}
|
||||
|
||||
query predicate dataFlow(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
any(Config c).hasFlow(pred, succ)
|
||||
}
|
||||
|
||||
DataFlow::SourceNode trackSource(DataFlow::TypeTracker t, DataFlow::SourceNode start) {
|
||||
t.start() and
|
||||
result.(DataFlow::CallNode).getCalleeName() = "source" and
|
||||
start = result
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 | t = t2.step(trackSource(t2, start), result))
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 |
|
||||
result = CollectionsTypeTracking::collectionStep(trackSource(t2, start), t, t2)
|
||||
)
|
||||
}
|
||||
|
||||
query DataFlow::SourceNode typeTracking(DataFlow::Node start) {
|
||||
result = trackSource(DataFlow::TypeTracker::end(), start)
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
(function() {
|
||||
var source = source();
|
||||
var set = new Set();
|
||||
set.add(source);
|
||||
|
||||
for (const e of set) {
|
||||
sink(e); // NOT OK.
|
||||
}
|
||||
|
||||
set.forEach(e => {
|
||||
sink(e);
|
||||
})
|
||||
|
||||
var map = new Map();
|
||||
map.set("key", source);
|
||||
map.forEach(v => {
|
||||
sink(v);
|
||||
});
|
||||
|
||||
for (const [key, value] of map) {
|
||||
sink(value); // NOT OK.
|
||||
sink(key); // OK
|
||||
}
|
||||
|
||||
for (const value of map.values()) {
|
||||
sink(value); // NOT OK.
|
||||
}
|
||||
|
||||
for (const e of set.values()) {
|
||||
sink(e); // NOT OK
|
||||
}
|
||||
|
||||
for (const e of set.keys()) {
|
||||
sink(e); // NOT OK
|
||||
}
|
||||
|
||||
for (const e of new Set(set.keys())) {
|
||||
sink(e); // NOT OK
|
||||
}
|
||||
|
||||
for (const e of new Set([source])) {
|
||||
sink(e); // NOT OK (not caught by type-tracking, as it doesn't include array steps).
|
||||
}
|
||||
|
||||
for (const e of new Set(set)) {
|
||||
sink(e); // NOT OK
|
||||
}
|
||||
|
||||
for (const e of Array.from(set)) {
|
||||
sink(e); // NOT OK (not caught by type-tracking, as it doesn't include array steps).
|
||||
}
|
||||
|
||||
sink(map.get("key")); // NOT OK.
|
||||
sink(map.get("nonExistingKey")); // OK.
|
||||
|
||||
// unknown write, known read
|
||||
var map2 = new map();
|
||||
map2.set(unknown(), source);
|
||||
sink(map2.get("foo")); // NOT OK (for data-flow). OK for type-tracking.
|
||||
|
||||
// unknown write, unknown read
|
||||
var map3 = new map();
|
||||
map3.set(unknown(), source);
|
||||
sink(map3.get(unknown())); // NOT OK (for data-flow). OK for type-tracking.
|
||||
|
||||
// known write, unknown read
|
||||
var map4 = new map();
|
||||
map4.set("foo", source);
|
||||
sink(map3.get(unknown())); // NOT OK (for data-flow). OK for type-tracking.
|
||||
})();
|
||||
@@ -1,5 +1,13 @@
|
||||
| MisspelledVariableName.js:2:40:2:45 | lenght | 'lenght' may be a typo for variable $@. | MisspelledVariableName.js:2:19:2:24 | length | length |
|
||||
| tst.js:2:10:2:20 | errorMesage | 'errorMesage' may be a typo for variable $@. | tst.js:1:12:1:23 | errorMessage | errorMessage |
|
||||
| tst.js:6:10:6:21 | errorMessage | 'errorMessage' may be a typo for variable $@. | tst.js:5:12:5:22 | errorMesage | errorMesage |
|
||||
| tst.js:6:10:6:21 | errorMessage | $@ may be a typo for 'errorMessage'. | tst.js:5:12:5:22 | errorMesage | errorMesage |
|
||||
| tst.js:11:12:11:22 | errorMesage | 'errorMesage' may be a typo for variable $@. | tst.js:9:12:9:23 | errorMessage | errorMessage |
|
||||
| tst.js:17:5:17:16 | errorMessage | 'errorMessage' may be a typo for variable $@. | tst.js:15:12:15:22 | errorMesage | errorMesage |
|
||||
| tst.js:17:5:17:16 | errorMessage | $@ may be a typo for 'errorMessage'. | tst.js:15:12:15:22 | errorMesage | errorMesage |
|
||||
| tst.js:22:2:22:12 | thisHandler | $@ may be a typo for 'thisHandler'. | tst.js:21:6:21:15 | thisHander | thisHander |
|
||||
| tst.js:23:2:23:12 | thisHandler | $@ may be a typo for 'thisHandler'. | tst.js:21:6:21:15 | thisHander | thisHander |
|
||||
| tst.js:24:2:24:12 | thisHandler | $@ may be a typo for 'thisHandler'. | tst.js:21:6:21:15 | thisHander | thisHander |
|
||||
| tst.js:25:2:25:12 | thisHandler | $@ may be a typo for 'thisHandler'. | tst.js:21:6:21:15 | thisHander | thisHander |
|
||||
| tst.js:26:2:26:12 | thisHandler | $@ may be a typo for 'thisHandler'. | tst.js:21:6:21:15 | thisHander | thisHander |
|
||||
| tst.js:27:2:27:12 | thisHandler | $@ may be a typo for 'thisHandler'. | tst.js:21:6:21:15 | thisHander | thisHander |
|
||||
| tst.js:28:2:28:12 | thisHandler | $@ may be a typo for 'thisHandler'. | tst.js:21:6:21:15 | thisHander | thisHander |
|
||||
| tst.js:29:2:29:12 | thisHandler | $@ may be a typo for 'thisHandler'. | tst.js:21:6:21:15 | thisHander | thisHander |
|
||||
|
||||
@@ -16,3 +16,15 @@ function k(errorMesage) {
|
||||
let inner = () =>
|
||||
errorMessage;
|
||||
}
|
||||
|
||||
function foo() {
|
||||
var thisHander;
|
||||
thisHandler.foo1;
|
||||
thisHandler.foo2;
|
||||
thisHandler.foo3;
|
||||
thisHandler.foo4;
|
||||
thisHandler.foo5;
|
||||
thisHandler.foo6;
|
||||
thisHandler.foo7;
|
||||
thisHandler.foo8;
|
||||
}
|
||||
@@ -2082,6 +2082,92 @@ nodes
|
||||
| other-fs-libraries.js:24:35:24:38 | path |
|
||||
| other-fs-libraries.js:24:35:24:38 | path |
|
||||
| other-fs-libraries.js:24:35:24:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url |
|
||||
| other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:40:35:40:38 | path |
|
||||
| tainted-require.js:7:19:7:37 | req.param("module") |
|
||||
| tainted-require.js:7:19:7:37 | req.param("module") |
|
||||
| tainted-require.js:7:19:7:37 | req.param("module") |
|
||||
@@ -5673,6 +5759,118 @@ edges
|
||||
| other-fs-libraries.js:9:24:9:30 | req.url | other-fs-libraries.js:9:14:9:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:9:24:9:30 | req.url | other-fs-libraries.js:9:14:9:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:9:24:9:30 | req.url | other-fs-libraries.js:9:14:9:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:7:38:48 | path | other-fs-libraries.js:40:35:40:38 | path |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:37 | url.par ... , true) | other-fs-libraries.js:38:14:38:43 | url.par ... ).query |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:43 | url.par ... ).query | other-fs-libraries.js:38:14:38:48 | url.par ... ry.path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:14:38:48 | url.par ... ry.path | other-fs-libraries.js:38:7:38:48 | path |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:38:14:38:37 | url.par ... , true) |
|
||||
| tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") |
|
||||
| tainted-sendFile.js:8:16:8:33 | req.param("gimme") | tainted-sendFile.js:8:16:8:33 | req.param("gimme") |
|
||||
| tainted-sendFile.js:10:16:10:33 | req.param("gimme") | tainted-sendFile.js:10:16:10:33 | req.param("gimme") |
|
||||
@@ -6572,6 +6770,7 @@ edges
|
||||
| other-fs-libraries.js:17:35:17:38 | path | other-fs-libraries.js:9:24:9:30 | req.url | other-fs-libraries.js:17:35:17:38 | path | This path depends on $@. | other-fs-libraries.js:9:24:9:30 | req.url | a user-provided value |
|
||||
| other-fs-libraries.js:19:56:19:59 | path | other-fs-libraries.js:9:24:9:30 | req.url | other-fs-libraries.js:19:56:19:59 | path | This path depends on $@. | other-fs-libraries.js:9:24:9:30 | req.url | a user-provided value |
|
||||
| other-fs-libraries.js:24:35:24:38 | path | other-fs-libraries.js:9:24:9:30 | req.url | other-fs-libraries.js:24:35:24:38 | path | This path depends on $@. | other-fs-libraries.js:9:24:9:30 | req.url | a user-provided value |
|
||||
| other-fs-libraries.js:40:35:40:38 | path | other-fs-libraries.js:38:24:38:30 | req.url | other-fs-libraries.js:40:35:40:38 | path | This path depends on $@. | other-fs-libraries.js:38:24:38:30 | req.url | a user-provided value |
|
||||
| tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | This path depends on $@. | tainted-require.js:7:19:7:37 | req.param("module") | a user-provided value |
|
||||
| tainted-sendFile.js:8:16:8:33 | req.param("gimme") | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | This path depends on $@. | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | a user-provided value |
|
||||
| tainted-sendFile.js:10:16:10:33 | req.param("gimme") | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | This path depends on $@. | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | a user-provided value |
|
||||
|
||||
@@ -31,3 +31,11 @@ function getFsModule(special) {
|
||||
return require("original-fs");
|
||||
}
|
||||
}
|
||||
|
||||
var util = require("util");
|
||||
|
||||
http.createServer(function(req, res) {
|
||||
var path = url.parse(req.url, true).query.path;
|
||||
|
||||
util.promisify(fs.readFileSync)(path); // NOT OK
|
||||
});
|
||||
@@ -39,6 +39,14 @@ nodes
|
||||
| child_process-test.js:54:25:54:49 | ['/C', ... at(cmd) |
|
||||
| child_process-test.js:54:25:54:49 | ['/C', ... at(cmd) |
|
||||
| child_process-test.js:54:46:54:48 | cmd |
|
||||
| child_process-test.js:70:9:70:49 | cmd |
|
||||
| child_process-test.js:70:15:70:38 | url.par ... , true) |
|
||||
| child_process-test.js:70:15:70:44 | url.par ... ).query |
|
||||
| child_process-test.js:70:15:70:49 | url.par ... ry.path |
|
||||
| child_process-test.js:70:25:70:31 | req.url |
|
||||
| child_process-test.js:70:25:70:31 | req.url |
|
||||
| child_process-test.js:72:29:72:31 | cmd |
|
||||
| child_process-test.js:72:29:72:31 | cmd |
|
||||
| execSeries.js:3:20:3:22 | arr |
|
||||
| execSeries.js:6:14:6:16 | arr |
|
||||
| execSeries.js:6:14:6:21 | arr[i++] |
|
||||
@@ -129,6 +137,13 @@ edges
|
||||
| child_process-test.js:53:54:53:56 | cmd | child_process-test.js:53:46:53:57 | ["bar", cmd] |
|
||||
| child_process-test.js:54:46:54:48 | cmd | child_process-test.js:54:25:54:49 | ['/C', ... at(cmd) |
|
||||
| child_process-test.js:54:46:54:48 | cmd | child_process-test.js:54:25:54:49 | ['/C', ... at(cmd) |
|
||||
| child_process-test.js:70:9:70:49 | cmd | child_process-test.js:72:29:72:31 | cmd |
|
||||
| child_process-test.js:70:9:70:49 | cmd | child_process-test.js:72:29:72:31 | cmd |
|
||||
| child_process-test.js:70:15:70:38 | url.par ... , true) | child_process-test.js:70:15:70:44 | url.par ... ).query |
|
||||
| child_process-test.js:70:15:70:44 | url.par ... ).query | child_process-test.js:70:15:70:49 | url.par ... ry.path |
|
||||
| child_process-test.js:70:15:70:49 | url.par ... ry.path | child_process-test.js:70:9:70:49 | cmd |
|
||||
| child_process-test.js:70:25:70:31 | req.url | child_process-test.js:70:15:70:38 | url.par ... , true) |
|
||||
| child_process-test.js:70:25:70:31 | req.url | child_process-test.js:70:15:70:38 | url.par ... , true) |
|
||||
| execSeries.js:3:20:3:22 | arr | execSeries.js:6:14:6:16 | arr |
|
||||
| execSeries.js:6:14:6:16 | arr | execSeries.js:6:14:6:21 | arr[i++] |
|
||||
| execSeries.js:6:14:6:21 | arr[i++] | execSeries.js:14:24:14:30 | command |
|
||||
@@ -197,6 +212,7 @@ edges
|
||||
| child_process-test.js:54:5:54:50 | cp.spaw ... t(cmd)) | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:54:25:54:49 | ['/C', ... at(cmd) | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value |
|
||||
| child_process-test.js:59:5:59:39 | cp.exec ... , args) | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:50:15:50:17 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value |
|
||||
| child_process-test.js:64:3:64:21 | cp.spawn(cmd, args) | child_process-test.js:6:25:6:31 | req.url | child_process-test.js:43:15:43:17 | cmd | This command depends on $@. | child_process-test.js:6:25:6:31 | req.url | a user-provided value |
|
||||
| child_process-test.js:72:29:72:31 | cmd | child_process-test.js:70:25:70:31 | req.url | child_process-test.js:72:29:72:31 | cmd | This command depends on $@. | child_process-test.js:70:25:70:31 | req.url | a user-provided value |
|
||||
| execSeries.js:14:41:14:47 | command | execSeries.js:18:34:18:40 | req.url | execSeries.js:14:41:14:47 | command | This command depends on $@. | execSeries.js:18:34:18:40 | req.url | a user-provided value |
|
||||
| other.js:7:33:7:35 | cmd | other.js:5:25:5:31 | req.url | other.js:7:33:7:35 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value |
|
||||
| other.js:8:28:8:30 | cmd | other.js:5:25:5:31 | req.url | other.js:8:28:8:30 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value |
|
||||
|
||||
@@ -63,3 +63,12 @@ var server = http.createServer(function(req, res) {
|
||||
function run(cmd, args) {
|
||||
cp.spawn(cmd, args); // NOT OK
|
||||
}
|
||||
|
||||
var util = require("util")
|
||||
|
||||
http.createServer(function(req, res) {
|
||||
let cmd = url.parse(req.url, true).query.path;
|
||||
|
||||
util.promisify(cp.exec)(cmd); // NOT OK
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user