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

Skip to content

Commit b0636dd

Browse files
committed
JS: Better local flow through .pipe chaining
1 parent 23d37c7 commit b0636dd

4 files changed

Lines changed: 58 additions & 6 deletions

File tree

javascript/ql/src/semmle/javascript/security/dataflow/ZipSlip.qll

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,33 @@ module ZipSlip {
3333
}
3434
}
3535

36+
/**
37+
* Holds if `node1` flows to `node2` in one step by virtue of
38+
* `node2` being of the form `.pipe(node1)`. The reason this flow
39+
* exists is that `.pipe` returns its argument to make chained
40+
* stream operations work.
41+
*/
42+
predicate pipeStep(DataFlow::Node node1, DataFlow::MethodCallNode node2) {
43+
node2.getMethodName() = "pipe" and
44+
node1 = node2.getArgument(0)
45+
}
46+
47+
/**
48+
* Holds if `node1` flows to `node2` in one step including the assumption that
49+
* `x` flows to `.pipe(x)`
50+
*/
51+
predicate stepsThroughPipe(DataFlow::Node node1, DataFlow::Node node2) {
52+
DataFlow::localFlowStep(node1, node2) or pipeStep(node1, node2)
53+
}
54+
55+
/**
56+
* Holds if `node1` flows to `node2` including the assumption that
57+
* `x` flows to `.pipe(x)`
58+
*/
59+
predicate flowsThroughPipe(DataFlow::Node node1, DataFlow::Node node2) {
60+
stepsThroughPipe*(node1, node2)
61+
}
62+
3663
/**
3764
* An access to the filepath of an entry of a zipfile being extracted
3865
* by npm module `unzip`. For example, in
@@ -50,12 +77,10 @@ module ZipSlip {
5077
*/
5178
class UnzipEntrySource extends Source {
5279
UnzipEntrySource() {
53-
exists(DataFlow::MethodCallNode pipe, DataFlow::MethodCallNode on |
54-
pipe.getMethodName() = "pipe" and
55-
pipe.getArgument(0).getALocalSource() = DataFlow::moduleImport("unzip")
56-
.getAMemberCall("Parse") and
57-
on = pipe.getAMemberCall("on") and
58-
this = on.getCallback(1).getParameter(0).getAPropertyRead("path")
80+
exists(DataFlow::SourceNode parsed |
81+
flowsThroughPipe(DataFlow::moduleImport("unzip").getAMemberCall("Parse"), parsed)
82+
and
83+
this = parsed.getAMemberCall("on").getCallback(1).getParameter(0).getAPropertyRead("path")
5984
)
6085
}
6186
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
nodes
2+
| ZipSlipBad2.js:5:9:5:46 | fileName |
3+
| ZipSlipBad2.js:5:20:5:46 | 'output ... ry.path |
4+
| ZipSlipBad2.js:5:37:5:46 | entry.path |
5+
| ZipSlipBad2.js:6:22:6:29 | fileName |
26
| ZipSlipBad.js:8:37:8:46 | entry.path |
37
edges
8+
| ZipSlipBad2.js:5:9:5:46 | fileName | ZipSlipBad2.js:6:22:6:29 | fileName |
9+
| ZipSlipBad2.js:5:20:5:46 | 'output ... ry.path | ZipSlipBad2.js:5:9:5:46 | fileName |
10+
| ZipSlipBad2.js:5:37:5:46 | entry.path | ZipSlipBad2.js:5:20:5:46 | 'output ... ry.path |
411
#select
12+
| ZipSlipBad2.js:6:22:6:29 | fileName | ZipSlipBad2.js:5:37:5:46 | entry.path | ZipSlipBad2.js:6:22:6:29 | fileName | Unsanitized zip archive $@, which may contain '..', is used in a file system operation. | ZipSlipBad2.js:5:37:5:46 | entry.path | item path |
513
| ZipSlipBad.js:8:37:8:46 | entry.path | ZipSlipBad.js:8:37:8:46 | entry.path | ZipSlipBad.js:8:37:8:46 | entry.path | Unsanitized zip archive $@, which may contain '..', is used in a file system operation. | ZipSlipBad.js:8:37:8:46 | entry.path | item path |
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
var fs = require('fs');
2+
var unzip = require('unzip');
3+
fs.readFile('path/to/archive.zip', function (err, zipContents) {
4+
unzip.Parse(zipContents).on('entry', function (entry) {
5+
var fileName = 'output/path/' + entry.path;
6+
fs.writeFileSync(fileName, entry.contents);
7+
});
8+
});
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/**
2+
* @externs
3+
*/
4+
var fs = {};
5+
6+
/**
7+
* @param {string} filename
8+
* @param {*} data
9+
* @return {void}
10+
*/
11+
fs.writeFileSync = function(filename, data) {};

0 commit comments

Comments
 (0)