Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ module TaintedPath {
guard instanceof StartsWithDirSanitizer or
guard instanceof IsAbsoluteSanitizer or
guard instanceof ContainsDotDotSanitizer or
guard instanceof RelativePathStartsWithDotDotSanitizer or
guard instanceof RelativePathStartsWithSanitizer or
guard instanceof IsInsideCheckSanitizer
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -368,29 +368,43 @@ module TaintedPath {
* // pathname is safe
* }
* ```
*
* or
* ```
* var relative = path.resolve(pathname); // or path.normalize
* if(relative.startsWith(webroot) {
* // pathname is safe
* } else {
* // pathname is unsafe
* }
* ```
*/
class RelativePathStartsWithDotDotSanitizer extends DataFlow::BarrierGuardNode {
class RelativePathStartsWithSanitizer extends DataFlow::BarrierGuardNode {
StringOps::StartsWith startsWith;
DataFlow::CallNode relativeCall;
DataFlow::CallNode pathCall;
string member;

RelativePathStartsWithDotDotSanitizer() {
RelativePathStartsWithSanitizer() {
(member = "relative" or member = "resolve" or member = "normalize") and
this = startsWith and
relativeCall = NodeJSLib::Path::moduleMember("relative").getACall() and
pathCall = NodeJSLib::Path::moduleMember(member).getACall() and
(
startsWith.getBaseString().getALocalSource() = relativeCall
startsWith.getBaseString().getALocalSource() = pathCall
or
startsWith
.getBaseString()
.getALocalSource()
.(NormalizingPathCall)
.getInput()
.getALocalSource() = relativeCall
.getALocalSource() = pathCall
) and
isDotDotSlashPrefix(startsWith.getSubstring())
(not member = "relative" or isDotDotSlashPrefix(startsWith.getSubstring()))
}

override predicate blocks(boolean outcome, Expr e) {
e = relativeCall.getArgument(1).asExpr() and outcome = startsWith.getPolarity().booleanNot()
member = "relative" and e = pathCall.getArgument(1).asExpr() and outcome = startsWith.getPolarity().booleanNot()
or
not member = "relative" and e = pathCall.getArgument(0).asExpr() and outcome = startsWith.getPolarity()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1631,6 +1631,29 @@ nodes
| normalizedPaths.js:332:19:332:32 | normalizedPath |
| normalizedPaths.js:332:19:332:32 | normalizedPath |
| normalizedPaths.js:332:19:332:32 | normalizedPath |
| normalizedPaths.js:339:6:339:46 | path |
| normalizedPaths.js:339:6:339:46 | path |
| normalizedPaths.js:339:6:339:46 | path |
| normalizedPaths.js:339:6:339:46 | path |
| normalizedPaths.js:339:13:339:46 | pathMod ... y.path) |
| normalizedPaths.js:339:13:339:46 | pathMod ... y.path) |
| normalizedPaths.js:339:13:339:46 | pathMod ... y.path) |
| normalizedPaths.js:339:13:339:46 | pathMod ... y.path) |
| normalizedPaths.js:339:32:339:45 | req.query.path |
| normalizedPaths.js:339:32:339:45 | req.query.path |
| normalizedPaths.js:339:32:339:45 | req.query.path |
| normalizedPaths.js:339:32:339:45 | req.query.path |
| normalizedPaths.js:339:32:339:45 | req.query.path |
| normalizedPaths.js:341:18:341:21 | path |
| normalizedPaths.js:341:18:341:21 | path |
| normalizedPaths.js:341:18:341:21 | path |
| normalizedPaths.js:341:18:341:21 | path |
| normalizedPaths.js:341:18:341:21 | path |
| normalizedPaths.js:346:19:346:22 | path |
| normalizedPaths.js:346:19:346:22 | path |
| normalizedPaths.js:346:19:346:22 | path |
| normalizedPaths.js:346:19:346:22 | path |
| normalizedPaths.js:346:19:346:22 | path |
| tainted-require.js:7:19:7:37 | req.param("module") |
| tainted-require.js:7:19:7:37 | req.param("module") |
| tainted-require.js:7:19:7:37 | req.param("module") |
Expand Down Expand Up @@ -4531,6 +4554,34 @@ edges
| normalizedPaths.js:320:45:320:48 | path | normalizedPaths.js:320:23:320:49 | pathMod ... , path) |
| normalizedPaths.js:320:45:320:48 | path | normalizedPaths.js:320:23:320:49 | pathMod ... , path) |
| normalizedPaths.js:320:45:320:48 | path | normalizedPaths.js:320:23:320:49 | pathMod ... , path) |
| normalizedPaths.js:339:6:339:46 | path | normalizedPaths.js:341:18:341:21 | path |
| normalizedPaths.js:339:6:339:46 | path | normalizedPaths.js:341:18:341:21 | path |
| normalizedPaths.js:339:6:339:46 | path | normalizedPaths.js:341:18:341:21 | path |
| normalizedPaths.js:339:6:339:46 | path | normalizedPaths.js:341:18:341:21 | path |
| normalizedPaths.js:339:6:339:46 | path | normalizedPaths.js:341:18:341:21 | path |
| normalizedPaths.js:339:6:339:46 | path | normalizedPaths.js:341:18:341:21 | path |
| normalizedPaths.js:339:6:339:46 | path | normalizedPaths.js:341:18:341:21 | path |
| normalizedPaths.js:339:6:339:46 | path | normalizedPaths.js:341:18:341:21 | path |
| normalizedPaths.js:339:6:339:46 | path | normalizedPaths.js:346:19:346:22 | path |
| normalizedPaths.js:339:6:339:46 | path | normalizedPaths.js:346:19:346:22 | path |
| normalizedPaths.js:339:6:339:46 | path | normalizedPaths.js:346:19:346:22 | path |
| normalizedPaths.js:339:6:339:46 | path | normalizedPaths.js:346:19:346:22 | path |
| normalizedPaths.js:339:6:339:46 | path | normalizedPaths.js:346:19:346:22 | path |
| normalizedPaths.js:339:6:339:46 | path | normalizedPaths.js:346:19:346:22 | path |
| normalizedPaths.js:339:6:339:46 | path | normalizedPaths.js:346:19:346:22 | path |
| normalizedPaths.js:339:6:339:46 | path | normalizedPaths.js:346:19:346:22 | path |
| normalizedPaths.js:339:13:339:46 | pathMod ... y.path) | normalizedPaths.js:339:6:339:46 | path |
| normalizedPaths.js:339:13:339:46 | pathMod ... y.path) | normalizedPaths.js:339:6:339:46 | path |
| normalizedPaths.js:339:13:339:46 | pathMod ... y.path) | normalizedPaths.js:339:6:339:46 | path |
| normalizedPaths.js:339:13:339:46 | pathMod ... y.path) | normalizedPaths.js:339:6:339:46 | path |
| normalizedPaths.js:339:32:339:45 | req.query.path | normalizedPaths.js:339:13:339:46 | pathMod ... y.path) |
| normalizedPaths.js:339:32:339:45 | req.query.path | normalizedPaths.js:339:13:339:46 | pathMod ... y.path) |
| normalizedPaths.js:339:32:339:45 | req.query.path | normalizedPaths.js:339:13:339:46 | pathMod ... y.path) |
| normalizedPaths.js:339:32:339:45 | req.query.path | normalizedPaths.js:339:13:339:46 | pathMod ... y.path) |
| normalizedPaths.js:339:32:339:45 | req.query.path | normalizedPaths.js:339:13:339:46 | pathMod ... y.path) |
| normalizedPaths.js:339:32:339:45 | req.query.path | normalizedPaths.js:339:13:339:46 | pathMod ... y.path) |
| normalizedPaths.js:339:32:339:45 | req.query.path | normalizedPaths.js:339:13:339:46 | pathMod ... y.path) |
| normalizedPaths.js:339:32:339:45 | req.query.path | normalizedPaths.js:339:13:339:46 | pathMod ... y.path) |
| tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") |
| tainted-sendFile.js:8:16:8:33 | req.param("gimme") | tainted-sendFile.js:8:16:8:33 | req.param("gimme") |
| tainted-sendFile.js:10:16:10:33 | req.param("gimme") | tainted-sendFile.js:10:16:10:33 | req.param("gimme") |
Expand Down Expand Up @@ -5411,6 +5462,8 @@ edges
| normalizedPaths.js:316:19:316:22 | path | normalizedPaths.js:303:13:303:26 | req.query.path | normalizedPaths.js:316:19:316:22 | path | This path depends on $@. | normalizedPaths.js:303:13:303:26 | req.query.path | a user-provided value |
| normalizedPaths.js:325:19:325:32 | normalizedPath | normalizedPaths.js:303:13:303:26 | req.query.path | normalizedPaths.js:325:19:325:32 | normalizedPath | This path depends on $@. | normalizedPaths.js:303:13:303:26 | req.query.path | a user-provided value |
| normalizedPaths.js:332:19:332:32 | normalizedPath | normalizedPaths.js:303:13:303:26 | req.query.path | normalizedPaths.js:332:19:332:32 | normalizedPath | This path depends on $@. | normalizedPaths.js:303:13:303:26 | req.query.path | a user-provided value |
| normalizedPaths.js:341:18:341:21 | path | normalizedPaths.js:339:32:339:45 | req.query.path | normalizedPaths.js:341:18:341:21 | path | This path depends on $@. | normalizedPaths.js:339:32:339:45 | req.query.path | a user-provided value |
| normalizedPaths.js:346:19:346:22 | path | normalizedPaths.js:339:32:339:45 | req.query.path | normalizedPaths.js:346:19:346:22 | path | This path depends on $@. | normalizedPaths.js:339:32:339:45 | req.query.path | a user-provided value |
| tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | This path depends on $@. | tainted-require.js:7:19:7:37 | req.param("module") | a user-provided value |
| tainted-sendFile.js:8:16:8:33 | req.param("gimme") | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | This path depends on $@. | tainted-sendFile.js:8:16:8:33 | req.param("gimme") | a user-provided value |
| tainted-sendFile.js:10:16:10:33 | req.param("gimme") | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | This path depends on $@. | tainted-sendFile.js:10:16:10:33 | req.param("gimme") | a user-provided value |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -334,3 +334,17 @@ app.get('/pseudo-normalizations', (req, res) => {
}

});

app.get('/yet-another-prefix', (req, res) => {
let path = pathModule.resolve(req.query.path);

fs.readFileSync(path); // NOT OK

var abs = pathModule.resolve(path);

if (abs.indexOf(root) !== 0) {
fs.readFileSync(path); // NOT OK
return;
}
fs.readFileSync(path); // OK
});