Merge remote-tracking branch 'upstream/master' into mergeback-2018-10-11

This commit is contained in:
Tom Hvitved
2018-10-11 14:36:44 +02:00
321 changed files with 27787 additions and 3927 deletions

View File

@@ -17,7 +17,7 @@ import javascript
* Holds if `setupCall` is a call to `$sceDelegateProvider.resourceUrlWhitelist` with
* argument `list`.
*/
predicate isResourceUrlWhitelist(DataFlow::MethodCallNode setupCall, DataFlow::ArrayLiteralNode list) {
predicate isResourceUrlWhitelist(DataFlow::MethodCallNode setupCall, DataFlow::ArrayCreationNode list) {
exists (AngularJS::ServiceReference service |
service.getName() = "$sceDelegateProvider" and
setupCall.asExpr() = service.getAMethodCall("resourceUrlWhitelist") and
@@ -33,7 +33,7 @@ class ResourceUrlWhitelistEntry extends Expr {
string pattern;
ResourceUrlWhitelistEntry() {
exists (DataFlow::ArrayLiteralNode whitelist |
exists (DataFlow::ArrayCreationNode whitelist |
isResourceUrlWhitelist(setupCall, whitelist) and
this = whitelist.getAnElement().asExpr() and
this.mayHaveStringValue(pattern)

View File

@@ -36,7 +36,7 @@ private predicate isBoundInMethod(MethodDeclaration method) {
bindAll.getArgument(1).mayHaveStringValue(name)
or
// _.bindAll(this, [<name1>, <name2>])
exists (DataFlow::ArrayLiteralNode names |
exists (DataFlow::ArrayCreationNode names |
names.flowsTo(bindAll.getArgument(1)) and
names.getAnElement().mayHaveStringValue(name)
)

View File

@@ -1,6 +1,6 @@
/**
* @name File Access data flows to Http POST/PUT
* @description Writing data from file directly to http body or request header can be an indication to data exfiltration or unauthorized information disclosure.
* @name File data in outbound network request
* @description Directly sending file data in an outbound network request can indicate unauthorized information disclosure.
* @kind problem
* @problem.severity warning
* @id js/file-access-to-http
@@ -11,6 +11,6 @@
import javascript
import semmle.javascript.security.dataflow.FileAccessToHttp
from FileAccessToHttpDataFlow::Configuration config, DataFlow::Node src, DataFlow::Node sink
from FileAccessToHttp::Configuration config, DataFlow::Node src, DataFlow::Node sink
where config.hasFlow (src, sink)
select src, "$@ flows directly to Http request body", sink, "File access"
select sink, "$@ flows directly to outbound network request", src, "File data"

View File

@@ -1,6 +1,6 @@
/**
* @name Http response data flows to File Access
* @description Writing data from an HTTP request directly to the file system allows arbitrary file upload and might indicate a backdoor.
* @name User-controlled data written to file
* @description Writing user-controlled data directly to the file system allows arbitrary file upload and might indicate a backdoor.
* @kind problem
* @problem.severity warning
* @id js/http-to-file-access
@@ -11,6 +11,6 @@
import javascript
import semmle.javascript.security.dataflow.HttpToFileAccess
from HttpToFileAccessFlow::Configuration configuration, DataFlow::Node src, DataFlow::Node sink
from HttpToFileAccess::Configuration configuration, DataFlow::Node src, DataFlow::Node sink
where configuration.hasFlow(src, sink)
select sink, "$@ flows to file system", src, "Untrusted data received from Http response"
select sink, "$@ flows to file system", src, "Untrusted data"

View File

@@ -25,8 +25,8 @@
<p>
To guard against request forgery, it is advisable to avoid
putting user input directly into a remote request. If a flexible
remote request mechanism is required, it is recommended to maintain a
putting user input directly into a network request. If a flexible
network request mechanism is required, it is recommended to maintain a
list of authorized request targets and choose from that list based on
the user input provided.

View File

@@ -1,6 +1,6 @@
/**
* @name Uncontrolled data used in remote request
* @description Sending remote requests with user-controlled data allows for request forgery attacks.
* @name Uncontrolled data used in network request
* @description Sending network requests with user-controlled data allows for request forgery attacks.
* @kind problem
* @problem.severity error
* @precision medium

View File

@@ -29,19 +29,27 @@ abstract class FileSystemAccess extends DataFlow::Node {
/** Gets an argument to this file system access that is interpreted as a path. */
abstract DataFlow::Node getAPathArgument();
/** Gets a node that represents file system access data, such as buffer the data is copied to. */
abstract DataFlow::Node getDataNode();
}
/**
* A data flow node that performs read file system access.
* A data flow node that reads data from the file system.
*/
abstract class FileSystemReadAccess extends FileSystemAccess { }
abstract class FileSystemReadAccess extends FileSystemAccess {
/** Gets a node that represents data from the file system. */
abstract DataFlow::Node getADataNode();
}
/**
* A data flow node that performs write file system access.
* A data flow node that writes data to the file system.
*/
abstract class FileSystemWriteAccess extends FileSystemAccess { }
abstract class FileSystemWriteAccess extends FileSystemAccess {
/** Gets a node that represents data to be written to the file system. */
abstract DataFlow::Node getADataNode();
}
/**
* A data flow node that contains a file name or an array of file names from the local file system.

View File

@@ -303,6 +303,16 @@ class ThisExpr extends @thisexpr, Expr {
Function getBinder() {
result = getEnclosingFunction().getThisBinder()
}
/**
* Gets the function or top-level whose `this` binding this expression refers to,
* which is the nearest enclosing non-arrow function or top-level.
*/
StmtContainer getBindingContainer() {
result = getContainer().(Function).getThisBindingContainer()
or
result = getContainer().(TopLevel)
}
}
/** An array literal. */

View File

@@ -206,6 +206,17 @@ class Function extends @function, Parameterized, TypeParameterized, StmtContaine
result = this
}
/**
* Gets the function or top-level whose `this` binding a `this` expression in this function refers to,
* which is the nearest enclosing non-arrow function or top-level.
*/
StmtContainer getThisBindingContainer() {
result = getThisBinder()
or
not exists(getThisBinder()) and
result = getTopLevel()
}
/**
* Holds if this function has a mapped `arguments` variable whose indices are aliased
* with the function's parameters.

View File

@@ -62,9 +62,9 @@ class JsonParseCall extends MethodCallExpr {
* However, since the function could be invoked in another way, we additionally
* still infer the ordinary abstract value.
*/
private class AnalyzedThisInArrayIterationFunction extends AnalyzedValueNode, DataFlow::ThisNode {
private class AnalyzedThisInArrayIterationFunction extends AnalyzedNode, DataFlow::ThisNode {
AnalyzedValueNode thisSource;
AnalyzedNode thisSource;
AnalyzedThisInArrayIterationFunction() {
exists(DataFlow::MethodCallNode bindingCall, string name |
@@ -82,7 +82,7 @@ private class AnalyzedThisInArrayIterationFunction extends AnalyzedValueNode, Da
override AbstractValue getALocalValue() {
result = thisSource.getALocalValue() or
result = AnalyzedValueNode.super.getALocalValue()
result = AnalyzedNode.super.getALocalValue()
}
}

View File

@@ -407,7 +407,7 @@ private class LibraryPartialCall extends AdditionalPartialInvokeNode {
override predicate isPartialArgument(DataFlow::Node callback, DataFlow::Node argument, int index) {
callback = getArgument(0) and
exists (DataFlow::ArrayLiteralNode array |
exists (DataFlow::ArrayCreationNode array |
array.flowsTo(getArgument(1)) and
argument = array.getElement(index))
}

View File

@@ -32,6 +32,7 @@ module DataFlow {
or TReflectiveCallNode(MethodCallExpr ce, string kind) {
ce.getMethodName() = kind and (kind = "call" or kind = "apply")
}
or TThisNode(StmtContainer f) { f.(Function).getThisBinder() = f or f instanceof TopLevel }
/**
* A node in the data flow graph.
@@ -867,6 +868,13 @@ module DataFlow {
nd = TDestructuringPatternNode(p)
}
/**
* INTERNAL: Use `thisNode(StmtContainer container)` instead.
*/
predicate thisNode(DataFlow::Node node, StmtContainer container) {
node = TThisNode(container)
}
/**
* A classification of flows that are not modeled, or only modeled incompletely, by
* `DataFlowNode`:
@@ -970,6 +978,11 @@ module DataFlow {
pred = valueNode(defSourceNode(def)) and
succ = TDestructuringPatternNode(def.getTarget())
)
or
// flow from 'this' parameter into 'this' expressions
exists (ThisExpr thiz |
pred = TThisNode(thiz.getBindingContainer()) and
succ = valueNode(thiz))
}
/**

View File

@@ -198,16 +198,36 @@ class NewNode extends InvokeNode {
override DataFlow::Impl::NewNodeDef impl;
}
/** A data flow node corresponding to a `this` expression. */
class ThisNode extends DataFlow::ValueNode, DataFlow::DefaultSourceNode {
override ThisExpr astNode;
/** A data flow node corresponding to the `this` parameter in a function or `this` at the top-level. */
class ThisNode extends DataFlow::Node, DataFlow::DefaultSourceNode {
ThisNode() {
DataFlow::thisNode(this, _)
}
/**
* Gets the function whose `this` binding this expression refers to,
* which is the nearest enclosing non-arrow function.
*/
FunctionNode getBinder() {
result = DataFlow::valueNode(astNode.getBinder())
exists (Function binder |
DataFlow::thisNode(this, binder) and
result = DataFlow::valueNode(binder))
}
/**
* Gets the function or top-level whose `this` binding this expression refers to,
* which is the nearest enclosing non-arrow function or top-level.
*/
StmtContainer getBindingContainer() {
DataFlow::thisNode(this, result)
}
override string toString() { result = "this" }
override predicate hasLocationInfo(string filepath, int startline, int startcolumn,
int endline, int endcolumn) {
// Use the function entry as the location
getBindingContainer().getEntry().getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}

View File

@@ -185,7 +185,6 @@ class DefaultSourceNode extends SourceNode {
astNode instanceof ObjectExpr or
astNode instanceof ArrayExpr or
astNode instanceof JSXNode or
astNode instanceof ThisExpr or
astNode instanceof GlobalVarAccess or
astNode instanceof ExternalModuleReference
)
@@ -198,5 +197,7 @@ class DefaultSourceNode extends SourceNode {
DataFlow::parameterNode(this, _)
or
this instanceof DataFlow::Impl::InvokeNodeDef
or
DataFlow::thisNode(this, _)
}
}

View File

@@ -10,7 +10,7 @@ import AbstractValuesImpl
/**
* Flow analysis for `this` expressions inside functions.
*/
private abstract class AnalyzedThisExpr extends DataFlow::AnalyzedValueNode, DataFlow::ThisNode {
private abstract class AnalyzedThisExpr extends DataFlow::AnalyzedNode, DataFlow::ThisNode {
DataFlow::FunctionNode binder;
AnalyzedThisExpr() {
@@ -29,7 +29,7 @@ private abstract class AnalyzedThisExpr extends DataFlow::AnalyzedValueNode, Dat
*/
private class AnalyzedThisInBoundFunction extends AnalyzedThisExpr {
AnalyzedValueNode thisSource;
AnalyzedNode thisSource;
AnalyzedThisInBoundFunction() {
exists(string name |

View File

@@ -146,7 +146,7 @@ private DataFlow::PropWrite getAPropertyDependencyInjection(Function function) {
*/
private class FunctionWithInjectProperty extends InjectableFunction {
override Function astNode;
DataFlow::ArrayLiteralNode dependencies;
DataFlow::ArrayCreationNode dependencies;
FunctionWithInjectProperty() {
(

View File

@@ -9,6 +9,10 @@ import javascript
/**
* A call that performs a request to a URL.
*
* Example: An HTTP POST request is a client request that sends some
* `data` to a `url`, where both the headers and the body of the request
* contribute to the `data`.
*/
abstract class CustomClientRequest extends DataFlow::InvokeNode {
@@ -16,10 +20,20 @@ abstract class CustomClientRequest extends DataFlow::InvokeNode {
* Gets the URL of the request.
*/
abstract DataFlow::Node getUrl();
/**
* Gets a node that contributes to the data-part this request.
*/
abstract DataFlow::Node getADataNode();
}
/**
* A call that performs a request to a URL.
*
* Example: An HTTP POST request is client request that sends some
* `data` to a `url`, where both the headers and the body of the request
* contribute to the `data`.
*/
class ClientRequest extends DataFlow::InvokeNode {
@@ -35,6 +49,14 @@ class ClientRequest extends DataFlow::InvokeNode {
DataFlow::Node getUrl() {
result = custom.getUrl()
}
/**
* Gets a node that contributes to the data-part this request.
*/
DataFlow::Node getADataNode() {
result = custom.getADataNode()
}
}
/**
@@ -83,6 +105,10 @@ private class RequestUrlRequest extends CustomClientRequest {
result = url
}
override DataFlow::Node getADataNode() {
result = getArgument(1)
}
}
/**
@@ -113,6 +139,10 @@ private class AxiosUrlRequest extends CustomClientRequest {
result = url
}
override DataFlow::Node getADataNode() {
none()
}
}
/**
@@ -144,6 +174,10 @@ private class FetchUrlRequest extends CustomClientRequest {
result = url
}
override DataFlow::Node getADataNode() {
none()
}
}
/**
@@ -169,6 +203,10 @@ private class GotUrlRequest extends CustomClientRequest {
result = url
}
override DataFlow::Node getADataNode() {
none()
}
}
/**
@@ -191,4 +229,8 @@ private class SuperAgentUrlRequest extends CustomClientRequest {
result = url
}
override DataFlow::Node getADataNode() {
none()
}
}

View File

@@ -63,6 +63,10 @@ module Electron {
result = getOptionArgument(0, "url")
}
override DataFlow::Node getADataNode() {
none()
}
}
/**
@@ -78,6 +82,10 @@ module Electron {
result = getOptionArgument(0, "url")
}
override DataFlow::Node getADataNode() {
none()
}
}

View File

@@ -824,7 +824,7 @@ module Express {
}
/** A call to `response.sendFile`, considered as a file system access. */
private class ResponseSendFileAsFileSystemAccess extends FileSystemAccess, DataFlow::ValueNode {
private class ResponseSendFileAsFileSystemAccess extends FileSystemReadAccess, DataFlow::ValueNode {
override MethodCallExpr astNode;
ResponseSendFileAsFileSystemAccess() {
@@ -832,8 +832,8 @@ module Express {
asExpr().(MethodCallExpr).calls(any(ResponseExpr res), name))
}
override DataFlow::Node getDataNode() {
result = DataFlow::valueNode(astNode)
override DataFlow::Node getADataNode() {
none()
}
override DataFlow::Node getAPathArgument() {
@@ -891,7 +891,7 @@ module Express {
getMethodName() = methodName and
exists (DataFlow::ValueNode arg |
arg = getAnArgument() |
exists (DataFlow::ArrayLiteralNode array |
exists (DataFlow::ArrayCreationNode array |
array.flowsTo(arg) and
routeHandlerArg = array.getAnElement()
) or

View File

@@ -144,8 +144,8 @@ module ExpressLibraries {
override DataFlow::Node getASecretKey() {
exists (DataFlow::Node secret | secret = getOption("secret") |
if exists(DataFlow::ArrayLiteralNode arr | arr.flowsTo(secret)) then
result = any (DataFlow::ArrayLiteralNode arr | arr.flowsTo(secret)).getAnElement()
if exists(DataFlow::ArrayCreationNode arr | arr.flowsTo(secret)) then
result = any (DataFlow::ArrayCreationNode arr | arr.flowsTo(secret)).getAnElement()
else
result = secret
)
@@ -182,8 +182,8 @@ module ExpressLibraries {
override DataFlow::Node getASecretKey() {
exists (DataFlow::Node arg0 | arg0 = getArgument(0) |
if exists(DataFlow::ArrayLiteralNode arr | arr.flowsTo(arg0)) then
result = any (DataFlow::ArrayLiteralNode arr | arr.flowsTo(arg0)).getAnElement()
if exists(DataFlow::ArrayCreationNode arr | arr.flowsTo(arg0)) then
result = any (DataFlow::ArrayCreationNode arr | arr.flowsTo(arg0)).getAnElement()
else
result = arg0
)
@@ -220,7 +220,7 @@ module ExpressLibraries {
override DataFlow::Node getASecretKey() {
result = getOption("secret") or
exists (DataFlow::ArrayLiteralNode keys |
exists (DataFlow::ArrayCreationNode keys |
keys.flowsTo(getOption("keys")) and
result = keys.getAnElement()
)

View File

@@ -132,11 +132,6 @@ module HTTP {
result = "http" or result = "https"
}
/**
* An expression whose value is sent as (part of) the body of an HTTP request (POST, PUT).
*/
abstract class RequestBody extends DataFlow::Node {}
/**
* An expression whose value is sent as (part of) the body of an HTTP response.
*/

View File

@@ -27,9 +27,9 @@ module LodashUnderscore {
* However, since the function could be invoked in another way, we additionally
* still infer the ordinary abstract value.
*/
private class AnalyzedThisInBoundCallback extends AnalyzedValueNode, DataFlow::ThisNode {
private class AnalyzedThisInBoundCallback extends AnalyzedNode, DataFlow::ThisNode {
AnalyzedValueNode thisSource;
AnalyzedNode thisSource;
AnalyzedThisInBoundCallback() {
exists(DataFlow::CallNode bindingCall, string binderName, int callbackIndex, int contextIndex, int argumentCount |
@@ -128,7 +128,7 @@ private class AnalyzedThisInBoundCallback extends AnalyzedValueNode, DataFlow::T
override AbstractValue getALocalValue() {
result = thisSource.getALocalValue() or
result = AnalyzedValueNode.super.getALocalValue()
result = AnalyzedNode.super.getALocalValue()
}
}

View File

@@ -379,7 +379,7 @@ module NodeJSLib {
*
* We determine this by looking for an externs declaration for
* `fs.methodName` where the `i`th parameter's name is `data` or
* `buffer` or a 'callback'.
* `buffer` or a `callback`.
*/
private predicate fsDataParam(string methodName, int i, string n) {
exists (ExternalMemberDecl decl, Function f, JSDocParamTag p |
@@ -401,160 +401,138 @@ module NodeJSLib {
)
}
/**
* A call to a method from module `fs`, `graceful-fs` or `fs-extra`.
*/
private class NodeJSFileSystemAccessCall extends FileSystemAccess, DataFlow::CallNode {
private class NodeJSFileSystemAccess extends FileSystemAccess, DataFlow::CallNode {
string methodName;
NodeJSFileSystemAccessCall() {
NodeJSFileSystemAccess() {
this = fsModuleMember(methodName).getACall()
}
/**
* Gets the name of the called method.
*/
string getMethodName() {
result = methodName
}
override DataFlow::Node getDataNode() {
(
methodName = "readFileSync" and
result = this
)
or
exists (int i, string paramName | fsDataParam(methodName, i, paramName) |
(
paramName = "callback" and
exists (DataFlow::ParameterNode p, string n |
p = getCallback(i).getAParameter() and
n = p.getName().toLowerCase() and
result = p |
n = "data" or n = "buffer" or n = "string"
)
)
or
result = getArgument(i))
}
override DataFlow::Node getAPathArgument() {
exists (int i | fsFileParam(methodName, i) |
result = getArgument(i))
}
}
/** Only NodeJSSystemFileAccessCalls that write data to 'fs' */
private class NodeJSFileSystemAccessWriteCall extends FileSystemWriteAccess, NodeJSFileSystemAccessCall {
NodeJSFileSystemAccessWriteCall () {
this.getMethodName() = "appendFile" or
this.getMethodName() = "appendFileSync" or
this.getMethodName() = "write" or
this.getMethodName() = "writeFile" or
this.getMethodName() = "writeFileSync" or
this.getMethodName() = "writeSync"
}
}
/** A write to the file system. */
private class NodeJSFileSystemAccessWrite extends FileSystemWriteAccess, NodeJSFileSystemAccess {
NodeJSFileSystemAccessWrite () {
methodName = "appendFile" or
methodName = "appendFileSync" or
methodName = "write" or
methodName = "writeFile" or
methodName = "writeFileSync" or
methodName = "writeSync"
}
/** Only NodeJSSystemFileAccessCalls that read data from 'fs' */
private class NodeJSFileSystemAccessReadCall extends FileSystemReadAccess, NodeJSFileSystemAccessCall {
NodeJSFileSystemAccessReadCall () {
this.getMethodName() = "read" or
this.getMethodName() = "readSync" or
this.getMethodName() = "readFile" or
this.getMethodName() = "readFileSync"
}
}
/**
* A call to write corresponds to a pattern where file stream is open first with 'createWriteStream', followed by 'write' or 'end' call
*/
private class NodeJSFileSystemWrite extends FileSystemWriteAccess, DataFlow::CallNode {
NodeJSFileSystemAccessCall init;
NodeJSFileSystemWrite() {
exists (NodeJSFileSystemAccessCall n |
n.getCalleeName() = "createWriteStream" and init = n |
this = n.getAMemberCall("write") or
this = n.getAMemberCall("end")
)
}
override DataFlow::Node getDataNode() {
result = this.getArgument(0)
}
override DataFlow::Node getAPathArgument() {
result = init.getAPathArgument()
}
}
/**
* A call to read corresponds to a pattern where file stream is open first with createReadStream, followed by 'read' call
*/
private class NodeJSFileSystemRead extends FileSystemReadAccess, DataFlow::CallNode {
NodeJSFileSystemAccessCall init;
NodeJSFileSystemRead() {
exists (NodeJSFileSystemAccessCall n |
n.getCalleeName() = "createReadStream" and init = n |
this = n.getAMemberCall("read")
)
}
override DataFlow::Node getDataNode() {
result = this
}
override DataFlow::Node getAPathArgument() {
result = init.getAPathArgument()
}
}
/**
* A call to read corresponds to a pattern where file stream is open first with createReadStream, followed by 'pipe' call
*/
private class NodeJSFileSystemPipe extends FileSystemReadAccess, DataFlow::CallNode {
NodeJSFileSystemAccessCall init;
NodeJSFileSystemPipe() {
exists (NodeJSFileSystemAccessCall n |
n.getCalleeName() = "createReadStream" and init = n |
this = n.getAMemberCall("pipe")
)
}
override DataFlow::Node getDataNode() {
result = this.getArgument(0)
}
override DataFlow::Node getAPathArgument() {
result = init.getAPathArgument()
}
}
/**
* An 'on' event where data comes in as a parameter (usage: readstream.on('data', chunk))
*/
private class NodeJSFileSystemReadDataEvent extends FileSystemReadAccess, DataFlow::CallNode {
NodeJSFileSystemAccessCall init;
NodeJSFileSystemReadDataEvent() {
exists(NodeJSFileSystemAccessCall n |
n.getCalleeName() = "createReadStream" and init = n |
this = n.getAMethodCall("on") and
this.getArgument(0).mayHaveStringValue("data")
override DataFlow::Node getADataNode() {
exists (int i, string paramName |
fsDataParam(methodName, i, paramName) |
if paramName = "callback" then
exists (DataFlow::ParameterNode p |
p = getCallback(i).getAParameter() and
p.getName().regexpMatch("(?i)data|buffer|string") and
result = p
)
else
result = getArgument(i)
)
}
override DataFlow::Node getDataNode() {
result = this.getCallback(1).getParameter(0)
}
/** A file system read. */
private class NodeJSFileSystemAccessRead extends FileSystemReadAccess, NodeJSFileSystemAccess {
NodeJSFileSystemAccessRead () {
methodName = "read" or
methodName = "readSync" or
methodName = "readFile" or
methodName = "readFileSync"
}
override DataFlow::Node getADataNode() {
if methodName.regexpMatch(".*Sync") then
result = this
else
exists (int i, string paramName |
fsDataParam(methodName, i, paramName) |
if paramName = "callback" then
exists (DataFlow::ParameterNode p |
p = getCallback(i).getAParameter() and
p.getName().regexpMatch("(?i)data|buffer|string") and
result = p
)
else
result = getArgument(i)
)
}
}
/**
* A write to the file system, using a stream.
*/
private class FileStreamWrite extends FileSystemWriteAccess, DataFlow::CallNode {
NodeJSFileSystemAccess stream;
FileStreamWrite() {
stream.getMethodName() = "createWriteStream" and
exists (string method |
method = "write" or
method = "end" |
this = stream.getAMemberCall(method)
)
}
override DataFlow::Node getADataNode() {
result = getArgument(0)
}
override DataFlow::Node getAPathArgument() {
result = init.getAPathArgument()
result = stream.getAPathArgument()
}
}
/**
* A read from the file system using a stream.
*/
private class FileStreamRead extends FileSystemReadAccess, DataFlow::CallNode {
NodeJSFileSystemAccess stream;
string method;
FileStreamRead() {
stream.getMethodName() = "createReadStream" and
this = stream.getAMemberCall(method) and
(method = "read" or method = "pipe" or method = "on")
}
override DataFlow::Node getADataNode() {
method = "read" and
result = this
or
method = "pipe" and
result = getArgument(0)
or
method = "on" and
getArgument(0).mayHaveStringValue("data") and
result = getCallback(1).getParameter(0)
}
override DataFlow::Node getAPathArgument() {
result = stream.getAPathArgument()
}
}
@@ -761,6 +739,10 @@ module NodeJSLib {
result = url
}
override DataFlow::Node getADataNode() {
result = getAMethodCall("write").getArgument(0)
}
}
/**
@@ -794,18 +776,6 @@ module NodeJSLib {
result = "http.request data parameter"
}
}
/**
* An argument to client request.write () method, can be used to write body to a HTTP or HTTPS POST/PUT request,
* or request option (like headers, cookies, even url)
*/
class HttpRequestWriteArgument extends HTTP::RequestBody, DataFlow::Node {
HttpRequestWriteArgument () {
exists(CustomClientRequest req |
this = req.getAMethodCall("write").getArgument(0) or
this = req.getArgument(0))
}
}
/**
* A data flow node that is registered as a callback for an HTTP or HTTPS request made by a Node.js process, for example the function `handler` in `http.request(url).on(message, handler)`.

View File

@@ -52,10 +52,20 @@ abstract class ReactComponent extends ASTNode {
}
/**
* Gets a `this` access in an instance method of this component.
* Gets the `this` node in an instance method of this component.
*/
DataFlow::SourceNode getAThisNode() {
result.(DataFlow::ThisNode).getBinder().getFunction() = getInstanceMethod(_)
}
/**
* Gets the `this` node in an instance method of this component.
*
* DEPRECATED: Use `getAThisNode` instead.
*/
deprecated
DataFlow::SourceNode getAThisAccess() {
result.asExpr().(ThisExpr).getBinder() = getInstanceMethod(_)
result = getAThisNode()
}
/**
@@ -515,9 +525,9 @@ private class FactoryDefinition extends ReactElementDefinition {
* However, since the function could be invoked in another way, we additionally
* still infer the ordinary abstract value.
*/
private class AnalyzedThisInBoundCallback extends AnalyzedValueNode, DataFlow::ThisNode {
private class AnalyzedThisInBoundCallback extends AnalyzedNode, DataFlow::ThisNode {
AnalyzedValueNode thisSource;
AnalyzedNode thisSource;
AnalyzedThisInBoundCallback() {
exists(DataFlow::CallNode bindingCall, string binderName |
@@ -533,7 +543,7 @@ private class AnalyzedThisInBoundCallback extends AnalyzedValueNode, DataFlow::T
override AbstractValue getALocalValue() {
result = thisSource.getALocalValue() or
result = AnalyzedValueNode.super.getALocalValue()
result = AnalyzedNode.super.getALocalValue()
}
}

View File

@@ -44,13 +44,5 @@ module Request {
}
}
// using 'request' library to make http 'POST' and 'PUT' requests with message body.
private class RequestPostBody extends HTTP::RequestBody {
RequestPostBody () {
this = DataFlow::moduleMember("request", "post").getACall().getArgument(1) or
this = DataFlow::moduleImport("request").getAnInvocation().getArgument(0)
}
}
}

View File

@@ -75,7 +75,7 @@ module CommandInjection {
ArgumentListTracking() { this = "ArgumentListTracking" }
override predicate isSource(DataFlow::Node nd) {
nd instanceof DataFlow::ArrayLiteralNode
nd instanceof DataFlow::ArrayCreationNode
or
exists (StringLiteral shell | shellCmd(shell, _) |
nd = DataFlow::valueNode(shell)
@@ -125,7 +125,7 @@ module CommandInjection {
* we want to report the `spawn` call as the sink, so we bind it to `sys`.
*/
private predicate indirectCommandInjection(DataFlow::Node sink, SystemCommandExecution sys) {
exists (ArgumentListTracking cfg, DataFlow::ArrayLiteralNode args,
exists (ArgumentListTracking cfg, DataFlow::ArrayCreationNode args,
StringLiteral shell, string dashC |
shellCmd(shell, dashC) and
cfg.hasFlow(DataFlow::valueNode(shell), sys.getACommandArgument()) and

View File

@@ -1,30 +1,33 @@
/**
* Provides Taint tracking configuration for reasoning about file access taint flow to http post body
/**
* Provides a taint tracking configuration for reasoning about file data in outbound network requests.
*/
import javascript
import semmle.javascript.frameworks.HTTP
import semmle.javascript.security.dataflow.RemoteFlowSources
module FileAccessToHttp {
module FileAccessToHttpDataFlow {
/**
* A data flow source for reasoning about file access to http post body flow vulnerabilities.
* A data flow source for file data in outbound network requests.
*/
abstract class Source extends DataFlow::Node { }
/**
* A data flow sink for reasoning about file access to http post body flow vulnerabilities.
* A data flow sink for file data in outbound network requests.
*/
abstract class Sink extends DataFlow::Node { }
/**
* A sanitizer for reasoning about file access to http post body flow vulnerabilities.
* A sanitizer for file data in outbound network requests.
*/
abstract class Sanitizer extends DataFlow::Node { }
/**
* A taint-tracking configuration for reasoning about file access to http post body flow vulnerabilities.
* A taint tracking configuration for file data in outbound network requests.
*/
class Configuration extends TaintTracking::Configuration {
Configuration() { this = "FileAccessToHttpDataFlow" }
Configuration() {
this = "FileAccessToHttp"
}
override predicate isSource(DataFlow::Node source) {
source instanceof Source
@@ -38,14 +41,9 @@ module FileAccessToHttpDataFlow {
super.isSanitizer(node) or
node instanceof Sanitizer
}
/** additional taint step that taints an object wrapping a source */
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
(
pred = DataFlow::valueNode(_) or
pred = DataFlow::parameterNode(_) or
pred instanceof DataFlow::PropRead
) and
// taint entire object on property write
exists (DataFlow::PropWrite pwr |
succ = pwr.getBase() and
pred = pwr.getRhs()
@@ -53,19 +51,26 @@ module FileAccessToHttpDataFlow {
}
}
/** A source is a file access parameter, as in readFromFile(buffer). */
/**
* A file access parameter, considered as a flow source for file data in outbound network requests.
*/
private class FileAccessArgumentAsSource extends Source {
FileAccessArgumentAsSource() {
exists(FileSystemReadAccess src |
this = src.getDataNode().getALocalSource()
this = src.getADataNode().getALocalSource()
)
}
}
/** Sink is any parameter or argument that evaluates to a parameter ot a function or call that sets Http Body on a request */
private class HttpRequestBodyAsSink extends Sink {
HttpRequestBodyAsSink () {
this instanceof HTTP::RequestBody
/**
* The URL or data of a client request, considered as a flow source for file data in outbound network requests.
*/
private class ClientRequestUrlOrDataAsSink extends Sink {
ClientRequestUrlOrDataAsSink () {
exists (ClientRequest req |
this = req.getUrl() or
this = req.getADataNode()
)
}
}
}

View File

@@ -1,30 +1,33 @@
/**
* Provides taint tracking configuration for reasoning about files created from untrusted http downloads.
/**
* Provides a taint tracking configuration for reasoning about writing user-controlled data to files.
*/
import javascript
import semmle.javascript.security.dataflow.RemoteFlowSources
module HttpToFileAccessFlow {
module HttpToFileAccess {
/**
* A data flow source from untrusted http request to file access taint tracking configuration.
* A data flow source for writing user-controlled data to files.
*/
abstract class Source extends DataFlow::Node { }
/**
* A data flow sink for untrusted http request to file access taint tracking configuration.
* A data flow sink for writing user-controlled data to files.
*/
abstract class Sink extends DataFlow::Node { }
/**
* A sanitizer for untrusted http request to file access taint tracking configuration.
* A sanitizer for writing user-controlled data to files.
*/
abstract class Sanitizer extends DataFlow::Node { }
/**
* A taint-tracking configuration for reasoning about file access from untrusted http response body.
* A taint tracking configuration for writing user-controlled data to files.
*/
class Configuration extends TaintTracking::Configuration {
Configuration() { this = "HttpToFileAccessFlow" }
Configuration() {
this = "HttpToFileAccess"
}
override predicate isSource(DataFlow::Node source) {
source instanceof Source
@@ -39,17 +42,17 @@ module HttpToFileAccessFlow {
node instanceof Sanitizer
}
}
/** A source of remote data, considered as a flow source for untrusted http data to file system access. */
/** A source of remote user input, considered as a flow source for writing user-controlled data to files. */
class RemoteFlowSourceAsSource extends Source {
RemoteFlowSourceAsSource() { this instanceof RemoteFlowSource }
}
/** A sink that represents file access method (write, append) argument */
class FileAccessAsSink extends Sink {
FileAccessAsSink () {
exists(FileSystemWriteAccess src |
this = src.getDataNode()
this = src.getADataNode()
)
}
}

View File

@@ -76,6 +76,7 @@
| tst.js:37:5:42:1 | o | tst.js:83:23:83:23 | o |
| tst.js:37:5:42:1 | o | tst.js:85:23:85:23 | o |
| tst.js:37:9:42:1 | {\\n x: ... ;\\n }\\n} | tst.js:37:5:42:1 | o |
| tst.js:39:4:39:3 | this | tst.js:40:5:40:8 | this |
| tst.js:46:10:46:11 | "" | tst.js:46:1:46:11 | global = "" |
| tst.js:49:1:54:1 | A | tst.js:55:1:55:1 | A |
| tst.js:49:1:54:1 | class A ... `\\n }\\n} | tst.js:49:1:54:1 | A |

View File

@@ -1,14 +1,20 @@
| eval.js:1:1:1:0 | this |
| eval.js:1:1:1:0 | this |
| eval.js:1:1:5:1 | functio ... eval`\\n} |
| eval.js:3:3:3:6 | eval |
| eval.js:3:3:3:16 | eval("x = 23") |
| sources.js:1:1:1:0 | this |
| sources.js:1:1:1:12 | new (x => x) |
| sources.js:1:6:1:6 | x |
| sources.js:1:6:1:11 | x => x |
| sources.js:3:1:5:6 | (functi ... \\n})(23) |
| sources.js:3:2:3:1 | this |
| sources.js:3:2:5:1 | functio ... x+19;\\n} |
| sources.js:3:11:3:11 | x |
| tst.js:1:1:1:0 | this |
| tst.js:1:10:1:11 | fs |
| tst.js:16:1:20:9 | (functi ... ("arg") |
| tst.js:16:2:16:1 | this |
| tst.js:16:2:20:1 | functio ... n "";\\n} |
| tst.js:16:13:16:13 | a |
| tst.js:17:7:17:10 | Math |
@@ -17,11 +23,12 @@
| tst.js:22:7:22:18 | readFileSync |
| tst.js:28:1:30:3 | (() =>\\n ... les\\n)() |
| tst.js:28:2:29:3 | () =>\\n x |
| tst.js:32:1:32:0 | this |
| tst.js:32:1:34:1 | functio ... ables\\n} |
| tst.js:35:1:35:7 | g(true) |
| tst.js:37:9:42:1 | {\\n x: ... ;\\n }\\n} |
| tst.js:39:4:39:3 | this |
| tst.js:39:4:41:3 | () {\\n this;\\n } |
| tst.js:40:5:40:8 | this |
| tst.js:43:1:43:3 | o.x |
| tst.js:44:1:44:3 | o.m |
| tst.js:44:1:44:5 | o.m() |
@@ -29,18 +36,22 @@
| tst.js:47:1:47:6 | global |
| tst.js:49:1:54:1 | class A ... `\\n }\\n} |
| tst.js:49:17:49:17 | B |
| tst.js:50:14:50:13 | this |
| tst.js:50:14:53:3 | () {\\n ... et`\\n } |
| tst.js:51:5:51:13 | super(42) |
| tst.js:58:1:58:3 | tag |
| tst.js:61:3:61:5 | o.m |
| tst.js:64:1:64:0 | this |
| tst.js:64:1:67:1 | functio ... lysed\\n} |
| tst.js:68:12:68:14 | h() |
| tst.js:69:1:69:9 | iter.next |
| tst.js:69:1:69:13 | iter.next(23) |
| tst.js:71:1:71:0 | this |
| tst.js:71:1:73:1 | async f ... lysed\\n} |
| tst.js:72:9:72:9 | p |
| tst.js:72:9:72:11 | p() |
| tst.js:87:1:96:2 | (functi ... r: 0\\n}) |
| tst.js:87:2:87:1 | this |
| tst.js:87:2:92:1 | functio ... + z;\\n} |
| tst.js:87:11:87:24 | { p: x, ...o } |
| tst.js:87:13:87:16 | p: x |
@@ -49,6 +60,7 @@
| tst.js:90:6:90:9 | r: z |
| tst.js:92:4:96:1 | {\\n p: ... r: 0\\n} |
| tst.js:98:1:103:17 | (functi ... 3, 0 ]) |
| tst.js:98:2:98:1 | this |
| tst.js:98:2:103:1 | functio ... + z;\\n} |
| tst.js:98:11:98:24 | [ x, ...rest ] |
| tst.js:98:13:98:13 | x |
@@ -56,7 +68,9 @@
| tst.js:99:9:99:9 | y |
| tst.js:101:7:101:7 | z |
| tst.js:103:4:103:16 | [ 19, 23, 0 ] |
| tst.ts:1:1:1:0 | this |
| tst.ts:3:3:3:8 | setX() |
| tst.ts:7:1:7:0 | this |
| tst.ts:7:1:9:1 | functio ... = 23;\\n} |
| tst.ts:8:3:8:5 | A.x |
| tst.ts:11:11:11:13 | A.x |
@@ -65,3 +79,4 @@
| tst.ts:13:39:13:38 | (...arg ... rgs); } |
| tst.ts:13:39:13:38 | args |
| tst.ts:13:39:13:38 | super(...args) |
| tst.ts:13:39:13:38 | this |

View File

@@ -1,10 +1,10 @@
| tst2.js:1:1:1:0 | this |
| tst2.js:1:9:1:25 | require("global") |
| tst2.js:3:1:3:24 | require ... indow") |
| tst2.js:7:1:7:6 | global |
| tst2.js:8:1:8:6 | global |
| tst2.js:9:1:9:4 | this |
| tst.js:1:1:1:0 | this |
| tst.js:1:1:1:6 | window |
| tst.js:2:1:2:4 | this |
| tst.js:3:1:3:6 | window |
| tst.js:4:1:4:6 | window |
| tst.js:4:1:4:13 | window.window |

View File

@@ -1,8 +1,8 @@
| tst.js:1:1:1:0 | this | tst.js:23:15:23:29 | this.someMethod |
| tst.js:1:1:1:0 | this | tst.js:24:36:24:45 | this.state |
| tst.js:14:5:14:11 | console | tst.js:14:5:14:15 | console.log |
| tst.js:17:5:17:11 | console | tst.js:17:5:17:15 | console.log |
| tst.js:23:15:23:18 | this | tst.js:23:15:23:29 | this.someMethod |
| tst.js:23:15:23:29 | this.someMethod | tst.js:23:15:23:34 | this.someMethod.bind |
| tst.js:24:36:24:39 | this | tst.js:24:36:24:45 | this.state |
| tst.js:24:36:24:45 | this.state | tst.js:24:36:24:50 | this.state.name |
| tst.js:34:6:34:7 | vv | tst.js:34:6:34:10 | vv.pp |
| tst.js:35:6:35:8 | vvv | tst.js:35:6:35:12 | vvv.ppp |

View File

@@ -1,8 +1,8 @@
| tst.js:1:1:1:0 | this | someMethod | tst.js:23:15:23:29 | this.someMethod |
| tst.js:1:1:1:0 | this | state | tst.js:24:36:24:45 | this.state |
| tst.js:14:5:14:11 | console | log | tst.js:14:5:14:15 | console.log |
| tst.js:17:5:17:11 | console | log | tst.js:17:5:17:15 | console.log |
| tst.js:23:15:23:18 | this | someMethod | tst.js:23:15:23:29 | this.someMethod |
| tst.js:23:15:23:29 | this.someMethod | bind | tst.js:23:15:23:34 | this.someMethod.bind |
| tst.js:24:36:24:39 | this | state | tst.js:24:36:24:45 | this.state |
| tst.js:24:36:24:45 | this.state | name | tst.js:24:36:24:50 | this.state.name |
| tst.js:34:6:34:7 | vv | pp | tst.js:34:6:34:10 | vv.pp |
| tst.js:35:6:35:8 | vvv | ppp | tst.js:35:6:35:12 | vvv.ppp |

View File

@@ -1,3 +1,5 @@
| tst.js:1:1:1:0 | this | tst.js:23:15:23:29 | this.someMethod |
| tst.js:1:1:1:0 | this | tst.js:24:36:24:45 | this.state |
| tst.js:2:11:10:1 | {\\n x ... }\\n} | tst.js:3:5:3:8 | x: 4 |
| tst.js:2:11:10:1 | {\\n x ... }\\n} | tst.js:4:5:6:5 | func: f ... ;\\n } |
| tst.js:2:11:10:1 | {\\n x ... }\\n} | tst.js:7:5:9:5 | f() {\\n ... ;\\n } |
@@ -5,10 +7,8 @@
| tst.js:14:5:14:11 | console | tst.js:14:5:14:15 | console.log |
| tst.js:17:5:17:11 | console | tst.js:17:5:17:15 | console.log |
| tst.js:21:1:21:1 | C | tst.js:21:1:21:6 | C.prop |
| tst.js:23:15:23:18 | this | tst.js:23:15:23:29 | this.someMethod |
| tst.js:23:15:23:29 | this.someMethod | tst.js:23:15:23:34 | this.someMethod.bind |
| tst.js:24:8:24:57 | <div on ... }</div> | tst.js:24:13:24:27 | onClick={click} |
| tst.js:24:36:24:39 | this | tst.js:24:36:24:45 | this.state |
| tst.js:24:36:24:45 | this.state | tst.js:24:36:24:50 | this.state.name |
| tst.js:26:2:29:1 | {\\n get ... v) {}\\n} | tst.js:27:3:27:26 | get x() ... null; } |
| tst.js:26:2:29:1 | {\\n get ... v) {}\\n} | tst.js:28:3:28:13 | set y(v) {} |

View File

@@ -1,3 +1,5 @@
| tst.js:1:1:1:0 | this | someMethod | tst.js:23:15:23:29 | this.someMethod |
| tst.js:1:1:1:0 | this | state | tst.js:24:36:24:45 | this.state |
| tst.js:2:11:10:1 | {\\n x ... }\\n} | f | tst.js:7:5:9:5 | f() {\\n ... ;\\n } |
| tst.js:2:11:10:1 | {\\n x ... }\\n} | func | tst.js:4:5:6:5 | func: f ... ;\\n } |
| tst.js:2:11:10:1 | {\\n x ... }\\n} | x | tst.js:3:5:3:8 | x: 4 |
@@ -5,10 +7,8 @@
| tst.js:14:5:14:11 | console | log | tst.js:14:5:14:15 | console.log |
| tst.js:17:5:17:11 | console | log | tst.js:17:5:17:15 | console.log |
| tst.js:21:1:21:1 | C | prop | tst.js:21:1:21:6 | C.prop |
| tst.js:23:15:23:18 | this | someMethod | tst.js:23:15:23:29 | this.someMethod |
| tst.js:23:15:23:29 | this.someMethod | bind | tst.js:23:15:23:34 | this.someMethod.bind |
| tst.js:24:8:24:57 | <div on ... }</div> | onClick | tst.js:24:13:24:27 | onClick={click} |
| tst.js:24:36:24:39 | this | state | tst.js:24:36:24:45 | this.state |
| tst.js:24:36:24:45 | this.state | name | tst.js:24:36:24:50 | this.state.name |
| tst.js:26:2:29:1 | {\\n get ... v) {}\\n} | x | tst.js:27:3:27:26 | get x() ... null; } |
| tst.js:26:2:29:1 | {\\n get ... v) {}\\n} | y | tst.js:28:3:28:13 | set y(v) {} |

View File

@@ -3,6 +3,8 @@
| partialCalls.js:4:17:4:24 | source() | partialCalls.js:30:14:30:20 | x.value |
| partialCalls.js:4:17:4:24 | source() | partialCalls.js:41:10:41:18 | id(taint) |
| partialCalls.js:4:17:4:24 | source() | partialCalls.js:51:14:51:14 | x |
| thisAssignments.js:4:17:4:24 | source() | thisAssignments.js:5:10:5:18 | obj.field |
| thisAssignments.js:7:19:7:26 | source() | thisAssignments.js:8:10:8:20 | this.field2 |
| tst.js:2:13:2:20 | source() | tst.js:4:10:4:10 | x |
| tst.js:2:13:2:20 | source() | tst.js:5:10:5:22 | "/" + x + "!" |
| tst.js:2:13:2:20 | source() | tst.js:14:10:14:17 | x.sort() |

View File

@@ -0,0 +1,10 @@
class C {
foo() {
let obj = {};
obj.field = source();
sink(obj.field); // NOT OK - tainted
this.field2 = source();
sink(this.field2); // NOT OK - tainted
}
}

View File

@@ -1,18 +1,42 @@
| es5.js:1:31:11:1 | {\\n dis ... ;\\n }\\n} | es5.js:1:31:11:1 | {\\n dis ... ;\\n }\\n} |
| es5.js:1:31:11:1 | {\\n dis ... ;\\n }\\n} | es5.js:3:11:3:10 | this |
| es5.js:1:31:11:1 | {\\n dis ... ;\\n }\\n} | es5.js:4:24:4:27 | this |
| es5.js:1:31:11:1 | {\\n dis ... ;\\n }\\n} | es5.js:6:20:6:19 | this |
| es5.js:18:33:22:1 | {\\n ren ... ;\\n }\\n} | es5.js:18:33:22:1 | {\\n ren ... ;\\n }\\n} |
| es5.js:18:33:22:1 | {\\n ren ... ;\\n }\\n} | es5.js:19:11:19:10 | this |
| es5.js:18:33:22:1 | {\\n ren ... ;\\n }\\n} | es5.js:20:24:20:27 | this |
| es6.js:1:1:8:1 | class H ... ;\\n }\\n} | es6.js:1:37:1:36 | this |
| es6.js:1:1:8:1 | class H ... ;\\n }\\n} | es6.js:2:9:2:8 | this |
| es6.js:1:1:8:1 | class H ... ;\\n }\\n} | es6.js:3:24:3:27 | this |
| es6.js:1:1:8:1 | class H ... ;\\n }\\n} | es6.js:5:14:5:13 | this |
| es6.js:14:1:20:1 | class H ... }\\n} | es6.js:15:16:15:15 | this |
| es6.js:14:1:20:1 | class H ... }\\n} | es6.js:16:9:16:12 | this |
| es6.js:14:1:20:1 | class H ... }\\n} | es6.js:17:9:17:12 | this |
| es6.js:14:1:20:1 | class H ... }\\n} | es6.js:18:9:18:12 | this |
| namedImport.js:3:1:3:28 | class C ... nent {} | namedImport.js:3:27:3:26 | this |
| namedImport.js:5:1:5:20 | class D extends C {} | namedImport.js:5:19:5:18 | this |
| plainfn.js:1:1:3:1 | functio ... div>;\\n} | plainfn.js:1:1:1:0 | this |
| plainfn.js:5:1:7:1 | functio ... iv");\\n} | plainfn.js:5:1:5:0 | this |
| plainfn.js:9:1:12:1 | functio ... rn x;\\n} | plainfn.js:9:1:9:0 | this |
| plainfn.js:20:1:24:1 | functio ... n 42;\\n} | plainfn.js:20:1:20:0 | this |
| preact.js:1:1:7:1 | class H ... }\\n} | preact.js:1:38:1:37 | this |
| preact.js:1:1:7:1 | class H ... }\\n} | preact.js:2:11:2:10 | this |
| preact.js:9:1:11:1 | class H ... nt {\\n\\n} | preact.js:9:38:9:37 | this |
| probably-a-component.js:1:1:6:1 | class H ... }\\n} | probably-a-component.js:1:31:1:30 | this |
| probably-a-component.js:1:1:6:1 | class H ... }\\n} | probably-a-component.js:2:11:2:10 | this |
| probably-a-component.js:1:1:6:1 | class H ... }\\n} | probably-a-component.js:3:9:3:12 | this |
| props.js:2:5:3:5 | class C ... {\\n } | props.js:2:37:2:36 | this |
| props.js:2:5:3:5 | class C ... {\\n } | props.js:9:5:9:55 | new C({ ... ctor"}) |
| props.js:13:31:17:5 | {\\n ... }\\n } | props.js:13:31:17:5 | {\\n ... }\\n } |
| props.js:13:31:17:5 | {\\n ... }\\n } | props.js:14:24:14:23 | this |
| props.js:26:5:28:5 | functio ... ;\\n } | props.js:26:5:26:4 | this |
| props.js:26:5:28:5 | functio ... ;\\n } | props.js:34:5:34:55 | new C({ ... ctor"}) |
| statePropertyReads.js:1:1:13:1 | class R ... }\\n} | statePropertyReads.js:2:16:2:15 | this |
| statePropertyReads.js:1:1:13:1 | class R ... }\\n} | statePropertyReads.js:3:9:3:12 | this |
| statePropertyReads.js:1:1:13:1 | class R ... }\\n} | statePropertyReads.js:5:9:5:12 | this |
| statePropertyReads.js:1:1:13:1 | class R ... }\\n} | statePropertyReads.js:7:9:7:12 | this |
| statePropertyReads.js:1:1:13:1 | class R ... }\\n} | statePropertyReads.js:10:23:10:22 | this |
| statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:2:16:2:15 | this |
| statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:3:13:3:22 | cmp |
| statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:3:19:3:22 | this |
| statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:4:9:4:11 | cmp |
@@ -21,28 +45,45 @@
| statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:14:9:14:11 | cmp |
| statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:18:9:18:11 | cmp |
| statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:22:9:22:11 | cmp |
| statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:25:20:25:19 | this |
| statePropertyWrites.js:36:19:45:1 | {\\n ren ... ;\\n }\\n} | statePropertyWrites.js:36:19:45:1 | {\\n ren ... ;\\n }\\n} |
| statePropertyWrites.js:36:19:45:1 | {\\n ren ... ;\\n }\\n} | statePropertyWrites.js:37:11:37:10 | this |
| statePropertyWrites.js:36:19:45:1 | {\\n ren ... ;\\n }\\n} | statePropertyWrites.js:38:24:38:27 | this |
| statePropertyWrites.js:36:19:45:1 | {\\n ren ... ;\\n }\\n} | statePropertyWrites.js:40:20:40:19 | this |
| thisAccesses.js:1:1:16:1 | class C ... }\\n} | thisAccesses.js:2:17:2:16 | this |
| thisAccesses.js:1:1:16:1 | class C ... }\\n} | thisAccesses.js:3:9:3:12 | this |
| thisAccesses.js:1:1:16:1 | class C ... }\\n} | thisAccesses.js:5:13:5:22 | dis |
| thisAccesses.js:1:1:16:1 | class C ... }\\n} | thisAccesses.js:5:19:5:22 | this |
| thisAccesses.js:1:1:16:1 | class C ... }\\n} | thisAccesses.js:6:9:6:11 | dis |
| thisAccesses.js:1:1:16:1 | class C ... }\\n} | thisAccesses.js:8:10:8:9 | this |
| thisAccesses.js:1:1:16:1 | class C ... }\\n} | thisAccesses.js:9:13:9:16 | this |
| thisAccesses.js:1:1:16:1 | class C ... }\\n} | thisAccesses.js:10:17:10:20 | this |
| thisAccesses.js:1:1:16:1 | class C ... }\\n} | thisAccesses.js:13:23:13:22 | this |
| thisAccesses.js:1:1:16:1 | class C ... }\\n} | thisAccesses.js:14:9:14:12 | this |
| thisAccesses.js:18:19:29:1 | {\\n r ... }\\n} | thisAccesses.js:18:19:29:1 | {\\n r ... }\\n} |
| thisAccesses.js:18:19:29:1 | {\\n r ... }\\n} | thisAccesses.js:19:13:19:12 | this |
| thisAccesses.js:18:19:29:1 | {\\n r ... }\\n} | thisAccesses.js:20:10:20:9 | this |
| thisAccesses.js:18:19:29:1 | {\\n r ... }\\n} | thisAccesses.js:21:13:21:16 | this |
| thisAccesses.js:18:19:29:1 | {\\n r ... }\\n} | thisAccesses.js:22:17:22:20 | this |
| thisAccesses.js:18:19:29:1 | {\\n r ... }\\n} | thisAccesses.js:26:25:26:24 | this |
| thisAccesses.js:18:19:29:1 | {\\n r ... }\\n} | thisAccesses.js:27:9:27:12 | this |
| thisAccesses.js:31:2:36:1 | functio ... iv/>;\\n} | thisAccesses.js:31:2:31:1 | this |
| thisAccesses.js:31:2:36:1 | functio ... iv/>;\\n} | thisAccesses.js:32:6:32:5 | this |
| thisAccesses.js:31:2:36:1 | functio ... iv/>;\\n} | thisAccesses.js:33:9:33:12 | this |
| thisAccesses.js:31:2:36:1 | functio ... iv/>;\\n} | thisAccesses.js:34:13:34:16 | this |
| thisAccesses.js:38:19:45:1 | {\\n r ... },\\n} | thisAccesses.js:38:19:45:1 | {\\n r ... },\\n} |
| thisAccesses.js:38:19:45:1 | {\\n r ... },\\n} | thisAccesses.js:39:13:39:12 | this |
| thisAccesses.js:38:19:45:1 | {\\n r ... },\\n} | thisAccesses.js:40:38:40:37 | this |
| thisAccesses.js:38:19:45:1 | {\\n r ... },\\n} | thisAccesses.js:41:13:41:16 | this |
| thisAccesses.js:38:19:45:1 | {\\n r ... },\\n} | thisAccesses.js:42:12:42:15 | this |
| thisAccesses.js:47:1:52:1 | class C ... }\\n} | thisAccesses.js:48:17:48:16 | this |
| thisAccesses.js:47:1:52:1 | class C ... }\\n} | thisAccesses.js:49:9:49:12 | this |
| thisAccesses.js:47:1:52:1 | class C ... }\\n} | thisAccesses.js:50:9:50:12 | this |
| thisAccesses_importedMappers.js:4:19:15:1 | {\\n r ... },\\n} | thisAccesses_importedMappers.js:4:19:15:1 | {\\n r ... },\\n} |
| thisAccesses_importedMappers.js:4:19:15:1 | {\\n r ... },\\n} | thisAccesses_importedMappers.js:5:13:5:12 | this |
| thisAccesses_importedMappers.js:4:19:15:1 | {\\n r ... },\\n} | thisAccesses_importedMappers.js:6:38:6:37 | this |
| thisAccesses_importedMappers.js:4:19:15:1 | {\\n r ... },\\n} | thisAccesses_importedMappers.js:7:13:7:16 | this |
| thisAccesses_importedMappers.js:4:19:15:1 | {\\n r ... },\\n} | thisAccesses_importedMappers.js:8:12:8:15 | this |
| thisAccesses_importedMappers.js:4:19:15:1 | {\\n r ... },\\n} | thisAccesses_importedMappers.js:9:25:9:24 | this |
| thisAccesses_importedMappers.js:4:19:15:1 | {\\n r ... },\\n} | thisAccesses_importedMappers.js:10:13:10:16 | this |
| thisAccesses_importedMappers.js:4:19:15:1 | {\\n r ... },\\n} | thisAccesses_importedMappers.js:11:12:11:15 | this |

View File

@@ -1,3 +1,4 @@
| addEventListener.js:2:20:2:29 | event.data | Cross-site scripting vulnerability due to $@. | addEventListener.js:1:43:1:47 | event | user-provided value |
| jquery.js:4:5:4:11 | tainted | Cross-site scripting vulnerability due to $@. | jquery.js:2:17:2:33 | document.location | user-provided value |
| jquery.js:7:5:7:34 | "<div i ... + "\\">" | Cross-site scripting vulnerability due to $@. | jquery.js:2:17:2:33 | document.location | user-provided value |
| jquery.js:8:18:8:34 | "XSS: " + tainted | Cross-site scripting vulnerability due to $@. | jquery.js:2:17:2:33 | document.location | user-provided value |

View File

@@ -0,0 +1,3 @@
this.addEventListener('message', function(event) {
document.write(event.data); // NOT OK
})

View File

@@ -1,8 +1,8 @@
| bufferRead.js:12:22:12:43 | new Buf ... s.size) | $@ flows directly to Http request body | bufferRead.js:33:21:33:28 | postData | File access |
| googlecompiler.js:44:54:44:57 | data | $@ flows directly to Http request body | googlecompiler.js:38:18:38:26 | post_data | File access |
| readFileSync.js:5:12:5:39 | fs.read ... t.txt") | $@ flows directly to Http request body | readFileSync.js:26:18:26:18 | s | File access |
| readStreamRead.js:13:21:13:35 | readable.read() | $@ flows directly to Http request body | readStreamRead.js:30:19:30:23 | chunk | File access |
| request.js:28:52:28:55 | data | $@ flows directly to Http request body | request.js:8:11:8:20 | {jsonData} | File access |
| request.js:43:51:43:54 | data | $@ flows directly to Http request body | request.js:16:11:23:3 | {\\n u ... ody\\n } | File access |
| sentAsHeaders.js:10:79:10:84 | buffer | $@ flows directly to Http request body | sentAsHeaders.js:14:20:19:9 | {\\n ... } | File access |
| sentAsHeaders.js:10:79:10:84 | buffer | $@ flows directly to Http request body | sentAsHeaders.js:20:20:25:9 | {\\n ... } | File access |
| bufferRead.js:33:21:33:28 | postData | $@ flows directly to outbound network request | bufferRead.js:12:22:12:43 | new Buf ... s.size) | File data |
| googlecompiler.js:38:18:38:26 | post_data | $@ flows directly to outbound network request | googlecompiler.js:44:54:44:57 | data | File data |
| readFileSync.js:26:18:26:18 | s | $@ flows directly to outbound network request | readFileSync.js:5:12:5:39 | fs.read ... t.txt") | File data |
| readStreamRead.js:30:19:30:23 | chunk | $@ flows directly to outbound network request | readStreamRead.js:13:21:13:35 | readable.read() | File data |
| request.js:8:11:8:20 | {jsonData} | $@ flows directly to outbound network request | request.js:28:52:28:55 | data | File data |
| request.js:16:11:23:3 | {\\n u ... ody\\n } | $@ flows directly to outbound network request | request.js:43:51:43:54 | data | File data |
| sentAsHeaders.js:14:20:19:9 | {\\n ... } | $@ flows directly to outbound network request | sentAsHeaders.js:10:79:10:84 | buffer | File data |
| sentAsHeaders.js:20:20:25:9 | {\\n ... } | $@ flows directly to outbound network request | sentAsHeaders.js:10:79:10:84 | buffer | File data |

View File

@@ -0,0 +1,6 @@
var express = require('express'),
app = express();
app.get('/getFooFile', function(req, res) {
res.sendFile("foo"); // OK (for now) since this is a server-side response
});

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,78 @@
// Automatically generated from TypeScript type definitions provided by
// DefinitelyTyped (https://github.com/DefinitelyTyped/DefinitelyTyped),
// which is licensed under the MIT license; see file DefinitelyTyped-LICENSE
// in parent directory.
// Type definitions for Node.js 10.5.x
// Project: http://nodejs.org/
// Definitions by: Microsoft TypeScript <http://typescriptlang.org>
// DefinitelyTyped <https://github.com/DefinitelyTyped/DefinitelyTyped>
// Parambir Singh <https://github.com/parambirs>
// Christian Vaagland Tellnes <https://github.com/tellnes>
// Wilco Bakker <https://github.com/WilcoBakker>
// Nicolas Voigt <https://github.com/octo-sniffle>
// Chigozirim C. <https://github.com/smac89>
// Flarna <https://github.com/Flarna>
// Mariusz Wiktorczyk <https://github.com/mwiktorczyk>
// wwwy3y3 <https://github.com/wwwy3y3>
// Deividas Bakanas <https://github.com/DeividasBakanas>
// Kelvin Jin <https://github.com/kjin>
// Alvis HT Tang <https://github.com/alvis>
// Sebastian Silbermann <https://github.com/eps1lon>
// Hannes Magnusson <https://github.com/Hannes-Magnusson-CK>
// Alberto Schiabel <https://github.com/jkomyno>
// Klaus Meinhardt <https://github.com/ajafff>
// Huw <https://github.com/hoo29>
// Nicolas Even <https://github.com/n-e>
// Bruno Scheufler <https://github.com/brunoscheufler>
// Mohsen Azimi <https://github.com/mohsen1>
// Hoàng Văn Khải <https://github.com/KSXGitHub>
// Alexander T. <https://github.com/a-tarasyuk>
// Lishude <https://github.com/islishude>
// Andrew Makarov <https://github.com/r3nya>
// Zane Hannan AU <https://github.com/ZaneHannanAU>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
/**
* @externs
* @fileoverview Definitions for module "fs"
*/
var fs = {};
/**
* @param {number} fd
* @param {Buffer} buffer
* @param {number} offset
* @param {number} length
* @param {number} position
* @param {(function(NodeJS.ErrnoException, number, Buffer): void)=} callback
* @return {void}
*/
fs.read = function(fd, buffer, offset, length, position, callback) {};
/**
* @param {string} filename
* @param {string} encoding
* @param {(function(NodeJS.ErrnoException, string): void)} callback
* @return {void}
*/
fs.readFile = function(filename, encoding, callback) {};
/**
* @param {string} filename
* @param {{encoding: string, flag: string}} options
* @param {(function(NodeJS.ErrnoException, string): void)} callback
* @return {void}
*/
fs.readFile = function(filename, options, callback) {};
/**
* @param {string} filename
* @param {{flag: string}} options
* @param {(function(NodeJS.ErrnoException, Buffer): void)} callback
* @return {void}
*/
fs.readFile = function(filename, options, callback) {};
/**
* @param {string} filename
* @param {(function(NodeJS.ErrnoException, Buffer): void)} callback
* @return {void}
*/
fs.readFile = function(filename, callback) {};

View File

@@ -1,3 +1,3 @@
| tst.js:16:33:16:33 | c | $@ flows to file system | tst.js:15:26:15:26 | c | Untrusted data received from Http response |
| tst.js:19:25:19:25 | c | $@ flows to file system | tst.js:15:26:15:26 | c | Untrusted data received from Http response |
| tst.js:24:22:24:22 | c | $@ flows to file system | tst.js:15:26:15:26 | c | Untrusted data received from Http response |
| tst.js:16:33:16:33 | c | $@ flows to file system | tst.js:15:26:15:26 | c | Untrusted data |
| tst.js:19:25:19:25 | c | $@ flows to file system | tst.js:15:26:15:26 | c | Untrusted data |
| tst.js:24:22:24:22 | c | $@ flows to file system | tst.js:15:26:15:26 | c | Untrusted data |

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,62 @@
// Automatically generated from TypeScript type definitions provided by
// DefinitelyTyped (https://github.com/DefinitelyTyped/DefinitelyTyped),
// which is licensed under the MIT license; see file DefinitelyTyped-LICENSE
// in parent directory.
// Type definitions for Node.js 10.5.x
// Project: http://nodejs.org/
// Definitions by: Microsoft TypeScript <http://typescriptlang.org>
// DefinitelyTyped <https://github.com/DefinitelyTyped/DefinitelyTyped>
// Parambir Singh <https://github.com/parambirs>
// Christian Vaagland Tellnes <https://github.com/tellnes>
// Wilco Bakker <https://github.com/WilcoBakker>
// Nicolas Voigt <https://github.com/octo-sniffle>
// Chigozirim C. <https://github.com/smac89>
// Flarna <https://github.com/Flarna>
// Mariusz Wiktorczyk <https://github.com/mwiktorczyk>
// wwwy3y3 <https://github.com/wwwy3y3>
// Deividas Bakanas <https://github.com/DeividasBakanas>
// Kelvin Jin <https://github.com/kjin>
// Alvis HT Tang <https://github.com/alvis>
// Sebastian Silbermann <https://github.com/eps1lon>
// Hannes Magnusson <https://github.com/Hannes-Magnusson-CK>
// Alberto Schiabel <https://github.com/jkomyno>
// Klaus Meinhardt <https://github.com/ajafff>
// Huw <https://github.com/hoo29>
// Nicolas Even <https://github.com/n-e>
// Bruno Scheufler <https://github.com/brunoscheufler>
// Mohsen Azimi <https://github.com/mohsen1>
// Hoàng Văn Khải <https://github.com/KSXGitHub>
// Alexander T. <https://github.com/a-tarasyuk>
// Lishude <https://github.com/islishude>
// Andrew Makarov <https://github.com/r3nya>
// Zane Hannan AU <https://github.com/ZaneHannanAU>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
/**
* @externs
* @fileoverview Definitions for module "fs"
*/
var fs = {};
/**
* @param {string} filename
* @param {*} data
* @param {(function(NodeJS.ErrnoException): void)=} callback
* @return {void}
*/
fs.writeFile = function(filename, data, callback) {};
/**
* @param {string} filename
* @param {*} data
* @param {{encoding: string, mode: number, flag: string}} options
* @param {(function(NodeJS.ErrnoException): void)=} callback
* @return {void}
*/
fs.writeFile = function(filename, data, options, callback) {};
/**
* @param {string} filename
* @param {*} data
* @param {{encoding: string, mode: string, flag: string}} options
* @param {(function(NodeJS.ErrnoException): void)=} callback
* @return {void}
*/
fs.writeFile = function(filename, data, options, callback) {};