Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b00938e

Browse files
committed
Make NodeJSLib use moduleMember for ES6-compatibility
1 parent e32dc08 commit b00938e

4 files changed

Lines changed: 48 additions & 34 deletions

File tree

javascript/ql/src/semmle/javascript/frameworks/HTTP.qll

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,13 @@ module HTTP {
125125
}
126126
}
127127

128+
/**
129+
* Gets the string `http` or `https`.
130+
*/
131+
string httpOrHttps() {
132+
result = "http" or result = "https"
133+
}
134+
128135
/**
129136
* An expression whose value is sent as (part of) the body of an HTTP response.
130137
*/

javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll

Lines changed: 29 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,19 @@ module NodeJSLib {
1616
result = DataFlow::moduleImport("process")
1717
}
1818

19+
/**
20+
* Gets a reference to a member of the 'process' object.
21+
*/
22+
private DataFlow::SourceNode processMember(string member) {
23+
result = process().getAPropertyRead(member) or
24+
result = DataFlow::moduleMember("process", member)
25+
}
26+
1927
/**
2028
* Holds if `call` is an invocation of `http.createServer` or `https.createServer`.
2129
*/
2230
predicate isCreateServer(CallExpr call) {
23-
exists (string name |
24-
name = "http" or name = "https" |
25-
call = DataFlow::moduleMember(name, "createServer").getAnInvocation().asExpr()
26-
)
31+
call = DataFlow::moduleMember(HTTP::httpOrHttps(), "createServer").getAnInvocation().asExpr()
2732
}
2833

2934
/**
@@ -234,30 +239,27 @@ module NodeJSLib {
234239
/**
235240
* A call to a path-module method that preserves taint.
236241
*/
237-
private class PathFlowTarget extends TaintTracking::AdditionalTaintStep, DataFlow::ValueNode {
238-
override CallExpr astNode;
239-
Expr tainted;
242+
private class PathFlowTarget extends TaintTracking::AdditionalTaintStep, DataFlow::CallNode {
243+
DataFlow::Node tainted;
240244

241245
PathFlowTarget() {
242-
exists (DataFlow::ModuleImportNode pathModule, string methodName |
243-
pathModule.getPath() = "path" and
244-
this = pathModule.getAMemberCall(methodName) |
246+
exists (string methodName | this = DataFlow::moduleMember("path", methodName).getACall() |
245247
// getters
246-
(methodName = "basename" and tainted = astNode.getArgument(0)) or
247-
(methodName = "dirname" and tainted = astNode.getArgument(0)) or
248-
(methodName = "extname" and tainted = astNode.getArgument(0)) or
248+
(methodName = "basename" and tainted = getArgument(0)) or
249+
(methodName = "dirname" and tainted = getArgument(0)) or
250+
(methodName = "extname" and tainted = getArgument(0)) or
249251

250252
// transformers
251-
(methodName = "join" and tainted = astNode.getAnArgument()) or
252-
(methodName = "normalize" and tainted = astNode.getArgument(0)) or
253-
(methodName = "relative" and tainted = astNode.getArgument([0..1])) or
254-
(methodName = "resolve" and tainted = astNode.getAnArgument()) or
255-
(methodName = "toNamespacedPath" and tainted = astNode.getArgument(0))
253+
(methodName = "join" and tainted = getAnArgument()) or
254+
(methodName = "normalize" and tainted = getArgument(0)) or
255+
(methodName = "relative" and tainted = getArgument([0..1])) or
256+
(methodName = "resolve" and tainted = getAnArgument()) or
257+
(methodName = "toNamespacedPath" and tainted = getArgument(0))
256258
)
257259
}
258260

259261
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
260-
pred.asExpr() = tainted and succ = this
262+
pred = tainted and succ = this
261263
}
262264

263265
}
@@ -294,13 +296,7 @@ module NodeJSLib {
294296
class Credentials extends CredentialsExpr {
295297

296298
Credentials() {
297-
exists (CallExpr call |
298-
exists (DataFlow::ModuleImportNode http |
299-
http.getPath() = "http" or http.getPath() = "https" |
300-
call = http.getAMemberCall("request").asExpr()
301-
) and
302-
call.hasOptionArgument(0, "auth", this)
303-
)
299+
this = DataFlow::moduleMember(HTTP::httpOrHttps(), "request").getACall().getOptionArgument(0, "auth").asExpr()
304300
}
305301

306302
override string getCredentialsKind() {
@@ -318,7 +314,7 @@ module NodeJSLib {
318314
ProcessTermination() {
319315
this = DataFlow::moduleImport("exit").getAnInvocation()
320316
or
321-
this = process().getAMemberCall("exit")
317+
this = processMember("exit").getACall()
322318
}
323319

324320
}
@@ -344,19 +340,18 @@ module NodeJSLib {
344340
/**
345341
* A call to a method from module `fs` or `graceful-fs`.
346342
*/
347-
private class NodeJSFileSystemAccess extends FileSystemAccess, DataFlow::ValueNode {
348-
override MethodCallExpr astNode;
343+
private class NodeJSFileSystemAccess extends FileSystemAccess, DataFlow::CallNode {
344+
string methodName;
349345

350346
NodeJSFileSystemAccess() {
351-
exists (DataFlow::ModuleImportNode fs |
352-
fs.getPath() = "fs" or fs.getPath() = "graceful-fs" |
353-
this = fs.getAMemberCall(_)
347+
exists (string moduleName | this = DataFlow::moduleMember(moduleName, methodName).getACall() |
348+
moduleName = "fs" or moduleName = "graceful-fs"
354349
)
355350
}
356351

357352
override DataFlow::Node getAPathArgument() {
358-
exists (int i | fsFileParam(astNode.getMethodName(), i) |
359-
result = DataFlow::valueNode(astNode.getArgument(i))
353+
exists (int i | fsFileParam(methodName, i) |
354+
result = getArgument(i)
360355
)
361356
}
362357
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { readFileSync } from 'fs';
2+
import { createServer } from 'http';
3+
import { parse } from 'url';
4+
import { join } from 'path';
5+
6+
var server = createServer(function(req, res) {
7+
let path = parse(req.url, true).query.path;
8+
9+
// BAD: This could read any file on the file system
10+
res.write(readFileSync(join("public", path)));
11+
});

javascript/ql/test/query-tests/Security/CWE-022/TaintedPath.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
| TaintedPath-es6.js:10:26:10:45 | join("public", path) | This path depends on $@. | TaintedPath-es6.js:7:20:7:26 | req.url | a user-provided value |
12
| TaintedPath.js:12:29:12:32 | path | This path depends on $@. | TaintedPath.js:9:24:9:30 | req.url | a user-provided value |
23
| TaintedPath.js:15:29:15:48 | "/home/user/" + path | This path depends on $@. | TaintedPath.js:9:24:9:30 | req.url | a user-provided value |
34
| TaintedPath.js:19:33:19:36 | path | This path depends on $@. | TaintedPath.js:9:24:9:30 | req.url | a user-provided value |

0 commit comments

Comments
 (0)