Merge tag 'codeql-cli/latest' into auto/sync-main-pr

Compatible with the latest released version of the CodeQL CLI
This commit is contained in:
dilanbhalla
2025-04-22 14:59:21 +00:00
728 changed files with 31702 additions and 5048 deletions

View File

@@ -1,3 +1,17 @@
## 2.6.1
### Minor Analysis Improvements
* Data passed to the [NextResponse](https://nextjs.org/docs/app/api-reference/functions/next-response) constructor is now treated as a sink for `js/reflected-xss`.
* Data received from [NextRequest](https://nextjs.org/docs/app/api-reference/functions/next-request) and [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) is now treated as a remote user input `source`.
* Added support for the `make-dir` package.
* Added support for the `open` package.
* Added taint propagation for `Uint8Array`, `ArrayBuffer`, `SharedArrayBuffer` and `TextDecoder.decode()`.
* Improved detection of `WebSocket` and `SockJS` usage.
* Added data received from `WebSocket` clients as a remote flow source.
* Added support for additional `mkdirp` methods as sinks in path-injection queries.
* Added support for additional `rimraf` methods as sinks in path-injection queries.
## 2.6.0
### New Features

View File

@@ -0,0 +1,13 @@
## 2.6.1
### Minor Analysis Improvements
* Data passed to the [NextResponse](https://nextjs.org/docs/app/api-reference/functions/next-response) constructor is now treated as a sink for `js/reflected-xss`.
* Data received from [NextRequest](https://nextjs.org/docs/app/api-reference/functions/next-request) and [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) is now treated as a remote user input `source`.
* Added support for the `make-dir` package.
* Added support for the `open` package.
* Added taint propagation for `Uint8Array`, `ArrayBuffer`, `SharedArrayBuffer` and `TextDecoder.decode()`.
* Improved detection of `WebSocket` and `SockJS` usage.
* Added data received from `WebSocket` clients as a remote flow source.
* Added support for additional `mkdirp` methods as sinks in path-injection queries.
* Added support for additional `rimraf` methods as sinks in path-injection queries.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 2.6.0
lastReleaseVersion: 2.6.1

View File

@@ -0,0 +1,6 @@
extensions:
- addsTo:
pack: codeql/javascript-all
extensible: sinkModel
data:
- ["make-dir", "Member[makeDirectory,makeDirectorySync].Argument[0]", "path-injection"]

View File

@@ -0,0 +1,7 @@
extensions:
- addsTo:
pack: codeql/javascript-all
extensible: sinkModel
data:
- ["mkdirp", "Member[nativeSync,native,manual,manualSync,mkdirpNative,mkdirpManual,mkdirpManualSync,mkdirpNativeSync,mkdirpSync,sync].Argument[0]", "path-injection"]
- ["mkdirp", "Argument[0]", "path-injection"]

View File

@@ -0,0 +1,7 @@
extensions:
- addsTo:
pack: codeql/javascript-all
extensible: sinkModel
data:
- ["open", "Argument[0]", "path-injection"]
- ["open", "Member[openApp].Argument[0]", "path-injection"]

View File

@@ -0,0 +1,8 @@
extensions:
- addsTo:
pack: codeql/javascript-all
extensible: sinkModel
data:
- ["rimraf", "Member[sync,native,manual,windows,moveRemove,posix].Argument[0]", "path-injection"]
- ["rimraf", "Member[rimrafSync,nativeSync,manualSync,windowsSync,moveRemoveSync,posixSync].Argument[0]", "path-injection"]
- ["rimraf", "Member[native,manual,windows,moveRemove,posix].Member[sync].Argument[0]", "path-injection"]

View File

@@ -136,6 +136,7 @@ import semmle.javascript.frameworks.UriLibraries
import semmle.javascript.frameworks.Vue
import semmle.javascript.frameworks.Vuex
import semmle.javascript.frameworks.Webix
import semmle.javascript.frameworks.WebResponse
import semmle.javascript.frameworks.WebSocket
import semmle.javascript.frameworks.XmlParsers
import semmle.javascript.frameworks.xUnit

View File

@@ -1,5 +1,5 @@
name: codeql/javascript-all
version: 2.6.0
version: 2.6.1
groups: javascript
dbscheme: semmlecode.javascript.dbscheme
extractor: javascript

View File

@@ -318,6 +318,11 @@ module API {
Node getParameter(int i) {
Stages::ApiStage::ref() and
result = this.getASuccessor(Label::parameter(i))
or
exists(int spreadIndex, string arrayProp |
result = this.getASuccessor(Label::spreadArgument(spreadIndex)).getMember(arrayProp) and
i = spreadIndex + arrayProp.toInt()
)
}
/**
@@ -860,6 +865,23 @@ module API {
.getStaticMember(name, DataFlow::MemberKind::getter())
.getAReturn()
)
or
// Handle rest parameters escaping into external code. For example:
//
// function foo(...rest) {
// externalFunc(rest);
// }
//
// Here, 'rest' reaches a def-node at the call to externalFunc, so we need to ensure
// the arguments passed to 'foo' are stored in the 'rest' array.
exists(Function fun, DataFlow::InvokeNode invoke, int argIndex, Parameter rest |
fun.getRestParameter() = rest and
rest.flow() = pred and
invoke.getACallee() = fun and
invoke.getArgument(argIndex) = rhs and
argIndex >= rest.getIndex() and
lbl = Label::member((argIndex - rest.getIndex()).toString())
)
)
or
exists(DataFlow::ClassNode cls, string name |
@@ -888,6 +910,11 @@ module API {
i = -1 and lbl = Label::receiver()
)
or
exists(int i |
spreadArgumentPassing(base, i, rhs) and
lbl = Label::spreadArgument(i)
)
or
exists(DataFlow::SourceNode src, DataFlow::PropWrite pw |
use(base, src) and pw = trackUseNode(src).getAPropertyWrite() and rhs = pw.getRhs()
|
@@ -931,6 +958,29 @@ module API {
)
}
pragma[nomagic]
private int firstSpreadIndex(InvokeExpr expr) {
result = min(int i | expr.getArgument(i) instanceof SpreadElement)
}
pragma[nomagic]
private InvokeExpr getAnInvocationWithSpread(DataFlow::SourceNode node, int i) {
result = node.getAnInvocation().asExpr() and
i = firstSpreadIndex(result)
}
private predicate spreadArgumentPassing(TApiNode base, int i, DataFlow::Node spreadArray) {
exists(
DataFlow::Node use, DataFlow::SourceNode pred, int bound, InvokeExpr invoke, int spreadPos
|
use(base, use) and
pred = trackUseNode(use, _, bound, "") and
invoke = getAnInvocationWithSpread(pred, spreadPos) and
spreadArray = invoke.getArgument(spreadPos).(SpreadElement).getOperand().flow() and
i = bound + spreadPos
)
}
/**
* Holds if `rhs` is the right-hand side of a definition of node `nd`.
*/
@@ -1579,6 +1629,9 @@ module API {
/** Gets the edge label for the receiver. */
LabelReceiver receiver() { any() }
/** Gets the edge label for a spread argument passed at index `i`. */
LabelSpreadArgument spreadArgument(int i) { result.getIndex() = i }
/** Gets the `return` edge label. */
LabelReturn return() { any() }
@@ -1628,6 +1681,7 @@ module API {
} or
MkLabelReceiver() or
MkLabelReturn() or
MkLabelSpreadArgument(int index) { index = [0 .. 10] } or
MkLabelDecoratedClass() or
MkLabelDecoratedMember() or
MkLabelDecoratedParameter() or
@@ -1743,6 +1797,21 @@ module API {
override string toString() { result = "getReceiver()" }
}
/** A label representing an array passed as a spread argument at a given index. */
class LabelSpreadArgument extends ApiLabel, MkLabelSpreadArgument {
private int index;
LabelSpreadArgument() { this = MkLabelSpreadArgument(index) }
/** Gets the argument index at which the spread argument appears. */
int getIndex() { result = index }
override string toString() {
// Note: This refers to the internal edge that has no corresponding method on API::Node
result = "getSpreadArgument(" + index + ")"
}
}
/** A label for a function that is a wrapper around another function. */
class LabelForwardingFunction extends ApiLabel, MkLabelForwardingFunction {
override string toString() { result = "getForwardingFunction()" }

View File

@@ -247,7 +247,7 @@ module DOM {
]
|
(
result = documentRef().getAMethodCall(collectionName) or
result = domValueRef().getAMethodCall(collectionName) or
result = DataFlow::globalVarRef(collectionName).getACall()
)
)
@@ -441,10 +441,12 @@ module DOM {
DataFlow::SourceNode domValueRef() {
result = domValueRef(DataFlow::TypeTracker::end())
or
result.hasUnderlyingType("Element")
result.hasUnderlyingType(["Element", "HTMLCollection", "HTMLCollectionOf"])
or
result.hasUnderlyingType(any(string s | s.matches("HTML%Element")))
or
result = documentRef()
or
exists(DataFlow::ClassNode cls |
cls.getASuperClassNode().getALocalSource() =
DataFlow::globalVarRef(any(string s | s.matches("HTML%Element"))) and

View File

@@ -254,6 +254,12 @@ private module Cached {
cached
predicate invocation(DataFlow::SourceNode func, DataFlow::InvokeNode invoke) {
hasLocalSource(invoke.getCalleeNode(), func)
or
exists(ClassDefinition cls, SuperCall call |
hasLocalSource(cls.getSuperClass().flow(), func) and
call.getBinder() = cls.getConstructor().getBody() and
invoke = call.flow()
)
}
/**

View File

@@ -427,16 +427,3 @@ class Chokidar extends FileNameProducer, FileSystemAccess, API::CallNode {
)
}
}
/**
* A call to the [`mkdirp`](https://www.npmjs.com/package/mkdirp) library.
*/
private class Mkdirp extends FileSystemAccess, API::CallNode {
Mkdirp() {
this = API::moduleImport("mkdirp").getACall()
or
this = API::moduleImport("mkdirp").getMember("sync").getACall()
}
override DataFlow::Node getAPathArgument() { result = this.getArgument(0) }
}

View File

@@ -108,6 +108,12 @@ module Http {
* Gets the route handler that sends this expression.
*/
abstract RouteHandler getRouteHandler();
/**
* Gets a header definition associated with this response body, if it they are provided
* by the same call.
*/
HeaderDefinition getAnAssociatedHeaderDefinition() { none() }
}
/**

View File

@@ -213,10 +213,12 @@ module NextJS {
/**
* Gets a folder that contains API endpoints for a Next.js application.
* These API endpoints act as Express-like route-handlers.
* It matches both the Pages Router (`pages/api/`) Next.js 12 or earlier and
* the App Router (`app/api/`) Next.js 13+ structures.
*/
Folder apiFolder() {
result = getANextPackage().getFile().getParentContainer().getFolder("pages").getFolder("api")
or
result =
getANextPackage().getFile().getParentContainer().getFolder(["pages", "app"]).getFolder("api") or
result = apiFolder().getAFolder()
}
@@ -271,4 +273,64 @@ module NextJS {
override string getCredentialsKind() { result = "jwt key" }
}
}
/**
* A route handler for Next.js 13+ App Router API endpoints, which are defined by exporting
* HTTP method functions (like `GET`, `POST`, `PUT`, `DELETE`) from route.js files inside
* the `app/api/` directory.
*/
class NextAppRouteHandler extends DataFlow::FunctionNode, Http::Servers::StandardRouteHandler {
NextAppRouteHandler() {
exists(Module mod |
mod.getFile().getParentContainer() = apiFolder() or
mod.getFile().getStem() = "middleware"
|
this =
mod.getAnExportedValue([any(Http::RequestMethodName m), "middleware"]).getAFunctionValue()
)
}
/**
* Gets the request parameter, which is either a `NextRequest` object (from `next/server`) or a standard web `Request` object.
*/
DataFlow::SourceNode getRequest() { result = this.getParameter(0) }
}
/**
* A source of user-controlled data from a `NextRequest` object (from `next/server`) or a standard web `Request` object
* in a Next.js App Router route handler.
*/
class NextAppRequestSource extends Http::RequestInputAccess {
NextAppRouteHandler handler;
string kind;
NextAppRequestSource() {
(
this =
handler.getRequest().getAMethodCall(["json", "formData", "blob", "arrayBuffer", "text"])
or
this = handler.getRequest().getAPropertyRead("body")
) and
kind = "body"
or
this = handler.getRequest().getAPropertyRead(["url", "nextUrl"]) and
kind = "url"
or
this =
handler
.getRequest()
.getAPropertyRead("nextUrl")
.getAPropertyRead("searchParams")
.getAMemberCall("get") and
kind = "parameter"
or
this = handler.getRequest().getAPropertyRead("headers") and kind = "headers"
}
override string getKind() { result = kind }
override Http::RouteHandler getRouteHandler() { result = handler }
override string getSourceType() { result = "Next.js App Router request" }
}
}

View File

@@ -0,0 +1,103 @@
/**
* Models the `Request` and `Response` objects from the Web standards.
*/
private import javascript
/** Treats `Response` as an entry point for API graphs. */
private class ResponseEntryPoint extends API::EntryPoint {
ResponseEntryPoint() { this = "global.Response" }
override DataFlow::SourceNode getASource() { result = DataFlow::globalVarRef("Response") }
}
/** Treats `Headers` as an entry point for API graphs. */
private class HeadersEntryPoint extends API::EntryPoint {
HeadersEntryPoint() { this = "global.Headers" }
override DataFlow::SourceNode getASource() { result = DataFlow::globalVarRef("Headers") }
}
/**
* A call to the `Response` and `NextResponse` constructor.
*/
private class ResponseCall extends API::InvokeNode {
ResponseCall() {
this = any(ResponseEntryPoint e).getANode().getAnInstantiation() or
this = API::moduleImport("next/server").getMember("NextResponse").getAnInstantiation()
}
}
/**
* A call to the `Headers` constructor.
*/
private class HeadersCall extends API::InvokeNode {
HeadersCall() { this = any(HeadersEntryPoint e).getANode().getAnInstantiation() }
}
/**
* The `headers` in `new Response(body, { headers })`
*/
private class ResponseArgumentHeaders extends Http::HeaderDefinition {
private ResponseCall response;
private API::Node headerNode;
ResponseArgumentHeaders() {
headerNode = response.getParameter(1).getMember("headers") and
this = headerNode.asSink()
}
ResponseCall getResponse() { result = response }
/**
* Gets a call to `new Headers()` that is passed as the headers to this call.
*/
private HeadersCall getHeadersCall() { headerNode.refersTo(result.getReturn()) }
/**
* Gets an object whose properties are interpreted as headers, such as `{'content-type': 'foo'}`.
*/
private API::Node getAPlainHeaderObject() {
// new Response(body, {...})
result = headerNode
or
// new Response(body, new Headers({...}))
result = this.getHeadersCall().getParameter(0)
}
private API::Node getHeaderNode(string headerName) {
exists(string prop |
result = this.getAPlainHeaderObject().getMember(prop) and
headerName = prop.toLowerCase()
)
or
exists(API::CallNode append |
append = this.getHeadersCall().getReturn().getMember(["append", "set"]).getACall() and
headerName = append.getArgument(0).getStringValue().toLowerCase() and
result = append.getParameter(1)
)
}
override predicate defines(string headerName, string headerValue) {
this.getHeaderNode(headerName).getAValueReachingSink().getStringValue() = headerValue
}
override string getAHeaderName() { exists(this.getHeaderNode(result)) }
override Http::RouteHandler getRouteHandler() { none() }
}
/**
* Data passed as the body in `new Response(body, ...)`.
*/
private class ResponseSink extends Http::ResponseSendArgument {
private ResponseCall response;
ResponseSink() { this = response.getArgument(0) }
override Http::RouteHandler getRouteHandler() { none() }
override ResponseArgumentHeaders getAnAssociatedHeaderDefinition() {
result.getResponse() = response
}
}

View File

@@ -47,6 +47,20 @@ private predicate areLibrariesCompatible(
(client = LibraryNames::ws() or client = LibraryNames::websocket())
}
/** Treats `WebSocket` as an entry point for API graphs. */
private class WebSocketEntryPoint extends API::EntryPoint {
WebSocketEntryPoint() { this = "global.WebSocket" }
override DataFlow::SourceNode getASource() { result = DataFlow::globalVarRef("WebSocket") }
}
/** Treats `SockJS` as an entry point for API graphs. */
private class SockJSEntryPoint extends API::EntryPoint {
SockJSEntryPoint() { this = "global.SockJS" }
override DataFlow::SourceNode getASource() { result = DataFlow::globalVarRef("SockJS") }
}
/**
* Provides classes that model WebSockets clients.
*/
@@ -56,7 +70,7 @@ module ClientWebSocket {
/**
* A class that can be used to instantiate a WebSocket instance.
*/
class SocketClass extends DataFlow::SourceNode {
deprecated class SocketClass extends DataFlow::SourceNode {
LibraryName library; // the name of the WebSocket library. Can be one of the libraries defined in `LibraryNames`.
SocketClass() {
@@ -78,13 +92,38 @@ module ClientWebSocket {
LibraryName getLibrary() { result = library }
}
/**
* A class that can be used to instantiate a WebSocket instance.
*/
class WebSocketClass extends API::Node {
LibraryName library; // the name of the WebSocket library. Can be one of the libraries defined in `LibraryNames`.
WebSocketClass() {
this = any(WebSocketEntryPoint e).getANode() and library = websocket()
or
this = API::moduleImport("ws") and library = ws()
or
// the sockjs-client library:https://www.npmjs.com/package/sockjs-client
library = sockjs() and
(
this = API::moduleImport("sockjs-client") or
this = any(SockJSEntryPoint e).getANode()
)
}
/**
* Gets the WebSocket library name.
*/
LibraryName getLibrary() { result = library }
}
/**
* A client WebSocket instance.
*/
class ClientSocket extends EventEmitter::Range, DataFlow::NewNode, ClientRequest::Range {
SocketClass socketClass;
class ClientSocket extends EventEmitter::Range, API::NewNode, ClientRequest::Range {
WebSocketClass socketClass;
ClientSocket() { this = socketClass.getAnInstantiation() }
ClientSocket() { this = socketClass.getAnInvocation() }
/**
* Gets the WebSocket library name.
@@ -115,10 +154,10 @@ module ClientWebSocket {
/**
* A message sent from a WebSocket client.
*/
class SendNode extends EventDispatch::Range, DataFlow::CallNode {
class SendNode extends EventDispatch::Range, API::CallNode {
override ClientSocket emitter;
SendNode() { this = emitter.getAMemberCall("send") }
SendNode() { this = emitter.getReturn().getMember("send").getACall() }
override string getChannel() { result = channelName() }
@@ -145,8 +184,8 @@ module ClientWebSocket {
private DataFlow::FunctionNode getAMessageHandler(
ClientWebSocket::ClientSocket emitter, string methodName
) {
exists(DataFlow::CallNode call |
call = emitter.getAMemberCall(methodName) and
exists(API::CallNode call |
call = emitter.getReturn().getMember(methodName).getACall() and
call.getArgument(0).mayHaveStringValue("message") and
result = call.getCallback(1)
)
@@ -161,7 +200,13 @@ module ClientWebSocket {
WebSocketReceiveNode() {
this = getAMessageHandler(emitter, "addEventListener")
or
this = emitter.getAPropertyWrite("onmessage").getRhs()
this = emitter.getReturn().getMember("onmessage").getAValueReachingSink()
or
exists(DataFlow::MethodCallNode bindCall |
bindCall = emitter.getReturn().getMember("onmessage").getAValueReachingSink() and
bindCall.getMethodName() = "bind" and
this = bindCall.getReceiver().getAFunctionValue()
)
}
override DataFlow::Node getReceivedItem(int i) {
@@ -192,7 +237,7 @@ module ServerWebSocket {
/**
* Gets a server created by a library named `library`.
*/
DataFlow::SourceNode getAServer(LibraryName library) {
deprecated DataFlow::SourceNode getAServer(LibraryName library) {
library = ws() and
result = DataFlow::moduleImport("ws").getAConstructorInvocation("Server")
or
@@ -200,11 +245,22 @@ module ServerWebSocket {
result = DataFlow::moduleImport("sockjs").getAMemberCall("createServer")
}
/**
* Gets a server created by a library named `library`.
*/
API::InvokeNode getAServerInvocation(LibraryName library) {
library = ws() and
result = API::moduleImport("ws").getMember("Server").getAnInvocation()
or
library = sockjs() and
result = API::moduleImport("sockjs").getMember("createServer").getAnInvocation()
}
/**
* Gets a `socket.on("connection", (msg, req) => {})` call.
*/
private DataFlow::CallNode getAConnectionCall(LibraryName library) {
result = getAServer(library).getAMemberCall(EventEmitter::on()) and
result = getAServerInvocation(library).getReturn().getMember(EventEmitter::on()).getACall() and
result.getArgument(0).mayHaveStringValue("connection")
}
@@ -324,15 +380,18 @@ module ServerWebSocket {
result = this.getCallback(1).getParameter(0)
}
}
/**
* A data flow node representing data received from a client, viewed as remote user input.
*/
private class ReceivedItemAsRemoteFlow extends RemoteFlowSource {
ReceivedItemAsRemoteFlow() { this = any(ReceiveNode rercv).getReceivedItem(_) }
override string getSourceType() { result = "WebSocket client data" }
override predicate isUserControlledObject() { any() }
}
}
/**
* A data flow node representing data received from a client or server, viewed as remote user input.
*/
private class ReceivedItemAsRemoteFlow extends RemoteFlowSource {
ReceivedItemAsRemoteFlow() {
this = any(ClientWebSocket::ReceiveNode rercv).getReceivedItem(_) or
this = any(ServerWebSocket::ReceiveNode rercv).getReceivedItem(_)
}
override string getSourceType() { result = "WebSocket transmitted data" }
override predicate isUserControlledObject() { any() }
}

View File

@@ -12,3 +12,5 @@ private import Sets
private import Strings
private import DynamicImportStep
private import UrlSearchParams
private import TypedArrays
private import Decoders

View File

@@ -0,0 +1,28 @@
private import javascript
private import semmle.javascript.dataflow.FlowSummary
private import semmle.javascript.dataflow.InferredTypes
private import semmle.javascript.dataflow.internal.DataFlowPrivate as Private
private import FlowSummaryUtil
private class TextDecoderEntryPoint extends API::EntryPoint {
TextDecoderEntryPoint() { this = "global.TextDecoder" }
override DataFlow::SourceNode getASource() { result = DataFlow::globalVarRef("TextDecoder") }
}
pragma[nomagic]
API::Node textDecoderConstructorRef() { result = any(TextDecoderEntryPoint e).getANode() }
class Decode extends SummarizedCallable {
Decode() { this = "TextDecoder#decode" }
override InstanceCall getACall() {
result = textDecoderConstructorRef().getInstance().getMember("decode").getACall()
}
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
preservesValue = false and
input = "Argument[0].ArrayElement" and
output = "ReturnValue"
}
}

View File

@@ -99,3 +99,19 @@ class StringSplitHashOrQuestionMark extends SummarizedCallable {
)
}
}
class StringFromCharCode extends SummarizedCallable {
StringFromCharCode() { this = "String#fromCharCode" }
override DataFlow::CallNode getACall() {
result = DataFlow::globalVarRef("String").getAPropertyRead("fromCharCode").getACall()
}
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
preservesValue = false and
(
input = "Argument[0..]" and
output = "ReturnValue"
)
}
}

View File

@@ -0,0 +1,89 @@
private import javascript
private import semmle.javascript.dataflow.FlowSummary
private import semmle.javascript.dataflow.InferredTypes
private import semmle.javascript.dataflow.internal.DataFlowPrivate as Private
private import FlowSummaryUtil
private class TypedArrayEntryPoint extends API::EntryPoint {
TypedArrayEntryPoint() { this = "global.Uint8Array" }
override DataFlow::SourceNode getASource() { result = DataFlow::globalVarRef("Uint8Array") }
}
pragma[nomagic]
API::Node typedArrayConstructorRef() { result = any(TypedArrayEntryPoint e).getANode() }
class TypedArrayConstructorSummary extends SummarizedCallable {
TypedArrayConstructorSummary() { this = "TypedArray constructor" }
override DataFlow::InvokeNode getACall() {
result = typedArrayConstructorRef().getAnInstantiation()
}
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
preservesValue = true and
input = "Argument[0].ArrayElement" and
output = "ReturnValue.ArrayElement"
}
}
class BufferTypedArray extends DataFlow::AdditionalFlowStep {
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
exists(DataFlow::PropRead p |
p = typedArrayConstructorRef().getInstance().getMember("buffer").asSource() and
pred = p.getBase() and
succ = p
)
}
}
class TypedArraySet extends SummarizedCallable {
TypedArraySet() { this = "TypedArray#set" }
override InstanceCall getACall() {
result = typedArrayConstructorRef().getInstance().getMember("set").getACall()
}
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
preservesValue = true and
input = "Argument[0].ArrayElement" and
output = "Argument[this].ArrayElement"
}
}
class TypedArraySubarray extends SummarizedCallable {
TypedArraySubarray() { this = "TypedArray#subarray" }
override InstanceCall getACall() { result.getMethodName() = "subarray" }
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
preservesValue = true and
input = "Argument[this].ArrayElement" and
output = "ReturnValue.ArrayElement"
}
}
private class ArrayBufferEntryPoint extends API::EntryPoint {
ArrayBufferEntryPoint() { this = ["global.ArrayBuffer", "global.SharedArrayBuffer"] }
override DataFlow::SourceNode getASource() {
result = DataFlow::globalVarRef(["ArrayBuffer", "SharedArrayBuffer"])
}
}
pragma[nomagic]
API::Node arrayBufferConstructorRef() { result = any(ArrayBufferEntryPoint a).getANode() }
class TransferLike extends SummarizedCallable {
TransferLike() { this = "ArrayBuffer#transfer" }
override InstanceCall getACall() {
result.getMethodName() = ["transfer", "transferToFixedLength"]
}
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
preservesValue = true and
input = "Argument[this].ArrayElement" and
output = "ReturnValue.ArrayElement"
}
}

View File

@@ -32,11 +32,11 @@ module ReflectedXss {
* Gets a HeaderDefinition that defines a XSS safe content-type for `send`.
*/
Http::HeaderDefinition getAXssSafeHeaderDefinition(Http::ResponseSendArgument send) {
exists(Http::RouteHandler h |
send.getRouteHandler() = h and
result = xssSafeContentTypeHeader(h)
|
// The HeaderDefinition affects a response sent at `send`.
isSafeContentTypeHeader(result) and
(
result = send.getAnAssociatedHeaderDefinition()
or
result = send.getRouteHandler().getAResponseHeader("content-type") and
headerAffects(result, send)
)
}
@@ -54,16 +54,22 @@ module ReflectedXss {
]
}
/**
* Holds if `h` may send a response with a content type that is safe for XSS.
*/
Http::HeaderDefinition xssSafeContentTypeHeader(Http::RouteHandler h) {
result = h.getAResponseHeader("content-type") and
not exists(string tp | result.defines("content-type", tp) |
private predicate isSafeContentTypeHeader(Http::HeaderDefinition header) {
header.getAHeaderName() = "content-type" and
not exists(string tp | header.defines("content-type", tp) |
tp.toLowerCase().matches(xssUnsafeContentType() + "%")
)
}
/**
* DEPRECATED. Use `getAXssSafeHeaderDefinition` instead.
* Holds if `h` may send a response with a content type that is safe for XSS.
*/
deprecated Http::HeaderDefinition xssSafeContentTypeHeader(Http::RouteHandler h) {
result = h.getAResponseHeader("content-type") and
isSafeContentTypeHeader(result)
}
/**
* Holds if a header set in `header` is likely to affect a response sent at `sender`.
*/
@@ -80,6 +86,8 @@ module ReflectedXss {
dominatingHeader.getBasicBlock().(ReachableBasicBlock).dominates(sender.getBasicBlock())
)
)
or
header = sender.getAnAssociatedHeaderDefinition()
}
bindingset[headerBlock]

View File

@@ -1,3 +1,14 @@
## 1.5.3
### Minor Analysis Improvements
* Data passed to the [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) constructor is now treated as a sink for `js/reflected-xss`.
* Slightly improved detection of DOM element references, leading to XSS results being detected in more cases.
### Bug Fixes
* Fixed a bug that would prevent extraction of `tsconfig.json` files when it contained an array literal with a trailing comma.
## 1.5.2
### Bug Fixes

View File

@@ -5,10 +5,12 @@
* @kind problem
* @problem.severity warning
* @id js/useless-expression
* @tags maintainability
* @tags quality
* maintainability
* correctness
* external/cwe/cwe-480
* external/cwe/cwe-561
* useless-code
* @precision very-high
*/

View File

@@ -30,30 +30,26 @@ private int powerOfTwo() {
* Gets a node that has value 2^n for some n.
*/
private DataFlow::Node isPowerOfTwo() {
exists(DataFlow::Node prev |
prev.getIntValue() = powerOfTwo()
or
// Getting around the 32 bit ints in QL. These are some hex values of the form 0x10000000
prev.asExpr().(NumberLiteral).getValue() =
["281474976710656", "17592186044416", "1099511627776", "68719476736", "4294967296"]
|
result = prev.getASuccessor*()
)
result.getIntValue() = powerOfTwo()
or
// Getting around the 32 bit ints in QL. These are some hex values of the form 0x10000000
result.asExpr().(NumberLiteral).getValue() =
["281474976710656", "17592186044416", "1099511627776", "68719476736", "4294967296"]
or
result = isPowerOfTwo().getASuccessor()
}
/**
* Gets a node that has value (2^n)-1 for some n.
*/
private DataFlow::Node isPowerOfTwoMinusOne() {
exists(DataFlow::Node prev |
prev.getIntValue() = powerOfTwo() - 1
or
// Getting around the 32 bit ints in QL. These are some hex values of the form 0xfffffff
prev.asExpr().(NumberLiteral).getValue() =
["281474976710655", "17592186044415", "1099511627775", "68719476735", "4294967295"]
|
result = prev.getASuccessor*()
)
result.getIntValue() = powerOfTwo() - 1
or
// Getting around the 32 bit ints in QL. These are some hex values of the form 0xfffffff
result.asExpr().(NumberLiteral).getValue() =
["281474976710655", "17592186044415", "1099511627775", "68719476735", "4294967295"]
or
result = isPowerOfTwoMinusOne().getASuccessor()
}
/**

View File

@@ -0,0 +1,10 @@
import javascript
API::NewNode getAWebSocketInstance() { result instanceof ClientWebSocket::ClientSocket }
from DataFlow::Node handler
where
handler = getAWebSocketInstance().getReturn().getMember("onmessage").asSource()
or
handler = getAWebSocketInstance().getAPropertyWrite("onmessage").getRhs()
select handler, "This is a WebSocket onmessage handler."

View File

@@ -0,0 +1,10 @@
## 1.5.3
### Minor Analysis Improvements
* Data passed to the [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) constructor is now treated as a sink for `js/reflected-xss`.
* Slightly improved detection of DOM element references, leading to XSS results being detected in more cases.
### Bug Fixes
* Fixed a bug that would prevent extraction of `tsconfig.json` files when it contained an array literal with a trailing comma.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.5.2
lastReleaseVersion: 1.5.3

View File

@@ -1,5 +1,5 @@
name: codeql/javascript-queries
version: 1.5.2
version: 1.5.3
groups:
- javascript
- queries

View File

@@ -9,3 +9,21 @@ function f() {
lib.m1({
...f()
})
function getArgs() {
return [
'x', /* def=moduleImport("something").getMember("exports").getMember("m2").getSpreadArgument(0).getArrayElement() */
'y', /* def=moduleImport("something").getMember("exports").getMember("m2").getSpreadArgument(0).getArrayElement() */
]
}
lib.m2(...getArgs());
function f3() {
return [
'x', /* def=moduleImport("something").getMember("exports").getMember("m3").getSpreadArgument(1).getArrayElement() */
'y', /* def=moduleImport("something").getMember("exports").getMember("m3").getSpreadArgument(1).getArrayElement() */
]
}
lib.m3.bind(undefined, 1)(...f3());

View File

@@ -7,20 +7,26 @@ test_documentRef
test_locationRef
| customization.js:3:3:3:14 | doc.location |
test_domValueRef
| customization.js:2:13:2:31 | customGetDocument() |
| customization.js:3:3:3:14 | doc.location |
| customization.js:4:3:4:20 | doc.getElementById |
| customization.js:4:3:4:28 | doc.get ... 'test') |
| event-handler-receiver.html:4:20:4:19 | this |
| event-handler-receiver.js:1:1:1:8 | document |
| event-handler-receiver.js:1:1:1:23 | documen ... entById |
| event-handler-receiver.js:1:1:1:32 | documen ... my-id') |
| event-handler-receiver.js:1:44:1:43 | this |
| event-handler-receiver.js:2:3:2:17 | this.parentNode |
| event-handler-receiver.js:5:1:5:8 | document |
| event-handler-receiver.js:5:1:5:23 | documen ... entById |
| event-handler-receiver.js:5:1:5:32 | documen ... my-id') |
| event-handler-receiver.js:5:60:5:59 | this |
| event-handler-receiver.js:6:3:6:17 | this.parentNode |
| nameditems.js:1:1:1:8 | document |
| nameditems.js:1:1:1:23 | documen ... entById |
| nameditems.js:1:1:1:30 | documen ... ('foo') |
| nameditems.js:1:1:2:19 | documen ... em('x') |
| querySelectorAll.js:2:5:2:12 | document |
| querySelectorAll.js:2:5:2:29 | documen ... ctorAll |
| querySelectorAll.js:2:5:2:36 | documen ... ('foo') |
| querySelectorAll.js:2:46:2:48 | elm |

View File

@@ -31,14 +31,14 @@ sensitiveAction
| tst.js:23:1:23:25 | require ... .exit() |
| tst.js:24:1:24:21 | global. ... .exit() |
sensitiveExpr
| tst.js:1:1:1:8 | password |
| tst.js:2:1:2:8 | PassWord |
| tst.js:3:1:3:21 | myPassw ... eartext |
| tst.js:4:1:4:10 | x.password |
| tst.js:5:1:5:11 | getPassword |
| tst.js:5:1:5:13 | getPassword() |
| tst.js:6:1:6:13 | x.getPassword |
| tst.js:6:1:6:15 | x.getPassword() |
| tst.js:7:1:7:15 | get("password") |
| tst.js:8:1:8:17 | x.get("password") |
| tst.js:21:1:21:6 | secret |
| tst.js:1:1:1:8 | password | password |
| tst.js:2:1:2:8 | PassWord | password |
| tst.js:3:1:3:21 | myPassw ... eartext | password |
| tst.js:4:1:4:10 | x.password | password |
| tst.js:5:1:5:11 | getPassword | password |
| tst.js:5:1:5:13 | getPassword() | password |
| tst.js:6:1:6:13 | x.getPassword | password |
| tst.js:6:1:6:15 | x.getPassword() | password |
| tst.js:7:1:7:15 | get("password") | password |
| tst.js:8:1:8:17 | x.get("password") | password |
| tst.js:21:1:21:6 | secret | secret |

View File

@@ -20,4 +20,4 @@ query predicate processTermination(NodeJSLib::ProcessTermination term) { any() }
query predicate sensitiveAction(SensitiveAction ac) { any() }
query predicate sensitiveExpr(SensitiveNode e) { any() }
query predicate sensitiveExpr(SensitiveNode e, string kind) { kind = e.getClassification() }

View File

@@ -0,0 +1,2 @@
query: tests.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,11 +1,11 @@
password;
PassWord;
myPasswordInCleartext;
x.password;
getPassword();
x.getPassword();
get("password");
x.get("password");
password; // $ cleartextPasswordExpr sensitiveExpr=password
PassWord; // $ cleartextPasswordExpr sensitiveExpr=password
myPasswordInCleartext; // $ cleartextPasswordExpr sensitiveExpr=password
x.password; // $ cleartextPasswordExpr sensitiveExpr=password
getPassword(); // $ cleartextPasswordExpr sensitiveExpr=password
x.getPassword(); // $ cleartextPasswordExpr sensitiveExpr=password
get("password"); // $ cleartextPasswordExpr sensitiveExpr=password
x.get("password"); // $ cleartextPasswordExpr sensitiveExpr=password
hashed_password;
password_hashed;
@@ -15,13 +15,13 @@ hashedPassword;
var exit = require('exit');
var e = process.exit;
e();
exit();
e(); // $ processTermination sensitiveAction
exit(); // $ processTermination sensitiveAction
secret;
secret; // $ sensitiveExpr=secret
require("process").exit();
global.process.exit();
require("process").exit(); // $ processTermination sensitiveAction
global.process.exit(); // $ processTermination sensitiveAction
get("https://example.com/news?password=true")
get("https://username:password@example.com")

View File

@@ -35,11 +35,23 @@ legacyDataFlowDifference
| spread.js:4:15:4:22 | source() | spread.js:18:8:18:8 | y | only flow with NEW data flow library |
| spread.js:4:15:4:22 | source() | spread.js:24:8:24:8 | y | only flow with NEW data flow library |
| tst.js:2:13:2:20 | source() | tst.js:17:10:17:10 | a | only flow with OLD data flow library |
| typed-arrays.js:2:13:2:20 | source() | typed-arrays.js:5:10:5:10 | y | only flow with NEW data flow library |
| typed-arrays.js:2:13:2:20 | source() | typed-arrays.js:7:10:7:17 | y.buffer | only flow with NEW data flow library |
| typed-arrays.js:2:13:2:20 | source() | typed-arrays.js:11:10:11:12 | arr | only flow with NEW data flow library |
| typed-arrays.js:2:13:2:20 | source() | typed-arrays.js:15:10:15:10 | z | only flow with NEW data flow library |
| typed-arrays.js:2:13:2:20 | source() | typed-arrays.js:18:10:18:12 | sub | only flow with NEW data flow library |
| typed-arrays.js:2:13:2:20 | source() | typed-arrays.js:42:10:42:30 | typedAr ... ring(y) | only flow with NEW data flow library |
| typed-arrays.js:2:13:2:20 | source() | typed-arrays.js:48:10:48:12 | str | only flow with NEW data flow library |
| typed-arrays.js:2:13:2:20 | source() | typed-arrays.js:52:10:52:13 | str2 | only flow with NEW data flow library |
| use-use-after-implicit-read.js:7:17:7:24 | source() | use-use-after-implicit-read.js:15:10:15:10 | x | only flow with NEW data flow library |
consistencyIssue
| nested-props.js:20 | expected an alert, but found none | NOT OK - but not found | Consistency |
| stringification-read-steps.js:17 | expected an alert, but found none | NOT OK | Consistency |
| stringification-read-steps.js:25 | expected an alert, but found none | NOT OK | Consistency |
| typed-arrays.js:23 | expected an alert, but found none | NOT OK -- Should be flagged but it is not. | Consistency |
| typed-arrays.js:28 | expected an alert, but found none | NOT OK -- Should be flagged but it is not. | Consistency |
| typed-arrays.js:32 | expected an alert, but found none | NOT OK -- Should be flagged but it is not. | Consistency |
| typed-arrays.js:36 | expected an alert, but found none | NOT OK -- Should be flagged but it is not. | Consistency |
flow
| access-path-sanitizer.js:2:18:2:25 | source() | access-path-sanitizer.js:4:8:4:12 | obj.x |
| addexpr.js:4:10:4:17 | source() | addexpr.js:7:8:7:8 | x |
@@ -325,6 +337,14 @@ flow
| tst.js:87:22:87:29 | source() | tst.js:90:14:90:25 | taintedValue |
| tst.js:93:22:93:29 | source() | tst.js:96:14:96:25 | taintedValue |
| tst.js:93:22:93:29 | source() | tst.js:97:14:97:26 | map.get(true) |
| typed-arrays.js:2:13:2:20 | source() | typed-arrays.js:5:10:5:10 | y |
| typed-arrays.js:2:13:2:20 | source() | typed-arrays.js:7:10:7:17 | y.buffer |
| typed-arrays.js:2:13:2:20 | source() | typed-arrays.js:11:10:11:12 | arr |
| typed-arrays.js:2:13:2:20 | source() | typed-arrays.js:15:10:15:10 | z |
| typed-arrays.js:2:13:2:20 | source() | typed-arrays.js:18:10:18:12 | sub |
| typed-arrays.js:2:13:2:20 | source() | typed-arrays.js:42:10:42:30 | typedAr ... ring(y) |
| typed-arrays.js:2:13:2:20 | source() | typed-arrays.js:48:10:48:12 | str |
| typed-arrays.js:2:13:2:20 | source() | typed-arrays.js:52:10:52:13 | str2 |
| use-use-after-implicit-read.js:7:17:7:24 | source() | use-use-after-implicit-read.js:8:10:8:17 | captured |
| use-use-after-implicit-read.js:7:17:7:24 | source() | use-use-after-implicit-read.js:15:10:15:10 | x |
| xml.js:5:18:5:25 | source() | xml.js:8:14:8:17 | text |

View File

@@ -0,0 +1,53 @@
function test() {
let x = source();
let y = new Uint8Array(x);
sink(y); // NOT OK
sink(y.buffer); // NOT OK
sink(y.length);
var arr = new Uint8Array(y.buffer, y.byteOffset, y.byteLength);
sink(arr); // NOT OK
const z = new Uint8Array([1, 2, 3]);
z.set(y, 3);
sink(z); // NOT OK
const sub = y.subarray(1, 3)
sink(sub); // NOT OK
const buffer = new ArrayBuffer(8);
const view = new Uint8Array(buffer);
view.set(x, 3);
sink(buffer); // NOT OK -- Should be flagged but it is not.
const sharedBuffer = new SharedArrayBuffer(8);
const view1 = new Uint8Array(sharedBuffer);
view1.set(x, 3);
sink(sharedBuffer); // NOT OK -- Should be flagged but it is not.
const transfered = buffer.transfer();
const transferedView = new Uint8Array(transfered);
sink(transferedView); // NOT OK -- Should be flagged but it is not.
const transfered2 = buffer.transferToFixedLength();
const transferedView2 = new Uint8Array(transfered2);
sink(transferedView2); // NOT OK -- Should be flagged but it is not.
var typedArrayToString = (function () {
return function (a) { return String.fromCharCode.apply(null, a); };
})();
sink(typedArrayToString(y)); // NOT OK
let str = '';
for (let i = 0; i < y.length; i++)
str += String.fromCharCode(y[i]);
sink(str); // NOT OK
const decoder = new TextDecoder('utf-8');
const str2 = decoder.decode(y);
sink(str2); // NOT OK
}

View File

@@ -0,0 +1,74 @@
import { MyWebSocket, MySockJS, myWebSocketInstance, mySockJSInstance } from './browser.js';
(function () {
const socket = new MyWebSocket('ws://localhost:9080'); // $ clientSocket
socket.addEventListener('open', function (event) {
socket.send('Hi from browser!'); // $ clientSend
});
socket.addEventListener('message', function (event) {
console.log('Message from server ', event.data); // $ remoteFlow
}); // $ clientReceive
socket.onmessage = function (event) {
console.log("Message from server 2", event.data); // $ remoteFlow
}; // $ clientReceive
})();
(function () {
var sock = new MySockJS('http://0.0.0.0:9999/echo'); // $ clientSocket
sock.onopen = function () {
sock.send('test'); // $ clientSend
};
sock.onmessage = function (e) {
console.log('message', e.data); // $ remoteFlow
sock.close();
}; // $ clientReceive
sock.addEventListener('message', function (event) {
console.log('Using addEventListener ', event.data); // $ remoteFlow
}); // $ clientReceive
})();
(function () {
myWebSocketInstance.addEventListener('open', function (event) {
myWebSocketInstance.send('Hi from browser!'); // $ clientSend
});
myWebSocketInstance.addEventListener('message', function (event) {
console.log('Message from server ', event.data); // $ remoteFlow
}); // $ clientReceive
myWebSocketInstance.onmessage = function (event) {
console.log("Message from server 2", event.data); // $ remoteFlow
}; // $ clientReceive
})();
(function () {
mySockJSInstance.onopen = function () {
mySockJSInstance.send('test'); // $ clientSend
};
mySockJSInstance.onmessage = function (e) {
console.log('message', e.data); // $ remoteFlow
mySockJSInstance.close();
}; // $ clientReceive
mySockJSInstance.addEventListener('message', function (event) {
console.log('Using addEventListener ', event.data); // $ remoteFlow
}); // $ clientReceive
})();
const recv_message = function (e) {
console.log('Received message:', e.data); // $ remoteFlow
}; // $ clientReceive
(function () {
myWebSocketInstance.onmessage = recv_message.bind(this);
})();

View File

@@ -1,32 +1,37 @@
(function () {
const socket = new WebSocket('ws://localhost:8080');
const socket = new WebSocket('ws://localhost:8080'); // $clientSocket
socket.addEventListener('open', function (event) {
socket.send('Hi from browser!');
socket.send('Hi from browser!'); // $clientSend
});
socket.addEventListener('message', function (event) {
console.log('Message from server ', event.data);
});
console.log('Message from server ', event.data); // $ remoteFlow
}); // $clientReceive
socket.onmessage = function (event) {
console.log("Message from server 2", event.data)
};
console.log("Message from server 2", event.data); // $ remoteFlow
}; // $clientReceive
})();
(function () {
var sock = new SockJS('http://0.0.0.0:9999/echo');
var sock = new SockJS('http://0.0.0.0:9999/echo'); // $clientSocket
sock.onopen = function () {
sock.send('test');
sock.send('test'); // $clientSend
};
sock.onmessage = function (e) {
console.log('message', e.data);
console.log('message', e.data); // $ remoteFlow
sock.close();
};
}; // $clientReceive
sock.addEventListener('message', function (event) {
console.log('Using addEventListener ', event.data);
});
})
console.log('Using addEventListener ', event.data); // $ remoteFlow
}); // $clientReceive
})();
export const MyWebSocket = WebSocket;
export const MySockJS = SockJS;
export const myWebSocketInstance = new WebSocket('ws://localhost:8080'); // $ clientSocket
export const mySockJSInstance = new SockJS('http://0.0.0.0:9999/echo'); // $ clientSocket

View File

@@ -0,0 +1,23 @@
const { MyWebSocketWS, myWebSocketWSInstance } = require('./client.js');
(function () {
const ws = new MyWebSocketWS('ws://example.org'); // $ clientSocket
ws.on('open', function open() {
ws.send('Hi from client!'); // $ clientSend
});
ws.on('message', function incoming(data) { // $ remoteFlow
console.log(data);
}); // $ clientReceive
})();
(function () {
myWebSocketWSInstance.on('open', function open() {
myWebSocketWSInstance.send('Hi from client!'); // $ clientSend
});
myWebSocketWSInstance.on('message', function incoming(data) { // $ remoteFlow
console.log(data);
}); // $ clientReceive
})();

View File

@@ -1,13 +1,16 @@
(function () {
const WebSocket = require('ws');
const WebSocket = require('ws');
const ws = new WebSocket('ws://example.org');
(function () {
const ws = new WebSocket('ws://example.org'); // $clientSocket
ws.on('open', function open() {
ws.send('Hi from client!');
ws.send('Hi from client!'); // $clientSend
});
ws.on('message', function incoming(data) {
ws.on('message', function incoming(data) { // $ remoteFlow
console.log(data);
});
})();
}); // $clientReceive
})();
module.exports.MyWebSocketWS = require('ws');
module.exports.myWebSocketWSInstance = new WebSocket('ws://example.org'); // $ clientSocket

View File

@@ -0,0 +1,23 @@
const { MyWebSocketServer, myWebSocketServerInstance } = require('./server.js');
(function () {
const wss = new MyWebSocketServer({ port: 8080 });
wss.on('connection', function connection(ws) { // $ serverSocket
ws.on('message', function incoming(message) { // $ remoteFlow
console.log('received: %s', message);
}); // $ serverReceive
ws.send('Hi from server!'); // $ serverSend
});
})();
(function () {
myWebSocketServerInstance.on('connection', function connection(ws) { // $ serverSocket
ws.on('message', function incoming(message) { // $ remoteFlow
console.log('received: %s', message);
}); // $ serverReceive
ws.send('Hi from server!'); // $ serverSend
});
})();

View File

@@ -1,13 +1,16 @@
(function () {
const WebSocket = require('ws');
const WebSocket = require('ws');
(function () {
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', function connection(ws) {
ws.on('message', function incoming(message) {
wss.on('connection', function connection(ws) { // $serverSocket
ws.on('message', function incoming(message) { // $remoteFlow
console.log('received: %s', message);
});
}); // $serverReceive
ws.send('Hi from server!');
ws.send('Hi from server!'); // $serverSend
});
})();
})();
module.exports.MyWebSocketServer = require('ws').Server;
module.exports.myWebSocketServerInstance = new WebSocket.Server({ port: 8080 });

View File

@@ -5,11 +5,11 @@ const sockjs = require('sockjs');
const app = express();
const server = http.createServer(app);
const sockjs_echo = sockjs.createServer({});
sockjs_echo.on('connection', function (conn) {
conn.on('data', function (message) {
sockjs_echo.on('connection', function (conn) { // $serverSocket
conn.on('data', function (message) { // $remoteFlow
var data = JSON.parse(message);
conn.write(JSON.stringify(eval(data.test)));
});
conn.write(JSON.stringify(eval(data.test))); // $serverSend
}); // $serverReceive
});
sockjs_echo.installHandlers(server, { prefix: '/echo' });

View File

@@ -1,35 +1,139 @@
clientSocket
| browser.js:2:17:2:52 | new Web ... :8080') |
| browser.js:19:13:19:50 | new Soc ... /echo') |
| client.js:4:13:4:45 | new Web ... e.org') |
clientReceive
| browser-custom.js:10:37:12:2 | functio ... Flow\\n\\t} |
| browser-custom.js:14:21:16:2 | functio ... Flow\\n\\t} |
| browser-custom.js:26:19:29:2 | functio ... e();\\n\\t} |
| browser-custom.js:31:35:33:2 | functio ... Flow\\n\\t} |
| browser-custom.js:42:53:44:5 | functio ... w\\n } |
| browser-custom.js:46:37:48:5 | functio ... w\\n } |
| browser-custom.js:57:34:60:5 | functio ... ;\\n } |
| browser-custom.js:62:50:64:5 | functio ... w\\n } |
| browser-custom.js:68:22:70:1 | functio ... eFlow\\n} |
| browser.js:8:37:10:2 | functio ... Flow\\n\\t} |
| browser.js:12:21:14:2 | functio ... Flow\\n\\t} |
| browser.js:24:19:27:2 | functio ... e();\\n\\t} |
| browser.js:29:35:31:2 | functio ... Flow\\n\\t} |
| client-custom.js:10:19:12:2 | functio ... ta);\\n\\t} |
| client-custom.js:20:38:22:2 | functio ... ta);\\n\\t} |
| client.js:10:19:12:2 | functio ... ta);\\n\\t} |
clientSend
| browser-custom.js:7:3:7:33 | socket. ... wser!') |
| browser-custom.js:23:3:23:19 | sock.send('test') |
| browser-custom.js:39:9:39:52 | myWebSo ... wser!') |
| browser-custom.js:54:9:54:37 | mySockJ ... 'test') |
| browser.js:5:3:5:33 | socket. ... wser!') |
| browser.js:21:3:21:19 | sock.send('test') |
| client-custom.js:7:3:7:28 | ws.send ... ient!') |
| client-custom.js:17:3:17:47 | myWebSo ... ient!') |
| client.js:7:3:7:28 | ws.send ... ient!') |
clientReceive
| browser.js:8:37:10:2 | functio ... ta);\\n\\t} |
| browser.js:12:21:14:2 | functio ... ata)\\n\\t} |
| browser.js:24:19:27:2 | functio ... e();\\n\\t} |
| browser.js:29:35:31:2 | functio ... ta);\\n\\t} |
| client.js:10:19:12:2 | functio ... ta);\\n\\t} |
serverSocket
| server.js:6:43:6:44 | ws |
| sockjs.js:8:40:8:43 | conn |
serverSend
| server.js:11:3:11:28 | ws.send ... rver!') |
| sockjs.js:11:9:11:51 | conn.wr ... test))) |
serverReceive
| server.js:7:3:9:4 | ws.on(' ... );\\n\\t\\t}) |
| sockjs.js:9:5:12:6 | conn.on ... \\n }) |
clientSocket
| browser-custom.js:4:17:4:54 | new MyW ... :9080') |
| browser-custom.js:21:13:21:52 | new MyS ... /echo') |
| browser.js:2:17:2:52 | new Web ... :8080') |
| browser.js:19:13:19:50 | new Soc ... /echo') |
| browser.js:36:36:36:71 | new Web ... :8080') |
| browser.js:37:33:37:70 | new Soc ... /echo') |
| client-custom.js:4:13:4:49 | new MyW ... e.org') |
| client.js:4:13:4:45 | new Web ... e.org') |
| client.js:16:40:16:72 | new Web ... e.org') |
flowSteps
| browser-custom.js:1:10:1:20 | MyWebSocket | browser-custom.js:1:10:1:20 | MyWebSocket |
| browser-custom.js:1:23:1:30 | MySockJS | browser-custom.js:1:23:1:30 | MySockJS |
| browser-custom.js:1:33:1:51 | myWebSocketInstance | browser-custom.js:1:33:1:51 | myWebSocketInstance |
| browser-custom.js:1:54:1:69 | mySockJSInstance | browser-custom.js:1:54:1:69 | mySockJSInstance |
| browser-custom.js:7:15:7:32 | 'Hi from browser!' | server-custom.js:7:38:7:44 | message |
| browser-custom.js:7:15:7:32 | 'Hi from browser!' | server-custom.js:17:38:17:44 | message |
| browser-custom.js:7:15:7:32 | 'Hi from browser!' | server.js:7:38:7:44 | message |
| browser-custom.js:23:13:23:18 | 'test' | sockjs.js:9:31:9:37 | message |
| browser-custom.js:39:34:39:51 | 'Hi from browser!' | server-custom.js:7:38:7:44 | message |
| browser-custom.js:39:34:39:51 | 'Hi from browser!' | server-custom.js:17:38:17:44 | message |
| browser-custom.js:39:34:39:51 | 'Hi from browser!' | server.js:7:38:7:44 | message |
| browser-custom.js:54:31:54:36 | 'test' | sockjs.js:9:31:9:37 | message |
| browser.js:5:15:5:32 | 'Hi from browser!' | server-custom.js:7:38:7:44 | message |
| browser.js:5:15:5:32 | 'Hi from browser!' | server-custom.js:17:38:17:44 | message |
| browser.js:5:15:5:32 | 'Hi from browser!' | server.js:7:38:7:44 | message |
| browser.js:21:13:21:18 | 'test' | sockjs.js:9:31:9:37 | message |
| client-custom.js:7:11:7:27 | 'Hi from client!' | server-custom.js:7:38:7:44 | message |
| client-custom.js:7:11:7:27 | 'Hi from client!' | server-custom.js:17:38:17:44 | message |
| client-custom.js:7:11:7:27 | 'Hi from client!' | server.js:7:38:7:44 | message |
| client-custom.js:17:30:17:46 | 'Hi from client!' | server-custom.js:7:38:7:44 | message |
| client-custom.js:17:30:17:46 | 'Hi from client!' | server-custom.js:17:38:17:44 | message |
| client-custom.js:17:30:17:46 | 'Hi from client!' | server.js:7:38:7:44 | message |
| client.js:7:11:7:27 | 'Hi from client!' | server-custom.js:7:38:7:44 | message |
| client.js:7:11:7:27 | 'Hi from client!' | server-custom.js:17:38:17:44 | message |
| client.js:7:11:7:27 | 'Hi from client!' | server.js:7:38:7:44 | message |
| client.js:15:32:15:44 | require('ws') | client-custom.js:1:9:1:21 | MyWebSocketWS |
| client.js:16:40:16:72 | new Web ... e.org') | client-custom.js:1:24:1:44 | myWebSo ... nstance |
| server-custom.js:11:11:11:27 | 'Hi from server!' | browser-custom.js:11:39:11:48 | event.data |
| server-custom.js:11:11:11:27 | 'Hi from server!' | browser-custom.js:15:40:15:49 | event.data |
| server-custom.js:11:11:11:27 | 'Hi from server!' | browser-custom.js:43:45:43:54 | event.data |
| server-custom.js:11:11:11:27 | 'Hi from server!' | browser-custom.js:47:46:47:55 | event.data |
| server-custom.js:11:11:11:27 | 'Hi from server!' | browser-custom.js:69:38:69:43 | e.data |
| server-custom.js:11:11:11:27 | 'Hi from server!' | browser.js:9:39:9:48 | event.data |
| server-custom.js:11:11:11:27 | 'Hi from server!' | browser.js:13:40:13:49 | event.data |
| server-custom.js:11:11:11:27 | 'Hi from server!' | client-custom.js:10:37:10:40 | data |
| server-custom.js:11:11:11:27 | 'Hi from server!' | client-custom.js:20:56:20:59 | data |
| server-custom.js:11:11:11:27 | 'Hi from server!' | client.js:10:37:10:40 | data |
| server-custom.js:21:11:21:27 | 'Hi from server!' | browser-custom.js:11:39:11:48 | event.data |
| server-custom.js:21:11:21:27 | 'Hi from server!' | browser-custom.js:15:40:15:49 | event.data |
| server-custom.js:21:11:21:27 | 'Hi from server!' | browser-custom.js:43:45:43:54 | event.data |
| server-custom.js:21:11:21:27 | 'Hi from server!' | browser-custom.js:47:46:47:55 | event.data |
| server-custom.js:21:11:21:27 | 'Hi from server!' | browser-custom.js:69:38:69:43 | e.data |
| server-custom.js:21:11:21:27 | 'Hi from server!' | browser.js:9:39:9:48 | event.data |
| server-custom.js:21:11:21:27 | 'Hi from server!' | browser.js:13:40:13:49 | event.data |
| server-custom.js:21:11:21:27 | 'Hi from server!' | client-custom.js:10:37:10:40 | data |
| server-custom.js:21:11:21:27 | 'Hi from server!' | client-custom.js:20:56:20:59 | data |
| server-custom.js:21:11:21:27 | 'Hi from server!' | client.js:10:37:10:40 | data |
| server.js:11:11:11:27 | 'Hi from server!' | browser-custom.js:11:39:11:48 | event.data |
| server.js:11:11:11:27 | 'Hi from server!' | browser-custom.js:15:40:15:49 | event.data |
| server.js:11:11:11:27 | 'Hi from server!' | browser-custom.js:43:45:43:54 | event.data |
| server.js:11:11:11:27 | 'Hi from server!' | browser-custom.js:47:46:47:55 | event.data |
| server.js:11:11:11:27 | 'Hi from server!' | browser-custom.js:69:38:69:43 | e.data |
| server.js:11:11:11:27 | 'Hi from server!' | browser.js:9:39:9:48 | event.data |
| server.js:11:11:11:27 | 'Hi from server!' | browser.js:13:40:13:49 | event.data |
| server.js:11:11:11:27 | 'Hi from server!' | client-custom.js:10:37:10:40 | data |
| server.js:11:11:11:27 | 'Hi from server!' | client-custom.js:20:56:20:59 | data |
| server.js:11:11:11:27 | 'Hi from server!' | client.js:10:37:10:40 | data |
| server.js:15:36:15:55 | require('ws').Server | server-custom.js:1:9:1:25 | MyWebSocketServer |
| server.js:16:44:16:79 | new Web ... 8080 }) | server-custom.js:1:28:1:52 | myWebSo ... nstance |
| sockjs.js:11:20:11:50 | JSON.st ... .test)) | browser-custom.js:27:26:27:31 | e.data |
| sockjs.js:11:20:11:50 | JSON.st ... .test)) | browser-custom.js:32:42:32:51 | event.data |
| sockjs.js:11:20:11:50 | JSON.st ... .test)) | browser-custom.js:58:32:58:37 | e.data |
| sockjs.js:11:20:11:50 | JSON.st ... .test)) | browser-custom.js:63:48:63:57 | event.data |
| sockjs.js:11:20:11:50 | JSON.st ... .test)) | browser.js:25:26:25:31 | e.data |
| sockjs.js:11:20:11:50 | JSON.st ... .test)) | browser.js:30:42:30:51 | event.data |
remoteFlow
| browser-custom.js:11:39:11:48 | event.data |
| browser-custom.js:15:40:15:49 | event.data |
| browser-custom.js:27:26:27:31 | e.data |
| browser-custom.js:32:42:32:51 | event.data |
| browser-custom.js:43:45:43:54 | event.data |
| browser-custom.js:47:46:47:55 | event.data |
| browser-custom.js:58:32:58:37 | e.data |
| browser-custom.js:63:48:63:57 | event.data |
| browser-custom.js:69:38:69:43 | e.data |
| browser.js:9:39:9:48 | event.data |
| browser.js:13:40:13:49 | event.data |
| browser.js:25:26:25:31 | e.data |
| browser.js:30:42:30:51 | event.data |
| client-custom.js:10:37:10:40 | data |
| client-custom.js:20:56:20:59 | data |
| client.js:10:37:10:40 | data |
| server-custom.js:7:38:7:44 | message |
| server-custom.js:17:38:17:44 | message |
| server.js:7:38:7:44 | message |
| sockjs.js:9:31:9:37 | message |
serverReceive
| server-custom.js:7:3:9:4 | ws.on(' ... );\\n\\t\\t}) |
| server-custom.js:17:3:19:4 | ws.on(' ... );\\n\\t\\t}) |
| server.js:7:3:9:4 | ws.on(' ... );\\n\\t\\t}) |
| sockjs.js:9:5:12:6 | conn.on ... \\n }) |
serverSend
| server-custom.js:11:3:11:28 | ws.send ... rver!') |
| server-custom.js:21:3:21:28 | ws.send ... rver!') |
| server.js:11:3:11:28 | ws.send ... rver!') |
| sockjs.js:11:9:11:51 | conn.wr ... test))) |
serverSocket
| server-custom.js:6:43:6:44 | ws |
| server-custom.js:16:65:16:66 | ws |
| server.js:6:43:6:44 | ws |
| sockjs.js:8:40:8:43 | conn |

View File

@@ -0,0 +1,2 @@
query: test.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -52,6 +52,19 @@
| handlebars.js:11:32:11:39 | filePath | handlebars.js:29:46:29:60 | req.params.path | handlebars.js:11:32:11:39 | filePath | This path depends on a $@. | handlebars.js:29:46:29:60 | req.params.path | user-provided value |
| handlebars.js:15:25:15:32 | filePath | handlebars.js:43:15:43:29 | req.params.path | handlebars.js:15:25:15:32 | filePath | This path depends on a $@. | handlebars.js:43:15:43:29 | req.params.path | user-provided value |
| hapi.js:15:44:15:51 | filepath | hapi.js:14:30:14:51 | request ... ilepath | hapi.js:15:44:15:51 | filepath | This path depends on a $@. | hapi.js:14:30:14:51 | request ... ilepath | user-provided value |
| make-dir.js:9:25:9:28 | file | make-dir.js:7:18:7:31 | req.query.file | make-dir.js:9:25:9:28 | file | This path depends on a $@. | make-dir.js:7:18:7:31 | req.query.file | user-provided value |
| make-dir.js:10:23:10:26 | file | make-dir.js:7:18:7:31 | req.query.file | make-dir.js:10:23:10:26 | file | This path depends on a $@. | make-dir.js:7:18:7:31 | req.query.file | user-provided value |
| mkdirp.js:11:12:11:18 | dirPath | mkdirp.js:9:42:9:59 | req.query.filename | mkdirp.js:11:12:11:18 | dirPath | This path depends on a $@. | mkdirp.js:9:42:9:59 | req.query.filename | user-provided value |
| mkdirp.js:12:17:12:23 | dirPath | mkdirp.js:9:42:9:59 | req.query.filename | mkdirp.js:12:17:12:23 | dirPath | This path depends on a $@. | mkdirp.js:9:42:9:59 | req.query.filename | user-provided value |
| mkdirp.js:13:23:13:29 | dirPath | mkdirp.js:9:42:9:59 | req.query.filename | mkdirp.js:13:23:13:29 | dirPath | This path depends on a $@. | mkdirp.js:9:42:9:59 | req.query.filename | user-provided value |
| mkdirp.js:14:19:14:25 | dirPath | mkdirp.js:9:42:9:59 | req.query.filename | mkdirp.js:14:19:14:25 | dirPath | This path depends on a $@. | mkdirp.js:9:42:9:59 | req.query.filename | user-provided value |
| mkdirp.js:15:19:15:25 | dirPath | mkdirp.js:9:42:9:59 | req.query.filename | mkdirp.js:15:19:15:25 | dirPath | This path depends on a $@. | mkdirp.js:9:42:9:59 | req.query.filename | user-provided value |
| mkdirp.js:16:23:16:29 | dirPath | mkdirp.js:9:42:9:59 | req.query.filename | mkdirp.js:16:23:16:29 | dirPath | This path depends on a $@. | mkdirp.js:9:42:9:59 | req.query.filename | user-provided value |
| mkdirp.js:17:25:17:31 | dirPath | mkdirp.js:9:42:9:59 | req.query.filename | mkdirp.js:17:25:17:31 | dirPath | This path depends on a $@. | mkdirp.js:9:42:9:59 | req.query.filename | user-provided value |
| mkdirp.js:18:25:18:31 | dirPath | mkdirp.js:9:42:9:59 | req.query.filename | mkdirp.js:18:25:18:31 | dirPath | This path depends on a $@. | mkdirp.js:9:42:9:59 | req.query.filename | user-provided value |
| mkdirp.js:19:29:19:35 | dirPath | mkdirp.js:9:42:9:59 | req.query.filename | mkdirp.js:19:29:19:35 | dirPath | This path depends on a $@. | mkdirp.js:9:42:9:59 | req.query.filename | user-provided value |
| mkdirp.js:20:29:20:35 | dirPath | mkdirp.js:9:42:9:59 | req.query.filename | mkdirp.js:20:29:20:35 | dirPath | This path depends on a $@. | mkdirp.js:9:42:9:59 | req.query.filename | user-provided value |
| mkdirp.js:21:23:21:29 | dirPath | mkdirp.js:9:42:9:59 | req.query.filename | mkdirp.js:21:23:21:29 | dirPath | This path depends on a $@. | mkdirp.js:9:42:9:59 | req.query.filename | user-provided value |
| more-fs-extra.js:10:15:10:22 | filename | more-fs-extra.js:8:26:8:33 | req.body | more-fs-extra.js:10:15:10:22 | filename | This path depends on a $@. | more-fs-extra.js:8:26:8:33 | req.body | user-provided value |
| more-fs-extra.js:11:11:11:18 | filename | more-fs-extra.js:8:26:8:33 | req.body | more-fs-extra.js:11:11:11:18 | filename | This path depends on a $@. | more-fs-extra.js:8:26:8:33 | req.body | user-provided value |
| more-fs-extra.js:12:14:12:21 | filename | more-fs-extra.js:8:26:8:33 | req.body | more-fs-extra.js:12:14:12:21 | filename | This path depends on a $@. | more-fs-extra.js:8:26:8:33 | req.body | user-provided value |
@@ -140,6 +153,8 @@
| normalizedPaths.js:408:19:408:60 | pathMod ... t('/')) | normalizedPaths.js:408:38:408:48 | req.query.x | normalizedPaths.js:408:19:408:60 | pathMod ... t('/')) | This path depends on a $@. | normalizedPaths.js:408:38:408:48 | req.query.x | user-provided value |
| normalizedPaths.js:415:19:415:22 | path | normalizedPaths.js:412:35:412:45 | req.query.x | normalizedPaths.js:415:19:415:22 | path | This path depends on a $@. | normalizedPaths.js:412:35:412:45 | req.query.x | user-provided value |
| normalizedPaths.js:426:21:426:24 | path | normalizedPaths.js:412:35:412:45 | req.query.x | normalizedPaths.js:426:21:426:24 | path | This path depends on a $@. | normalizedPaths.js:412:35:412:45 | req.query.x | user-provided value |
| open.js:9:10:9:13 | file | open.js:7:18:7:31 | req.query.file | open.js:9:10:9:13 | file | This path depends on a $@. | open.js:7:18:7:31 | req.query.file | user-provided value |
| open.js:10:13:10:16 | file | open.js:7:18:7:31 | req.query.file | open.js:10:13:10:16 | file | This path depends on a $@. | open.js:7:18:7:31 | req.query.file | user-provided value |
| other-fs-libraries.js:11:19:11:22 | path | other-fs-libraries.js:9:24:9:30 | req.url | other-fs-libraries.js:11:19:11:22 | path | This path depends on a $@. | other-fs-libraries.js:9:24:9:30 | req.url | user-provided value |
| other-fs-libraries.js:12:27:12:30 | path | other-fs-libraries.js:9:24:9:30 | req.url | other-fs-libraries.js:12:27:12:30 | path | This path depends on a $@. | other-fs-libraries.js:9:24:9:30 | req.url | user-provided value |
| other-fs-libraries.js:13:24:13:27 | path | other-fs-libraries.js:9:24:9:30 | req.url | other-fs-libraries.js:13:24:13:27 | path | This path depends on a $@. | other-fs-libraries.js:9:24:9:30 | req.url | user-provided value |
@@ -168,6 +183,26 @@
| prettier.js:11:44:11:44 | p | prettier.js:6:13:6:13 | p | prettier.js:11:44:11:44 | p | This path depends on a $@. | prettier.js:6:13:6:13 | p | user-provided value |
| pupeteer.js:9:28:9:34 | tainted | pupeteer.js:5:28:5:53 | parseTo ... t).name | pupeteer.js:9:28:9:34 | tainted | This path depends on a $@. | pupeteer.js:5:28:5:53 | parseTo ... t).name | user-provided value |
| pupeteer.js:13:37:13:43 | tainted | pupeteer.js:5:28:5:53 | parseTo ... t).name | pupeteer.js:13:37:13:43 | tainted | This path depends on a $@. | pupeteer.js:5:28:5:53 | parseTo ... t).name | user-provided value |
| rimraf.js:10:17:10:20 | path | rimraf.js:8:22:8:29 | req.body | rimraf.js:10:17:10:20 | path | This path depends on a $@. | rimraf.js:8:22:8:29 | req.body | user-provided value |
| rimraf.js:11:23:11:26 | path | rimraf.js:8:22:8:29 | req.body | rimraf.js:11:23:11:26 | path | This path depends on a $@. | rimraf.js:8:22:8:29 | req.body | user-provided value |
| rimraf.js:12:19:12:22 | path | rimraf.js:8:22:8:29 | req.body | rimraf.js:12:19:12:22 | path | This path depends on a $@. | rimraf.js:8:22:8:29 | req.body | user-provided value |
| rimraf.js:13:25:13:28 | path | rimraf.js:8:22:8:29 | req.body | rimraf.js:13:25:13:28 | path | This path depends on a $@. | rimraf.js:8:22:8:29 | req.body | user-provided value |
| rimraf.js:14:24:14:27 | path | rimraf.js:8:22:8:29 | req.body | rimraf.js:14:24:14:27 | path | This path depends on a $@. | rimraf.js:8:22:8:29 | req.body | user-provided value |
| rimraf.js:15:23:15:26 | path | rimraf.js:8:22:8:29 | req.body | rimraf.js:15:23:15:26 | path | This path depends on a $@. | rimraf.js:8:22:8:29 | req.body | user-provided value |
| rimraf.js:16:25:16:28 | path | rimraf.js:8:22:8:29 | req.body | rimraf.js:16:25:16:28 | path | This path depends on a $@. | rimraf.js:8:22:8:29 | req.body | user-provided value |
| rimraf.js:17:19:17:22 | path | rimraf.js:8:22:8:29 | req.body | rimraf.js:17:19:17:22 | path | This path depends on a $@. | rimraf.js:8:22:8:29 | req.body | user-provided value |
| rimraf.js:18:24:18:27 | path | rimraf.js:8:22:8:29 | req.body | rimraf.js:18:24:18:27 | path | This path depends on a $@. | rimraf.js:8:22:8:29 | req.body | user-provided value |
| rimraf.js:19:23:19:26 | path | rimraf.js:8:22:8:29 | req.body | rimraf.js:19:23:19:26 | path | This path depends on a $@. | rimraf.js:8:22:8:29 | req.body | user-provided value |
| rimraf.js:20:26:20:29 | path | rimraf.js:8:22:8:29 | req.body | rimraf.js:20:26:20:29 | path | This path depends on a $@. | rimraf.js:8:22:8:29 | req.body | user-provided value |
| rimraf.js:21:20:21:23 | path | rimraf.js:8:22:8:29 | req.body | rimraf.js:21:20:21:23 | path | This path depends on a $@. | rimraf.js:8:22:8:29 | req.body | user-provided value |
| rimraf.js:22:25:22:28 | path | rimraf.js:8:22:8:29 | req.body | rimraf.js:22:25:22:28 | path | This path depends on a $@. | rimraf.js:8:22:8:29 | req.body | user-provided value |
| rimraf.js:23:24:23:27 | path | rimraf.js:8:22:8:29 | req.body | rimraf.js:23:24:23:27 | path | This path depends on a $@. | rimraf.js:8:22:8:29 | req.body | user-provided value |
| rimraf.js:24:23:24:26 | path | rimraf.js:8:22:8:29 | req.body | rimraf.js:24:23:24:26 | path | This path depends on a $@. | rimraf.js:8:22:8:29 | req.body | user-provided value |
| rimraf.js:25:28:25:31 | path | rimraf.js:8:22:8:29 | req.body | rimraf.js:25:28:25:31 | path | This path depends on a $@. | rimraf.js:8:22:8:29 | req.body | user-provided value |
| rimraf.js:26:27:26:30 | path | rimraf.js:8:22:8:29 | req.body | rimraf.js:26:27:26:30 | path | This path depends on a $@. | rimraf.js:8:22:8:29 | req.body | user-provided value |
| rimraf.js:27:22:27:25 | path | rimraf.js:8:22:8:29 | req.body | rimraf.js:27:22:27:25 | path | This path depends on a $@. | rimraf.js:8:22:8:29 | req.body | user-provided value |
| rimraf.js:28:18:28:21 | path | rimraf.js:8:22:8:29 | req.body | rimraf.js:28:18:28:21 | path | This path depends on a $@. | rimraf.js:8:22:8:29 | req.body | user-provided value |
| rimraf.js:29:23:29:26 | path | rimraf.js:8:22:8:29 | req.body | rimraf.js:29:23:29:26 | path | This path depends on a $@. | rimraf.js:8:22:8:29 | req.body | user-provided value |
| sharedlib-repro.js:22:18:22:25 | filepath | sharedlib-repro.js:13:22:13:43 | req.par ... spaceId | sharedlib-repro.js:22:18:22:25 | filepath | This path depends on a $@. | sharedlib-repro.js:13:22:13:43 | req.par ... spaceId | user-provided value |
| tainted-access-paths.js:8:19:8:22 | path | tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:8:19:8:22 | path | This path depends on a $@. | tainted-access-paths.js:6:24:6:30 | req.url | user-provided value |
| tainted-access-paths.js:12:19:12:25 | obj.sub | tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:12:19:12:25 | obj.sub | This path depends on a $@. | tainted-access-paths.js:6:24:6:30 | req.url | user-provided value |
@@ -370,6 +405,23 @@ edges
| handlebars.js:43:15:43:29 | req.params.path | handlebars.js:13:73:13:80 | filePath | provenance | |
| hapi.js:14:19:14:51 | filepath | hapi.js:15:44:15:51 | filepath | provenance | |
| hapi.js:14:30:14:51 | request ... ilepath | hapi.js:14:19:14:51 | filepath | provenance | |
| make-dir.js:7:11:7:31 | file | make-dir.js:9:25:9:28 | file | provenance | |
| make-dir.js:7:11:7:31 | file | make-dir.js:10:23:10:26 | file | provenance | |
| make-dir.js:7:18:7:31 | req.query.file | make-dir.js:7:11:7:31 | file | provenance | |
| mkdirp.js:9:11:9:76 | dirPath | mkdirp.js:11:12:11:18 | dirPath | provenance | |
| mkdirp.js:9:11:9:76 | dirPath | mkdirp.js:12:17:12:23 | dirPath | provenance | |
| mkdirp.js:9:11:9:76 | dirPath | mkdirp.js:13:23:13:29 | dirPath | provenance | |
| mkdirp.js:9:11:9:76 | dirPath | mkdirp.js:14:19:14:25 | dirPath | provenance | |
| mkdirp.js:9:11:9:76 | dirPath | mkdirp.js:15:19:15:25 | dirPath | provenance | |
| mkdirp.js:9:11:9:76 | dirPath | mkdirp.js:16:23:16:29 | dirPath | provenance | |
| mkdirp.js:9:11:9:76 | dirPath | mkdirp.js:17:25:17:31 | dirPath | provenance | |
| mkdirp.js:9:11:9:76 | dirPath | mkdirp.js:18:25:18:31 | dirPath | provenance | |
| mkdirp.js:9:11:9:76 | dirPath | mkdirp.js:19:29:19:35 | dirPath | provenance | |
| mkdirp.js:9:11:9:76 | dirPath | mkdirp.js:20:29:20:35 | dirPath | provenance | |
| mkdirp.js:9:11:9:76 | dirPath | mkdirp.js:21:23:21:29 | dirPath | provenance | |
| mkdirp.js:9:21:9:76 | path.jo ... ltDir') | mkdirp.js:9:11:9:76 | dirPath | provenance | |
| mkdirp.js:9:42:9:59 | req.query.filename | mkdirp.js:9:42:9:75 | req.que ... ultDir' | provenance | |
| mkdirp.js:9:42:9:75 | req.que ... ultDir' | mkdirp.js:9:21:9:76 | path.jo ... ltDir') | provenance | Config |
| more-fs-extra.js:8:11:8:22 | { filename } | more-fs-extra.js:8:13:8:20 | filename | provenance | Config |
| more-fs-extra.js:8:11:8:33 | filename | more-fs-extra.js:10:15:10:22 | filename | provenance | |
| more-fs-extra.js:8:11:8:33 | filename | more-fs-extra.js:11:11:11:18 | filename | provenance | |
@@ -541,6 +593,9 @@ edges
| normalizedPaths.js:412:7:412:46 | path | normalizedPaths.js:426:21:426:24 | path | provenance | |
| normalizedPaths.js:412:14:412:46 | pathMod ... uery.x) | normalizedPaths.js:412:7:412:46 | path | provenance | |
| normalizedPaths.js:412:35:412:45 | req.query.x | normalizedPaths.js:412:14:412:46 | pathMod ... uery.x) | provenance | Config |
| open.js:7:11:7:31 | file | open.js:9:10:9:13 | file | provenance | |
| open.js:7:11:7:31 | file | open.js:10:13:10:16 | file | provenance | |
| open.js:7:18:7:31 | req.query.file | open.js:7:11:7:31 | file | provenance | |
| other-fs-libraries.js:9:7:9:48 | path | other-fs-libraries.js:11:19:11:22 | path | provenance | |
| other-fs-libraries.js:9:7:9:48 | path | other-fs-libraries.js:12:27:12:30 | path | provenance | |
| other-fs-libraries.js:9:7:9:48 | path | other-fs-libraries.js:13:24:13:27 | path | provenance | |
@@ -594,6 +649,29 @@ edges
| pupeteer.js:5:9:5:71 | tainted | pupeteer.js:13:37:13:43 | tainted | provenance | |
| pupeteer.js:5:19:5:71 | "dir/" ... t.data" | pupeteer.js:5:9:5:71 | tainted | provenance | |
| pupeteer.js:5:28:5:53 | parseTo ... t).name | pupeteer.js:5:19:5:71 | "dir/" ... t.data" | provenance | Config |
| rimraf.js:8:11:8:18 | { path } | rimraf.js:8:13:8:16 | path | provenance | Config |
| rimraf.js:8:11:8:29 | path | rimraf.js:10:17:10:20 | path | provenance | |
| rimraf.js:8:11:8:29 | path | rimraf.js:11:23:11:26 | path | provenance | |
| rimraf.js:8:11:8:29 | path | rimraf.js:12:19:12:22 | path | provenance | |
| rimraf.js:8:11:8:29 | path | rimraf.js:13:25:13:28 | path | provenance | |
| rimraf.js:8:11:8:29 | path | rimraf.js:14:24:14:27 | path | provenance | |
| rimraf.js:8:11:8:29 | path | rimraf.js:15:23:15:26 | path | provenance | |
| rimraf.js:8:11:8:29 | path | rimraf.js:16:25:16:28 | path | provenance | |
| rimraf.js:8:11:8:29 | path | rimraf.js:17:19:17:22 | path | provenance | |
| rimraf.js:8:11:8:29 | path | rimraf.js:18:24:18:27 | path | provenance | |
| rimraf.js:8:11:8:29 | path | rimraf.js:19:23:19:26 | path | provenance | |
| rimraf.js:8:11:8:29 | path | rimraf.js:20:26:20:29 | path | provenance | |
| rimraf.js:8:11:8:29 | path | rimraf.js:21:20:21:23 | path | provenance | |
| rimraf.js:8:11:8:29 | path | rimraf.js:22:25:22:28 | path | provenance | |
| rimraf.js:8:11:8:29 | path | rimraf.js:23:24:23:27 | path | provenance | |
| rimraf.js:8:11:8:29 | path | rimraf.js:24:23:24:26 | path | provenance | |
| rimraf.js:8:11:8:29 | path | rimraf.js:25:28:25:31 | path | provenance | |
| rimraf.js:8:11:8:29 | path | rimraf.js:26:27:26:30 | path | provenance | |
| rimraf.js:8:11:8:29 | path | rimraf.js:27:22:27:25 | path | provenance | |
| rimraf.js:8:11:8:29 | path | rimraf.js:28:18:28:21 | path | provenance | |
| rimraf.js:8:11:8:29 | path | rimraf.js:29:23:29:26 | path | provenance | |
| rimraf.js:8:13:8:16 | path | rimraf.js:8:11:8:29 | path | provenance | |
| rimraf.js:8:22:8:29 | req.body | rimraf.js:8:11:8:18 | { path } | provenance | |
| sharedlib-repro.js:13:22:13:43 | req.par ... spaceId | sharedlib-repro.js:21:27:21:34 | filepath | provenance | |
| sharedlib-repro.js:21:27:21:34 | filepath | sharedlib-repro.js:22:18:22:25 | filepath | provenance | |
| tainted-access-paths.js:6:7:6:48 | path | tainted-access-paths.js:8:19:8:22 | path | provenance | |
@@ -876,6 +954,25 @@ nodes
| hapi.js:14:19:14:51 | filepath | semmle.label | filepath |
| hapi.js:14:30:14:51 | request ... ilepath | semmle.label | request ... ilepath |
| hapi.js:15:44:15:51 | filepath | semmle.label | filepath |
| make-dir.js:7:11:7:31 | file | semmle.label | file |
| make-dir.js:7:18:7:31 | req.query.file | semmle.label | req.query.file |
| make-dir.js:9:25:9:28 | file | semmle.label | file |
| make-dir.js:10:23:10:26 | file | semmle.label | file |
| mkdirp.js:9:11:9:76 | dirPath | semmle.label | dirPath |
| mkdirp.js:9:21:9:76 | path.jo ... ltDir') | semmle.label | path.jo ... ltDir') |
| mkdirp.js:9:42:9:59 | req.query.filename | semmle.label | req.query.filename |
| mkdirp.js:9:42:9:75 | req.que ... ultDir' | semmle.label | req.que ... ultDir' |
| mkdirp.js:11:12:11:18 | dirPath | semmle.label | dirPath |
| mkdirp.js:12:17:12:23 | dirPath | semmle.label | dirPath |
| mkdirp.js:13:23:13:29 | dirPath | semmle.label | dirPath |
| mkdirp.js:14:19:14:25 | dirPath | semmle.label | dirPath |
| mkdirp.js:15:19:15:25 | dirPath | semmle.label | dirPath |
| mkdirp.js:16:23:16:29 | dirPath | semmle.label | dirPath |
| mkdirp.js:17:25:17:31 | dirPath | semmle.label | dirPath |
| mkdirp.js:18:25:18:31 | dirPath | semmle.label | dirPath |
| mkdirp.js:19:29:19:35 | dirPath | semmle.label | dirPath |
| mkdirp.js:20:29:20:35 | dirPath | semmle.label | dirPath |
| mkdirp.js:21:23:21:29 | dirPath | semmle.label | dirPath |
| more-fs-extra.js:8:11:8:22 | { filename } | semmle.label | { filename } |
| more-fs-extra.js:8:11:8:33 | filename | semmle.label | filename |
| more-fs-extra.js:8:13:8:20 | filename | semmle.label | filename |
@@ -1073,6 +1170,10 @@ nodes
| normalizedPaths.js:412:35:412:45 | req.query.x | semmle.label | req.query.x |
| normalizedPaths.js:415:19:415:22 | path | semmle.label | path |
| normalizedPaths.js:426:21:426:24 | path | semmle.label | path |
| open.js:7:11:7:31 | file | semmle.label | file |
| open.js:7:18:7:31 | req.query.file | semmle.label | req.query.file |
| open.js:9:10:9:13 | file | semmle.label | file |
| open.js:10:13:10:16 | file | semmle.label | file |
| other-fs-libraries.js:9:7:9:48 | path | semmle.label | path |
| other-fs-libraries.js:9:14:9:37 | url.par ... , true) | semmle.label | url.par ... , true) |
| other-fs-libraries.js:9:14:9:43 | url.par ... ).query | semmle.label | url.par ... ).query |
@@ -1133,6 +1234,30 @@ nodes
| pupeteer.js:5:28:5:53 | parseTo ... t).name | semmle.label | parseTo ... t).name |
| pupeteer.js:9:28:9:34 | tainted | semmle.label | tainted |
| pupeteer.js:13:37:13:43 | tainted | semmle.label | tainted |
| rimraf.js:8:11:8:18 | { path } | semmle.label | { path } |
| rimraf.js:8:11:8:29 | path | semmle.label | path |
| rimraf.js:8:13:8:16 | path | semmle.label | path |
| rimraf.js:8:22:8:29 | req.body | semmle.label | req.body |
| rimraf.js:10:17:10:20 | path | semmle.label | path |
| rimraf.js:11:23:11:26 | path | semmle.label | path |
| rimraf.js:12:19:12:22 | path | semmle.label | path |
| rimraf.js:13:25:13:28 | path | semmle.label | path |
| rimraf.js:14:24:14:27 | path | semmle.label | path |
| rimraf.js:15:23:15:26 | path | semmle.label | path |
| rimraf.js:16:25:16:28 | path | semmle.label | path |
| rimraf.js:17:19:17:22 | path | semmle.label | path |
| rimraf.js:18:24:18:27 | path | semmle.label | path |
| rimraf.js:19:23:19:26 | path | semmle.label | path |
| rimraf.js:20:26:20:29 | path | semmle.label | path |
| rimraf.js:21:20:21:23 | path | semmle.label | path |
| rimraf.js:22:25:22:28 | path | semmle.label | path |
| rimraf.js:23:24:23:27 | path | semmle.label | path |
| rimraf.js:24:23:24:26 | path | semmle.label | path |
| rimraf.js:25:28:25:31 | path | semmle.label | path |
| rimraf.js:26:27:26:30 | path | semmle.label | path |
| rimraf.js:27:22:27:25 | path | semmle.label | path |
| rimraf.js:28:18:28:21 | path | semmle.label | path |
| rimraf.js:29:23:29:26 | path | semmle.label | path |
| sharedlib-repro.js:13:22:13:43 | req.par ... spaceId | semmle.label | req.par ... spaceId |
| sharedlib-repro.js:21:27:21:34 | filepath | semmle.label | filepath |
| sharedlib-repro.js:22:18:22:25 | filepath | semmle.label | filepath |

View File

@@ -0,0 +1,11 @@
import { makeDirectory, makeDirectorySync } from 'make-dir';
const express = require('express');
const app = express();
app.get('/makedir', async (req, res) => {
const file = req.query.file; // $ Source
await makeDirectory(file); // $ Alert
makeDirectorySync(file); // $ Alert
});

View File

@@ -0,0 +1,22 @@
const express = require('express');
const mkdirp = require('mkdirp');
const path = require('path');
const app = express();
app.use(express.json());
app.post('/foo', async (req, res) => {
const dirPath = path.join(__dirname, req.query.filename || 'defaultDir'); // $ Source
mkdirp(dirPath); // $ Alert
mkdirp.sync(dirPath); // $ Alert
mkdirp.nativeSync(dirPath); // $ Alert
mkdirp.native(dirPath); // $ Alert
mkdirp.manual(dirPath); // $ Alert
mkdirp.manualSync(dirPath); // $ Alert
mkdirp.mkdirpNative(dirPath); // $ Alert
mkdirp.mkdirpManual(dirPath); // $ Alert
mkdirp.mkdirpManualSync(dirPath); // $ Alert
mkdirp.mkdirpNativeSync(dirPath); // $ Alert
mkdirp.mkdirpSync(dirPath); // $ Alert
});

View File

@@ -0,0 +1,11 @@
import open, {openApp, apps} from 'open';
const express = require('express');
const app = express();
app.get('/open', (req, res) => {
const file = req.query.file; // $ Source
open(file); // $ Alert
openApp(file); // $ Alert
});

View File

@@ -0,0 +1,30 @@
const express = require('express');
const rimraf = require('rimraf');
const app = express();
app.use(express.json());
app.post('/rmsync', async (req, res) => {
const { path } = req.body; // $ Source
rimraf.sync(path); // $ Alert
rimraf.rimrafSync(path); // $ Alert
rimraf.native(path); // $ Alert
await rimraf.native(path); // $ Alert
rimraf.native.sync(path); // $ Alert
rimraf.nativeSync(path); // $ Alert
await rimraf.manual(path); // $ Alert
rimraf.manual(path); // $ Alert
rimraf.manual.sync(path); // $ Alert
rimraf.manualSync(path); // $ Alert
await rimraf.windows(path); // $ Alert
rimraf.windows(path); // $ Alert
rimraf.windows.sync(path); // $ Alert
rimraf.windowsSync(path); // $ Alert
rimraf.moveRemove(path); // $ Alert
rimraf.moveRemove.sync(path); // $ Alert
rimraf.moveRemoveSync(path); // $ Alert
rimraf.posixSync(path); // $ Alert
rimraf.posix(path); // $ Alert
rimraf.posix.sync(path); // $ Alert
});

View File

@@ -53,6 +53,7 @@
| dates.js:57:31:57:101 | `Time i ... aint)}` | dates.js:54:36:54:55 | window.location.hash | dates.js:57:31:57:101 | `Time i ... aint)}` | Cross-site scripting vulnerability due to $@. | dates.js:54:36:54:55 | window.location.hash | user-provided value |
| dates.js:59:31:59:87 | `Time i ... aint)}` | dates.js:54:36:54:55 | window.location.hash | dates.js:59:31:59:87 | `Time i ... aint)}` | Cross-site scripting vulnerability due to $@. | dates.js:54:36:54:55 | window.location.hash | user-provided value |
| dates.js:61:31:61:88 | `Time i ... aint)}` | dates.js:54:36:54:55 | window.location.hash | dates.js:61:31:61:88 | `Time i ... aint)}` | Cross-site scripting vulnerability due to $@. | dates.js:54:36:54:55 | window.location.hash | user-provided value |
| dom.js:4:20:4:30 | window.name | dom.js:4:20:4:30 | window.name | dom.js:4:20:4:30 | window.name | Cross-site scripting vulnerability due to $@. | dom.js:4:20:4:30 | window.name | user-provided value |
| dragAndDrop.ts:15:25:15:28 | html | dragAndDrop.ts:8:18:8:50 | dataTra ... /html') | dragAndDrop.ts:15:25:15:28 | html | Cross-site scripting vulnerability due to $@. | dragAndDrop.ts:8:18:8:50 | dataTra ... /html') | user-provided value |
| dragAndDrop.ts:24:23:24:57 | e.dataT ... /html') | dragAndDrop.ts:24:23:24:57 | e.dataT ... /html') | dragAndDrop.ts:24:23:24:57 | e.dataT ... /html') | Cross-site scripting vulnerability due to $@. | dragAndDrop.ts:24:23:24:57 | e.dataT ... /html') | user-provided value |
| dragAndDrop.ts:29:19:29:53 | e.dataT ... /html') | dragAndDrop.ts:29:19:29:53 | e.dataT ... /html') | dragAndDrop.ts:29:19:29:53 | e.dataT ... /html') | Cross-site scripting vulnerability due to $@. | dragAndDrop.ts:29:19:29:53 | e.dataT ... /html') | user-provided value |
@@ -937,6 +938,7 @@ nodes
| dates.js:61:31:61:88 | `Time i ... aint)}` | semmle.label | `Time i ... aint)}` |
| dates.js:61:42:61:86 | dayjs.s ... (taint) | semmle.label | dayjs.s ... (taint) |
| dates.js:61:81:61:85 | taint | semmle.label | taint |
| dom.js:4:20:4:30 | window.name | semmle.label | window.name |
| dragAndDrop.ts:8:11:8:50 | html | semmle.label | html |
| dragAndDrop.ts:8:18:8:50 | dataTra ... /html') | semmle.label | dataTra ... /html') |
| dragAndDrop.ts:15:25:15:28 | html | semmle.label | html |

View File

@@ -138,6 +138,7 @@ nodes
| dates.js:61:31:61:88 | `Time i ... aint)}` | semmle.label | `Time i ... aint)}` |
| dates.js:61:42:61:86 | dayjs.s ... (taint) | semmle.label | dayjs.s ... (taint) |
| dates.js:61:81:61:85 | taint | semmle.label | taint |
| dom.js:4:20:4:30 | window.name | semmle.label | window.name |
| dragAndDrop.ts:8:11:8:50 | html | semmle.label | html |
| dragAndDrop.ts:8:18:8:50 | dataTra ... /html') | semmle.label | dataTra ... /html') |
| dragAndDrop.ts:15:25:15:28 | html | semmle.label | html |

View File

@@ -0,0 +1,5 @@
function t1() {
const elm = document.getElementById("foo");
const e2 = elm.getElementsByTagName("bar")[0];
e2.innerHTML = window.name; // $ Alert
}

View File

@@ -27,6 +27,14 @@
| ReflectedXssContentTypes.js:39:13:39:35 | "FOO: " ... rams.id | ReflectedXssContentTypes.js:39:23:39:35 | req.params.id | ReflectedXssContentTypes.js:39:13:39:35 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to a $@. | ReflectedXssContentTypes.js:39:23:39:35 | req.params.id | user-provided value |
| ReflectedXssContentTypes.js:70:12:70:34 | "FOO: " ... rams.id | ReflectedXssContentTypes.js:70:22:70:34 | req.params.id | ReflectedXssContentTypes.js:70:12:70:34 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to a $@. | ReflectedXssContentTypes.js:70:22:70:34 | req.params.id | user-provided value |
| ReflectedXssGood3.js:139:12:139:27 | escapeHtml3(url) | ReflectedXssGood3.js:135:15:135:27 | req.params.id | ReflectedXssGood3.js:139:12:139:27 | escapeHtml3(url) | Cross-site scripting vulnerability due to a $@. | ReflectedXssGood3.js:135:15:135:27 | req.params.id | user-provided value |
| app/api/route.ts:5:18:5:21 | body | app/api/route.ts:2:24:2:33 | req.json() | app/api/route.ts:5:18:5:21 | body | Cross-site scripting vulnerability due to a $@. | app/api/route.ts:2:24:2:33 | req.json() | user-provided value |
| app/api/route.ts:13:18:13:21 | body | app/api/route.ts:2:24:2:33 | req.json() | app/api/route.ts:13:18:13:21 | body | Cross-site scripting vulnerability due to a $@. | app/api/route.ts:2:24:2:33 | req.json() | user-provided value |
| app/api/route.ts:25:18:25:21 | body | app/api/route.ts:2:24:2:33 | req.json() | app/api/route.ts:25:18:25:21 | body | Cross-site scripting vulnerability due to a $@. | app/api/route.ts:2:24:2:33 | req.json() | user-provided value |
| app/api/route.ts:29:25:29:28 | body | app/api/route.ts:2:24:2:33 | req.json() | app/api/route.ts:29:25:29:28 | body | Cross-site scripting vulnerability due to a $@. | app/api/route.ts:2:24:2:33 | req.json() | user-provided value |
| app/api/routeNextRequest.ts:7:20:7:23 | body | app/api/routeNextRequest.ts:4:22:4:31 | req.json() | app/api/routeNextRequest.ts:7:20:7:23 | body | Cross-site scripting vulnerability due to a $@. | app/api/routeNextRequest.ts:4:22:4:31 | req.json() | user-provided value |
| app/api/routeNextRequest.ts:15:20:15:23 | body | app/api/routeNextRequest.ts:4:22:4:31 | req.json() | app/api/routeNextRequest.ts:15:20:15:23 | body | Cross-site scripting vulnerability due to a $@. | app/api/routeNextRequest.ts:4:22:4:31 | req.json() | user-provided value |
| app/api/routeNextRequest.ts:27:20:27:23 | body | app/api/routeNextRequest.ts:4:22:4:31 | req.json() | app/api/routeNextRequest.ts:27:20:27:23 | body | Cross-site scripting vulnerability due to a $@. | app/api/routeNextRequest.ts:4:22:4:31 | req.json() | user-provided value |
| app/api/routeNextRequest.ts:31:27:31:30 | body | app/api/routeNextRequest.ts:4:22:4:31 | req.json() | app/api/routeNextRequest.ts:31:27:31:30 | body | Cross-site scripting vulnerability due to a $@. | app/api/routeNextRequest.ts:4:22:4:31 | req.json() | user-provided value |
| etherpad.js:11:12:11:19 | response | etherpad.js:9:16:9:30 | req.query.jsonp | etherpad.js:11:12:11:19 | response | Cross-site scripting vulnerability due to a $@. | etherpad.js:9:16:9:30 | req.query.jsonp | user-provided value |
| formatting.js:6:14:6:47 | util.fo ... , evil) | formatting.js:4:16:4:29 | req.query.evil | formatting.js:6:14:6:47 | util.fo ... , evil) | Cross-site scripting vulnerability due to a $@. | formatting.js:4:16:4:29 | req.query.evil | user-provided value |
| formatting.js:7:14:7:53 | require ... , evil) | formatting.js:4:16:4:29 | req.query.evil | formatting.js:7:14:7:53 | require ... , evil) | Cross-site scripting vulnerability due to a $@. | formatting.js:4:16:4:29 | req.query.evil | user-provided value |
@@ -40,6 +48,15 @@
| partial.js:28:14:28:18 | x + y | partial.js:31:47:31:53 | req.url | partial.js:28:14:28:18 | x + y | Cross-site scripting vulnerability due to a $@. | partial.js:31:47:31:53 | req.url | user-provided value |
| partial.js:37:14:37:18 | x + y | partial.js:40:43:40:49 | req.url | partial.js:37:14:37:18 | x + y | Cross-site scripting vulnerability due to a $@. | partial.js:40:43:40:49 | req.url | user-provided value |
| promises.js:6:25:6:25 | x | promises.js:5:44:5:57 | req.query.data | promises.js:6:25:6:25 | x | Cross-site scripting vulnerability due to a $@. | promises.js:5:44:5:57 | req.query.data | user-provided value |
| response-object.js:9:18:9:21 | data | response-object.js:7:18:7:25 | req.body | response-object.js:9:18:9:21 | data | Cross-site scripting vulnerability due to a $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
| response-object.js:10:18:10:21 | data | response-object.js:7:18:7:25 | req.body | response-object.js:10:18:10:21 | data | Cross-site scripting vulnerability due to a $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
| response-object.js:11:18:11:21 | data | response-object.js:7:18:7:25 | req.body | response-object.js:11:18:11:21 | data | Cross-site scripting vulnerability due to a $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
| response-object.js:14:18:14:21 | data | response-object.js:7:18:7:25 | req.body | response-object.js:14:18:14:21 | data | Cross-site scripting vulnerability due to a $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
| response-object.js:17:18:17:21 | data | response-object.js:7:18:7:25 | req.body | response-object.js:17:18:17:21 | data | Cross-site scripting vulnerability due to a $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
| response-object.js:23:18:23:21 | data | response-object.js:7:18:7:25 | req.body | response-object.js:23:18:23:21 | data | Cross-site scripting vulnerability due to a $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
| response-object.js:26:18:26:21 | data | response-object.js:7:18:7:25 | req.body | response-object.js:26:18:26:21 | data | Cross-site scripting vulnerability due to a $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
| response-object.js:34:18:34:21 | data | response-object.js:7:18:7:25 | req.body | response-object.js:34:18:34:21 | data | Cross-site scripting vulnerability due to a $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
| response-object.js:38:18:38:21 | data | response-object.js:7:18:7:25 | req.body | response-object.js:38:18:38:21 | data | Cross-site scripting vulnerability due to a $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
| tst2.js:7:12:7:12 | p | tst2.js:6:9:6:9 | p | tst2.js:7:12:7:12 | p | Cross-site scripting vulnerability due to a $@. | tst2.js:6:9:6:9 | p | user-provided value |
| tst2.js:8:12:8:12 | r | tst2.js:6:12:6:15 | q: r | tst2.js:8:12:8:12 | r | Cross-site scripting vulnerability due to a $@. | tst2.js:6:12:6:15 | q: r | user-provided value |
| tst2.js:18:12:18:12 | p | tst2.js:14:9:14:9 | p | tst2.js:18:12:18:12 | p | Cross-site scripting vulnerability due to a $@. | tst2.js:14:9:14:9 | p | user-provided value |
@@ -119,6 +136,18 @@ edges
| ReflectedXssGood3.js:135:15:135:27 | req.params.id | ReflectedXssGood3.js:135:9:135:27 | url | provenance | |
| ReflectedXssGood3.js:139:24:139:26 | url | ReflectedXssGood3.js:68:22:68:26 | value | provenance | |
| ReflectedXssGood3.js:139:24:139:26 | url | ReflectedXssGood3.js:139:12:139:27 | escapeHtml3(url) | provenance | |
| app/api/route.ts:2:11:2:33 | body | app/api/route.ts:5:18:5:21 | body | provenance | |
| app/api/route.ts:2:11:2:33 | body | app/api/route.ts:13:18:13:21 | body | provenance | |
| app/api/route.ts:2:11:2:33 | body | app/api/route.ts:25:18:25:21 | body | provenance | |
| app/api/route.ts:2:11:2:33 | body | app/api/route.ts:29:25:29:28 | body | provenance | |
| app/api/route.ts:2:18:2:33 | await req.json() | app/api/route.ts:2:11:2:33 | body | provenance | |
| app/api/route.ts:2:24:2:33 | req.json() | app/api/route.ts:2:18:2:33 | await req.json() | provenance | |
| app/api/routeNextRequest.ts:4:9:4:31 | body | app/api/routeNextRequest.ts:7:20:7:23 | body | provenance | |
| app/api/routeNextRequest.ts:4:9:4:31 | body | app/api/routeNextRequest.ts:15:20:15:23 | body | provenance | |
| app/api/routeNextRequest.ts:4:9:4:31 | body | app/api/routeNextRequest.ts:27:20:27:23 | body | provenance | |
| app/api/routeNextRequest.ts:4:9:4:31 | body | app/api/routeNextRequest.ts:31:27:31:30 | body | provenance | |
| app/api/routeNextRequest.ts:4:16:4:31 | await req.json() | app/api/routeNextRequest.ts:4:9:4:31 | body | provenance | |
| app/api/routeNextRequest.ts:4:22:4:31 | req.json() | app/api/routeNextRequest.ts:4:16:4:31 | await req.json() | provenance | |
| etherpad.js:9:5:9:53 | response | etherpad.js:11:12:11:19 | response | provenance | |
| etherpad.js:9:16:9:30 | req.query.jsonp | etherpad.js:9:5:9:53 | response | provenance | |
| formatting.js:4:9:4:29 | evil | formatting.js:6:43:6:46 | evil | provenance | |
@@ -149,6 +178,16 @@ edges
| promises.js:5:36:5:42 | [post update] resolve [resolve-value] | promises.js:5:16:5:22 | resolve [Return] [resolve-value] | provenance | |
| promises.js:5:44:5:57 | req.query.data | promises.js:5:36:5:42 | [post update] resolve [resolve-value] | provenance | |
| promises.js:6:11:6:11 | x | promises.js:6:25:6:25 | x | provenance | |
| response-object.js:7:11:7:25 | data | response-object.js:9:18:9:21 | data | provenance | |
| response-object.js:7:11:7:25 | data | response-object.js:10:18:10:21 | data | provenance | |
| response-object.js:7:11:7:25 | data | response-object.js:11:18:11:21 | data | provenance | |
| response-object.js:7:11:7:25 | data | response-object.js:14:18:14:21 | data | provenance | |
| response-object.js:7:11:7:25 | data | response-object.js:17:18:17:21 | data | provenance | |
| response-object.js:7:11:7:25 | data | response-object.js:23:18:23:21 | data | provenance | |
| response-object.js:7:11:7:25 | data | response-object.js:26:18:26:21 | data | provenance | |
| response-object.js:7:11:7:25 | data | response-object.js:34:18:34:21 | data | provenance | |
| response-object.js:7:11:7:25 | data | response-object.js:38:18:38:21 | data | provenance | |
| response-object.js:7:18:7:25 | req.body | response-object.js:7:11:7:25 | data | provenance | |
| tst2.js:6:7:6:30 | p | tst2.js:7:12:7:12 | p | provenance | |
| tst2.js:6:7:6:30 | r | tst2.js:8:12:8:12 | r | provenance | |
| tst2.js:6:9:6:9 | p | tst2.js:6:7:6:30 | p | provenance | |
@@ -290,6 +329,20 @@ nodes
| ReflectedXssGood3.js:135:15:135:27 | req.params.id | semmle.label | req.params.id |
| ReflectedXssGood3.js:139:12:139:27 | escapeHtml3(url) | semmle.label | escapeHtml3(url) |
| ReflectedXssGood3.js:139:24:139:26 | url | semmle.label | url |
| app/api/route.ts:2:11:2:33 | body | semmle.label | body |
| app/api/route.ts:2:18:2:33 | await req.json() | semmle.label | await req.json() |
| app/api/route.ts:2:24:2:33 | req.json() | semmle.label | req.json() |
| app/api/route.ts:5:18:5:21 | body | semmle.label | body |
| app/api/route.ts:13:18:13:21 | body | semmle.label | body |
| app/api/route.ts:25:18:25:21 | body | semmle.label | body |
| app/api/route.ts:29:25:29:28 | body | semmle.label | body |
| app/api/routeNextRequest.ts:4:9:4:31 | body | semmle.label | body |
| app/api/routeNextRequest.ts:4:16:4:31 | await req.json() | semmle.label | await req.json() |
| app/api/routeNextRequest.ts:4:22:4:31 | req.json() | semmle.label | req.json() |
| app/api/routeNextRequest.ts:7:20:7:23 | body | semmle.label | body |
| app/api/routeNextRequest.ts:15:20:15:23 | body | semmle.label | body |
| app/api/routeNextRequest.ts:27:20:27:23 | body | semmle.label | body |
| app/api/routeNextRequest.ts:31:27:31:30 | body | semmle.label | body |
| etherpad.js:9:5:9:53 | response | semmle.label | response |
| etherpad.js:9:16:9:30 | req.query.jsonp | semmle.label | req.query.jsonp |
| etherpad.js:11:12:11:19 | response | semmle.label | response |
@@ -332,6 +385,17 @@ nodes
| promises.js:5:44:5:57 | req.query.data | semmle.label | req.query.data |
| promises.js:6:11:6:11 | x | semmle.label | x |
| promises.js:6:25:6:25 | x | semmle.label | x |
| response-object.js:7:11:7:25 | data | semmle.label | data |
| response-object.js:7:18:7:25 | req.body | semmle.label | req.body |
| response-object.js:9:18:9:21 | data | semmle.label | data |
| response-object.js:10:18:10:21 | data | semmle.label | data |
| response-object.js:11:18:11:21 | data | semmle.label | data |
| response-object.js:14:18:14:21 | data | semmle.label | data |
| response-object.js:17:18:17:21 | data | semmle.label | data |
| response-object.js:23:18:23:21 | data | semmle.label | data |
| response-object.js:26:18:26:21 | data | semmle.label | data |
| response-object.js:34:18:34:21 | data | semmle.label | data |
| response-object.js:38:18:38:21 | data | semmle.label | data |
| tst2.js:6:7:6:30 | p | semmle.label | p |
| tst2.js:6:7:6:30 | r | semmle.label | r |
| tst2.js:6:9:6:9 | p | semmle.label | p |

View File

@@ -26,6 +26,14 @@
| ReflectedXssContentTypes.js:39:13:39:35 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:39:23:39:35 | req.params.id | user-provided value |
| ReflectedXssContentTypes.js:70:12:70:34 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:70:22:70:34 | req.params.id | user-provided value |
| ReflectedXssGood3.js:139:12:139:27 | escapeHtml3(url) | Cross-site scripting vulnerability due to $@. | ReflectedXssGood3.js:135:15:135:27 | req.params.id | user-provided value |
| app/api/route.ts:5:18:5:21 | body | Cross-site scripting vulnerability due to $@. | app/api/route.ts:2:24:2:33 | req.json() | user-provided value |
| app/api/route.ts:13:18:13:21 | body | Cross-site scripting vulnerability due to $@. | app/api/route.ts:2:24:2:33 | req.json() | user-provided value |
| app/api/route.ts:25:18:25:21 | body | Cross-site scripting vulnerability due to $@. | app/api/route.ts:2:24:2:33 | req.json() | user-provided value |
| app/api/route.ts:29:25:29:28 | body | Cross-site scripting vulnerability due to $@. | app/api/route.ts:2:24:2:33 | req.json() | user-provided value |
| app/api/routeNextRequest.ts:7:20:7:23 | body | Cross-site scripting vulnerability due to $@. | app/api/routeNextRequest.ts:4:22:4:31 | req.json() | user-provided value |
| app/api/routeNextRequest.ts:15:20:15:23 | body | Cross-site scripting vulnerability due to $@. | app/api/routeNextRequest.ts:4:22:4:31 | req.json() | user-provided value |
| app/api/routeNextRequest.ts:27:20:27:23 | body | Cross-site scripting vulnerability due to $@. | app/api/routeNextRequest.ts:4:22:4:31 | req.json() | user-provided value |
| app/api/routeNextRequest.ts:31:27:31:30 | body | Cross-site scripting vulnerability due to $@. | app/api/routeNextRequest.ts:4:22:4:31 | req.json() | user-provided value |
| formatting.js:6:14:6:47 | util.fo ... , evil) | Cross-site scripting vulnerability due to $@. | formatting.js:4:16:4:29 | req.query.evil | user-provided value |
| formatting.js:7:14:7:53 | require ... , evil) | Cross-site scripting vulnerability due to $@. | formatting.js:4:16:4:29 | req.query.evil | user-provided value |
| live-server.js:6:13:6:50 | `<html> ... /html>` | Cross-site scripting vulnerability due to $@. | live-server.js:4:21:4:27 | req.url | user-provided value |
@@ -38,6 +46,15 @@
| partial.js:28:14:28:18 | x + y | Cross-site scripting vulnerability due to $@. | partial.js:31:47:31:53 | req.url | user-provided value |
| partial.js:37:14:37:18 | x + y | Cross-site scripting vulnerability due to $@. | partial.js:40:43:40:49 | req.url | user-provided value |
| promises.js:6:25:6:25 | x | Cross-site scripting vulnerability due to $@. | promises.js:5:44:5:57 | req.query.data | user-provided value |
| response-object.js:9:18:9:21 | data | Cross-site scripting vulnerability due to $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
| response-object.js:10:18:10:21 | data | Cross-site scripting vulnerability due to $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
| response-object.js:11:18:11:21 | data | Cross-site scripting vulnerability due to $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
| response-object.js:14:18:14:21 | data | Cross-site scripting vulnerability due to $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
| response-object.js:17:18:17:21 | data | Cross-site scripting vulnerability due to $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
| response-object.js:23:18:23:21 | data | Cross-site scripting vulnerability due to $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
| response-object.js:26:18:26:21 | data | Cross-site scripting vulnerability due to $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
| response-object.js:34:18:34:21 | data | Cross-site scripting vulnerability due to $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
| response-object.js:38:18:38:21 | data | Cross-site scripting vulnerability due to $@. | response-object.js:7:18:7:25 | req.body | user-provided value |
| tst2.js:7:12:7:12 | p | Cross-site scripting vulnerability due to $@. | tst2.js:6:9:6:9 | p | user-provided value |
| tst2.js:8:12:8:12 | r | Cross-site scripting vulnerability due to $@. | tst2.js:6:12:6:15 | q: r | user-provided value |
| tst2.js:18:12:18:12 | p | Cross-site scripting vulnerability due to $@. | tst2.js:14:9:14:9 | p | user-provided value |

View File

@@ -0,0 +1,30 @@
export async function POST(req: Request) {
const body = await req.json(); // $ Source
new Response(body, {headers: { 'Content-Type': 'application/json' }});
new Response(body, {headers: { 'Content-Type': 'text/html' }}); // $ Alert
const headers2 = new Headers(req.headers);
headers2.append('Content-Type', 'application/json');
new Response(body, { headers: headers2 });
const headers3 = new Headers(req.headers);
headers3.append('Content-Type', 'text/html');
new Response(body, { headers: headers3 }); // $ Alert
const headers4 = new Headers({
...Object.fromEntries(req.headers),
'Content-Type': 'application/json'
});
new Response(body, { headers: headers4 });
const headers5 = new Headers({
...Object.fromEntries(req.headers),
'Content-Type': 'text/html'
});
new Response(body, { headers: headers5 }); // $ Alert
const headers = new Headers(req.headers);
headers.set('Content-Type', 'text/html');
return new Response(body, { headers }); // $ Alert
}

View File

@@ -0,0 +1,32 @@
import { NextRequest, NextResponse } from 'next/server';
export async function POST(req: NextRequest) {
const body = await req.json(); // $ Source
new NextResponse(body, {headers: { 'Content-Type': 'application/json' }});
new NextResponse(body, {headers: { 'Content-Type': 'text/html' }}); // $ Alert
const headers2 = new Headers(req.headers);
headers2.append('Content-Type', 'application/json');
new NextResponse(body, { headers: headers2 });
const headers3 = new Headers(req.headers);
headers3.append('Content-Type', 'text/html');
new NextResponse(body, { headers: headers3 }); // $ Alert
const headers4 = new Headers({
...Object.fromEntries(req.headers),
'Content-Type': 'application/json'
});
new NextResponse(body, { headers: headers4 });
const headers5 = new Headers({
...Object.fromEntries(req.headers),
'Content-Type': 'text/html'
});
new NextResponse(body, { headers: headers5 }); // $ Alert
const headers = new Headers(req.headers);
headers.set('Content-Type', 'text/html');
return new NextResponse(body, { headers }); // $ Alert
}

View File

@@ -0,0 +1,39 @@
const express = require('express');
// Note: We're using using express for the taint source in order to to test 'Response'
// in isolation from the more complicated http frameworks.
express().get('/foo', (req) => {
const data = req.body; // $ Source
new Response(data); // $ Alert
new Response(data, {}); // $ Alert
new Response(data, { headers: null }); // $ Alert
new Response(data, { headers: { 'content-type': 'text/plain'}});
new Response(data, { headers: { 'content-type': 'text/html'}}); // $ Alert
new Response(data, { headers: { 'Content-Type': 'text/plain'}});
new Response(data, { headers: { 'Content-Type': 'text/html'}}); // $ Alert
const headers1 = new Headers({ 'content-type': 'text/plain'});
new Response(data, { headers: headers1 });
const headers2 = new Headers({ 'content-type': 'text/html'});
new Response(data, { headers: headers2 }); // $ Alert
const headers3 = new Headers();
new Response(data, { headers: headers3 }); // $ Alert
const headers4 = new Headers();
headers4.set('content-type', 'text/plain');
new Response(data, { headers: headers4 });
const headers5 = new Headers();
headers5.set('content-type', 'text/html');
new Response(data, { headers: headers5 }); // $ Alert
const headers6 = new Headers();
headers6.set('unrelated-header', 'text/plain');
new Response(data, { headers: headers6 }); // $ Alert
});

View File

@@ -81,9 +81,12 @@ edges
| pako.js:18:48:18:66 | zipFile.data.buffer | pako.js:18:33:18:67 | new Uin ... buffer) | provenance | Config |
| pako.js:28:19:28:25 | zipFile | pako.js:29:36:29:42 | zipFile | provenance | |
| pako.js:29:11:29:62 | myArray | pako.js:32:31:32:37 | myArray | provenance | |
| pako.js:29:11:29:62 | myArray [ArrayElement] | pako.js:32:31:32:37 | myArray | provenance | |
| pako.js:29:21:29:55 | new Uin ... buffer) | pako.js:29:11:29:62 | myArray | provenance | |
| pako.js:29:21:29:55 | new Uin ... buffer) [ArrayElement] | pako.js:29:11:29:62 | myArray [ArrayElement] | provenance | |
| pako.js:29:36:29:42 | zipFile | pako.js:29:36:29:54 | zipFile.data.buffer | provenance | |
| pako.js:29:36:29:54 | zipFile.data.buffer | pako.js:29:21:29:55 | new Uin ... buffer) | provenance | Config |
| pako.js:29:36:29:54 | zipFile.data.buffer | pako.js:29:21:29:55 | new Uin ... buffer) [ArrayElement] | provenance | |
| unbzip2.js:12:5:12:43 | fs.crea ... lePath) | unbzip2.js:12:50:12:54 | bz2() | provenance | Config |
| unbzip2.js:12:25:12:42 | req.query.FilePath | unbzip2.js:12:5:12:43 | fs.crea ... lePath) | provenance | Config |
| unzipper.js:13:26:13:62 | Readabl ... e.data) | unzipper.js:16:23:16:63 | unzippe ... ath' }) | provenance | Config |
@@ -183,7 +186,9 @@ nodes
| pako.js:21:31:21:37 | myArray | semmle.label | myArray |
| pako.js:28:19:28:25 | zipFile | semmle.label | zipFile |
| pako.js:29:11:29:62 | myArray | semmle.label | myArray |
| pako.js:29:11:29:62 | myArray [ArrayElement] | semmle.label | myArray [ArrayElement] |
| pako.js:29:21:29:55 | new Uin ... buffer) | semmle.label | new Uin ... buffer) |
| pako.js:29:21:29:55 | new Uin ... buffer) [ArrayElement] | semmle.label | new Uin ... buffer) [ArrayElement] |
| pako.js:29:36:29:42 | zipFile | semmle.label | zipFile |
| pako.js:29:36:29:54 | zipFile.data.buffer | semmle.label | zipFile.data.buffer |
| pako.js:32:31:32:37 | myArray | semmle.label | myArray |

View File

@@ -1,2 +0,0 @@
consistencyIssue
resultInWrongFile

View File

@@ -1,25 +0,0 @@
import javascript
import semmle.javascript.security.dataflow.RequestForgeryQuery as RequestForgery
import semmle.javascript.security.dataflow.ClientSideRequestForgeryQuery as ClientSideRequestForgery
deprecated import utils.test.ConsistencyChecking
query predicate resultInWrongFile(DataFlow::Node node) {
exists(string filePattern |
RequestForgery::RequestForgeryFlow::flowTo(node) and
filePattern = ".*serverSide.*"
or
ClientSideRequestForgery::ClientSideRequestForgeryFlow::flowTo(node) and
filePattern = ".*clientSide.*"
|
not node.getFile().getRelativePath().regexpMatch(filePattern)
)
}
deprecated class Consistency extends ConsistencyConfiguration {
Consistency() { this = "Consistency" }
override DataFlow::Node getAnAlert() {
RequestForgery::RequestForgeryFlow::flowTo(result) or
ClientSideRequestForgery::ClientSideRequestForgeryFlow::flowTo(result)
}
}

View File

@@ -0,0 +1,5 @@
export async function POST(req: Request) {
const { url } = await req.json(); // $ Source[js/request-forgery]
const res = await fetch(url); // $ Alert[js/request-forgery] Sink[js/request-forgery]
return new Response(res.body, { headers: res.headers });
}

View File

@@ -0,0 +1,8 @@
import { NextRequest, NextResponse } from 'next/server';
export async function POST(req: NextRequest) {
const { url } = await req.json(); // $ Source[js/request-forgery]
const res = await fetch(url); // $ Alert[js/request-forgery] Sink[js/request-forgery]
const data = await res.text();
return new NextResponse(data, { headers: res.headers });
}

View File

@@ -0,0 +1,18 @@
import { NextRequest, NextResponse } from 'next/server';
export async function middleware(req: NextRequest) {
const target = req.nextUrl // $ Source[js/request-forgery]
const target2 = target.searchParams.get('target'); // $ Source[js/request-forgery]
if (target) {
const res = await fetch(target) // $ Alert[js/request-forgery] Sink[js/request-forgery]
const data = await res.text()
return new NextResponse(data)
}
if (target2) {
const res = await fetch(target2); // $ Alert[js/request-forgery] Sink[js/request-forgery]
const data = await res.text();
return new NextResponse(data);
}
return NextResponse.next()
}

View File

@@ -0,0 +1,13 @@
{
"name": "next-edge-proxy-app",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"next": "15.1.7"
}
}

View File

@@ -1,5 +1,10 @@
#select
| Request/app/api/proxy/route2.serverSide.ts:5:21:5:30 | fetch(url) | Request/app/api/proxy/route2.serverSide.ts:4:25:4:34 | req.json() | Request/app/api/proxy/route2.serverSide.ts:5:27:5:29 | url | The $@ of this request depends on a $@. | Request/app/api/proxy/route2.serverSide.ts:5:27:5:29 | url | URL | Request/app/api/proxy/route2.serverSide.ts:4:25:4:34 | req.json() | user-provided value |
| Request/app/api/proxy/route.serverSide.ts:3:21:3:30 | fetch(url) | Request/app/api/proxy/route.serverSide.ts:2:25:2:34 | req.json() | Request/app/api/proxy/route.serverSide.ts:3:27:3:29 | url | The $@ of this request depends on a $@. | Request/app/api/proxy/route.serverSide.ts:3:27:3:29 | url | URL | Request/app/api/proxy/route.serverSide.ts:2:25:2:34 | req.json() | user-provided value |
| Request/middleware.ts:7:25:7:37 | fetch(target) | Request/middleware.ts:4:20:4:30 | req.nextUrl | Request/middleware.ts:7:31:7:36 | target | The $@ of this request depends on a $@. | Request/middleware.ts:7:31:7:36 | target | URL | Request/middleware.ts:4:20:4:30 | req.nextUrl | user-provided value |
| Request/middleware.ts:12:27:12:40 | fetch(target2) | Request/middleware.ts:5:21:5:53 | target. ... arget') | Request/middleware.ts:12:33:12:39 | target2 | The $@ of this request depends on a $@. | Request/middleware.ts:12:33:12:39 | target2 | URL | Request/middleware.ts:5:21:5:53 | target. ... arget') | user-provided value |
| apollo.serverSide.ts:8:39:8:64 | get(fil ... => {}) | apollo.serverSide.ts:7:36:7:44 | { files } | apollo.serverSide.ts:8:43:8:50 | file.url | The $@ of this request depends on a $@. | apollo.serverSide.ts:8:43:8:50 | file.url | URL | apollo.serverSide.ts:7:36:7:44 | { files } | user-provided value |
| apollo.serverSide.ts:18:37:18:62 | get(fil ... => {}) | apollo.serverSide.ts:17:34:17:42 | { files } | apollo.serverSide.ts:18:41:18:48 | file.url | The $@ of this request depends on a $@. | apollo.serverSide.ts:18:41:18:48 | file.url | URL | apollo.serverSide.ts:17:34:17:42 | { files } | user-provided value |
| axiosInterceptors.serverSide.js:11:26:11:40 | userProvidedUrl | axiosInterceptors.serverSide.js:19:21:19:28 | req.body | axiosInterceptors.serverSide.js:11:26:11:40 | userProvidedUrl | The $@ of this request depends on a $@. | axiosInterceptors.serverSide.js:11:26:11:40 | userProvidedUrl | endpoint | axiosInterceptors.serverSide.js:19:21:19:28 | req.body | user-provided value |
| serverSide.js:18:5:18:20 | request(tainted) | serverSide.js:14:29:14:35 | req.url | serverSide.js:18:13:18:19 | tainted | The $@ of this request depends on a $@. | serverSide.js:18:13:18:19 | tainted | URL | serverSide.js:14:29:14:35 | req.url | user-provided value |
| serverSide.js:20:5:20:24 | request.get(tainted) | serverSide.js:14:29:14:35 | req.url | serverSide.js:20:17:20:23 | tainted | The $@ of this request depends on a $@. | serverSide.js:20:17:20:23 | tainted | URL | serverSide.js:14:29:14:35 | req.url | user-provided value |
@@ -26,11 +31,28 @@
| serverSide.js:125:5:128:6 | axios({ ... \\n }) | serverSide.js:123:29:123:35 | req.url | serverSide.js:127:14:127:20 | tainted | The $@ of this request depends on a $@. | serverSide.js:127:14:127:20 | tainted | URL | serverSide.js:123:29:123:35 | req.url | user-provided value |
| serverSide.js:131:5:131:20 | axios.get(myUrl) | serverSide.js:123:29:123:35 | req.url | serverSide.js:131:15:131:19 | myUrl | The $@ of this request depends on a $@. | serverSide.js:131:15:131:19 | myUrl | URL | serverSide.js:123:29:123:35 | req.url | user-provided value |
edges
| Request/app/api/proxy/route2.serverSide.ts:4:9:4:15 | { url } | Request/app/api/proxy/route2.serverSide.ts:4:9:4:34 | url | provenance | |
| Request/app/api/proxy/route2.serverSide.ts:4:9:4:34 | url | Request/app/api/proxy/route2.serverSide.ts:5:27:5:29 | url | provenance | |
| Request/app/api/proxy/route2.serverSide.ts:4:19:4:34 | await req.json() | Request/app/api/proxy/route2.serverSide.ts:4:9:4:15 | { url } | provenance | |
| Request/app/api/proxy/route2.serverSide.ts:4:25:4:34 | req.json() | Request/app/api/proxy/route2.serverSide.ts:4:19:4:34 | await req.json() | provenance | |
| Request/app/api/proxy/route.serverSide.ts:2:9:2:15 | { url } | Request/app/api/proxy/route.serverSide.ts:2:9:2:34 | url | provenance | |
| Request/app/api/proxy/route.serverSide.ts:2:9:2:34 | url | Request/app/api/proxy/route.serverSide.ts:3:27:3:29 | url | provenance | |
| Request/app/api/proxy/route.serverSide.ts:2:19:2:34 | await req.json() | Request/app/api/proxy/route.serverSide.ts:2:9:2:15 | { url } | provenance | |
| Request/app/api/proxy/route.serverSide.ts:2:25:2:34 | req.json() | Request/app/api/proxy/route.serverSide.ts:2:19:2:34 | await req.json() | provenance | |
| Request/middleware.ts:4:11:4:30 | target | Request/middleware.ts:7:31:7:36 | target | provenance | |
| Request/middleware.ts:4:20:4:30 | req.nextUrl | Request/middleware.ts:4:11:4:30 | target | provenance | |
| Request/middleware.ts:5:11:5:53 | target2 | Request/middleware.ts:12:33:12:39 | target2 | provenance | |
| Request/middleware.ts:5:21:5:53 | target. ... arget') | Request/middleware.ts:5:11:5:53 | target2 | provenance | |
| apollo.serverSide.ts:7:36:7:44 | files | apollo.serverSide.ts:8:13:8:17 | files | provenance | |
| apollo.serverSide.ts:7:36:7:44 | { files } | apollo.serverSide.ts:7:36:7:44 | files | provenance | |
| apollo.serverSide.ts:8:13:8:17 | files | apollo.serverSide.ts:8:28:8:31 | file | provenance | |
| apollo.serverSide.ts:8:28:8:31 | file | apollo.serverSide.ts:8:43:8:46 | file | provenance | |
| apollo.serverSide.ts:8:43:8:46 | file | apollo.serverSide.ts:8:43:8:50 | file.url | provenance | |
| apollo.serverSide.ts:17:34:17:42 | files | apollo.serverSide.ts:18:11:18:15 | files | provenance | |
| apollo.serverSide.ts:17:34:17:42 | { files } | apollo.serverSide.ts:17:34:17:42 | files | provenance | |
| apollo.serverSide.ts:18:11:18:15 | files | apollo.serverSide.ts:18:26:18:29 | file | provenance | |
| apollo.serverSide.ts:18:26:18:29 | file | apollo.serverSide.ts:18:41:18:44 | file | provenance | |
| apollo.serverSide.ts:18:41:18:44 | file | apollo.serverSide.ts:18:41:18:48 | file.url | provenance | |
| axiosInterceptors.serverSide.js:19:11:19:17 | { url } | axiosInterceptors.serverSide.js:19:11:19:28 | url | provenance | |
| axiosInterceptors.serverSide.js:19:11:19:28 | url | axiosInterceptors.serverSide.js:20:23:20:25 | url | provenance | |
| axiosInterceptors.serverSide.js:19:21:19:28 | req.body | axiosInterceptors.serverSide.js:19:11:19:17 | { url } | provenance | |
@@ -85,12 +107,34 @@ edges
| serverSide.js:130:9:130:45 | myUrl | serverSide.js:131:15:131:19 | myUrl | provenance | |
| serverSide.js:130:37:130:43 | tainted | serverSide.js:130:9:130:45 | myUrl | provenance | |
nodes
| Request/app/api/proxy/route2.serverSide.ts:4:9:4:15 | { url } | semmle.label | { url } |
| Request/app/api/proxy/route2.serverSide.ts:4:9:4:34 | url | semmle.label | url |
| Request/app/api/proxy/route2.serverSide.ts:4:19:4:34 | await req.json() | semmle.label | await req.json() |
| Request/app/api/proxy/route2.serverSide.ts:4:25:4:34 | req.json() | semmle.label | req.json() |
| Request/app/api/proxy/route2.serverSide.ts:5:27:5:29 | url | semmle.label | url |
| Request/app/api/proxy/route.serverSide.ts:2:9:2:15 | { url } | semmle.label | { url } |
| Request/app/api/proxy/route.serverSide.ts:2:9:2:34 | url | semmle.label | url |
| Request/app/api/proxy/route.serverSide.ts:2:19:2:34 | await req.json() | semmle.label | await req.json() |
| Request/app/api/proxy/route.serverSide.ts:2:25:2:34 | req.json() | semmle.label | req.json() |
| Request/app/api/proxy/route.serverSide.ts:3:27:3:29 | url | semmle.label | url |
| Request/middleware.ts:4:11:4:30 | target | semmle.label | target |
| Request/middleware.ts:4:20:4:30 | req.nextUrl | semmle.label | req.nextUrl |
| Request/middleware.ts:5:11:5:53 | target2 | semmle.label | target2 |
| Request/middleware.ts:5:21:5:53 | target. ... arget') | semmle.label | target. ... arget') |
| Request/middleware.ts:7:31:7:36 | target | semmle.label | target |
| Request/middleware.ts:12:33:12:39 | target2 | semmle.label | target2 |
| apollo.serverSide.ts:7:36:7:44 | files | semmle.label | files |
| apollo.serverSide.ts:7:36:7:44 | { files } | semmle.label | { files } |
| apollo.serverSide.ts:8:13:8:17 | files | semmle.label | files |
| apollo.serverSide.ts:8:28:8:31 | file | semmle.label | file |
| apollo.serverSide.ts:8:43:8:46 | file | semmle.label | file |
| apollo.serverSide.ts:8:43:8:50 | file.url | semmle.label | file.url |
| apollo.serverSide.ts:17:34:17:42 | files | semmle.label | files |
| apollo.serverSide.ts:17:34:17:42 | { files } | semmle.label | { files } |
| apollo.serverSide.ts:18:11:18:15 | files | semmle.label | files |
| apollo.serverSide.ts:18:26:18:29 | file | semmle.label | file |
| apollo.serverSide.ts:18:41:18:44 | file | semmle.label | file |
| apollo.serverSide.ts:18:41:18:48 | file.url | semmle.label | file.url |
| axiosInterceptors.serverSide.js:11:26:11:40 | userProvidedUrl | semmle.label | userProvidedUrl |
| axiosInterceptors.serverSide.js:19:11:19:17 | { url } | semmle.label | { url } |
| axiosInterceptors.serverSide.js:19:11:19:28 | url | semmle.label | url |

View File

@@ -14,8 +14,8 @@ function createApolloServer(typeDefs) {
const resolvers2 = {
Mutation: {
downloadFiles: async (_, { files }) => { // $ MISSING: Source[js/request-forgery]
files.forEach((file) => { get(file.url, (res) => {}); }); // $ MISSING: Alert[js/request-forgery] Sink[js/request-forgery]
downloadFiles: async (_, { files }) => { // $ Source[js/request-forgery]
files.forEach((file) => { get(file.url, (res) => {}); }); // $ Alert[js/request-forgery] Sink[js/request-forgery]
return true;
},
},