mirror of
https://github.com/github/codeql.git
synced 2026-04-30 03:05:15 +02:00
Merge pull request #7921 from erik-krogh/snapdragon
JS: add model for the snapdragon library
This commit is contained in:
@@ -122,6 +122,7 @@ import semmle.javascript.frameworks.Request
|
||||
import semmle.javascript.frameworks.RxJS
|
||||
import semmle.javascript.frameworks.ServerLess
|
||||
import semmle.javascript.frameworks.ShellJS
|
||||
import semmle.javascript.frameworks.Snapdragon
|
||||
import semmle.javascript.frameworks.SystemCommandExecutors
|
||||
import semmle.javascript.frameworks.SQL
|
||||
import semmle.javascript.frameworks.SocketIO
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Provides classes for working with applications using [snapdragon](https://www.npmjs.com/package/snapdragon).
|
||||
*/
|
||||
|
||||
import javascript
|
||||
|
||||
/**
|
||||
* A module modeling taint steps for the [snapdragon](https://www.npmjs.com/package/snapdragon) library.
|
||||
*/
|
||||
private module Snapdragon {
|
||||
private API::Node getSetCall(API::Node base) { result = base.getMember("set").getReturn() }
|
||||
|
||||
/**
|
||||
* A taint step through the [snapdragon](https://www.npmjs.com/package/snapdragon) library.
|
||||
*
|
||||
* Models both parsing (converting a string to an AST) and compilation (converting an AST to a string).
|
||||
* For example:
|
||||
* ```JavaScript
|
||||
* var snapdragon = new (require("snapdragon"))();
|
||||
* snapdragon.parser.set("foo", function () {
|
||||
* sink(this); // <- sink
|
||||
* });
|
||||
* snapdragon.parse("source", opts); // <- source
|
||||
* ```
|
||||
*/
|
||||
private class SnapDragonStep extends DataFlow::SharedFlowStep {
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(string methodName, API::CallNode set, API::CallNode call, API::Node base |
|
||||
// the handler, registered with a call to `.set`.
|
||||
set = getSetCall+(base.getMember(methodName + "r")).getAnImmediateUse() and
|
||||
// the snapdragon instance. The API is chaining, you can also use the instance directly.
|
||||
base = API::moduleImport("snapdragon").getInstance() and
|
||||
methodName = ["parse", "compile"] and
|
||||
(
|
||||
// snapdragon.parse(..)
|
||||
call = getSetCall*(base).getMember(methodName).getACall()
|
||||
or
|
||||
// snapdragon.parser.set().set().parse(..)
|
||||
call = getSetCall*(set.getReturn()).getMember(methodName).getACall()
|
||||
)
|
||||
|
|
||||
pred = call.getArgument(0) and
|
||||
(
|
||||
// for parsers handlers the input is the `this` pointer.
|
||||
methodName = "parse" and
|
||||
succ = DataFlow::thisNode(set.getCallback(1).getFunction())
|
||||
or
|
||||
// for compiler handlers the input is the first parameter.
|
||||
methodName = "compile" and
|
||||
succ = set.getParameter(1).getParameter(0).getAnImmediateUse()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
4
javascript/ql/src/change-notes/2022-02-10-snapdragon.md
Normal file
4
javascript/ql/src/change-notes/2022-02-10-snapdragon.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Added dataflow through the [`snapdragon`](https://npmjs.com/package/snapdragon) library.
|
||||
@@ -34,6 +34,9 @@
|
||||
| lib/lib.js:28:3:28:4 | f* | Strings with many repetitions of 'f' can start matching anywhere after the start of the preceeding f*g |
|
||||
| lib/moduleLib/moduleLib.js:2:3:2:4 | a* | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding a*b |
|
||||
| lib/otherLib/js/src/index.js:2:3:2:4 | a* | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding a*b |
|
||||
| lib/snapdragon.js:7:28:7:29 | a* | Strings starting with 'a' and with many repetitions of 'a' can start matching anywhere after the start of the preceeding aa*$ |
|
||||
| lib/snapdragon.js:15:26:15:27 | a* | Strings starting with 'a' and with many repetitions of 'a' can start matching anywhere after the start of the preceeding aa*$ |
|
||||
| lib/snapdragon.js:23:22:23:23 | a* | Strings starting with 'a' and with many repetitions of 'a' can start matching anywhere after the start of the preceeding aa*$ |
|
||||
| lib/sublib/factory.js:13:14:13:15 | f* | Strings with many repetitions of 'f' can start matching anywhere after the start of the preceeding f*g |
|
||||
| polynomial-redos.js:7:24:7:26 | \\s+ | Strings with many repetitions of ' ' can start matching anywhere after the start of the preceeding \\s+$ |
|
||||
| polynomial-redos.js:8:17:8:18 | * | Strings with many repetitions of ' ' can start matching anywhere after the start of the preceeding *, * |
|
||||
|
||||
@@ -30,6 +30,23 @@ nodes
|
||||
| lib/otherLib/js/src/index.js:1:28:1:31 | name |
|
||||
| lib/otherLib/js/src/index.js:2:13:2:16 | name |
|
||||
| lib/otherLib/js/src/index.js:2:13:2:16 | name |
|
||||
| lib/snapdragon.js:3:34:3:38 | input |
|
||||
| lib/snapdragon.js:3:34:3:38 | input |
|
||||
| lib/snapdragon.js:7:15:7:18 | this |
|
||||
| lib/snapdragon.js:7:15:7:18 | this |
|
||||
| lib/snapdragon.js:9:12:9:16 | input |
|
||||
| lib/snapdragon.js:12:34:12:38 | input |
|
||||
| lib/snapdragon.js:12:34:12:38 | input |
|
||||
| lib/snapdragon.js:15:13:15:16 | this |
|
||||
| lib/snapdragon.js:15:13:15:16 | this |
|
||||
| lib/snapdragon.js:17:20:17:24 | input |
|
||||
| lib/snapdragon.js:20:34:20:38 | input |
|
||||
| lib/snapdragon.js:20:34:20:38 | input |
|
||||
| lib/snapdragon.js:22:44:22:47 | node |
|
||||
| lib/snapdragon.js:23:5:23:8 | node |
|
||||
| lib/snapdragon.js:23:5:23:12 | node.val |
|
||||
| lib/snapdragon.js:23:5:23:12 | node.val |
|
||||
| lib/snapdragon.js:25:22:25:26 | input |
|
||||
| lib/sublib/factory.js:12:26:12:29 | name |
|
||||
| lib/sublib/factory.js:12:26:12:29 | name |
|
||||
| lib/sublib/factory.js:13:24:13:27 | name |
|
||||
@@ -207,6 +224,20 @@ edges
|
||||
| lib/otherLib/js/src/index.js:1:28:1:31 | name | lib/otherLib/js/src/index.js:2:13:2:16 | name |
|
||||
| lib/otherLib/js/src/index.js:1:28:1:31 | name | lib/otherLib/js/src/index.js:2:13:2:16 | name |
|
||||
| lib/otherLib/js/src/index.js:1:28:1:31 | name | lib/otherLib/js/src/index.js:2:13:2:16 | name |
|
||||
| lib/snapdragon.js:3:34:3:38 | input | lib/snapdragon.js:9:12:9:16 | input |
|
||||
| lib/snapdragon.js:3:34:3:38 | input | lib/snapdragon.js:9:12:9:16 | input |
|
||||
| lib/snapdragon.js:9:12:9:16 | input | lib/snapdragon.js:7:15:7:18 | this |
|
||||
| lib/snapdragon.js:9:12:9:16 | input | lib/snapdragon.js:7:15:7:18 | this |
|
||||
| lib/snapdragon.js:12:34:12:38 | input | lib/snapdragon.js:17:20:17:24 | input |
|
||||
| lib/snapdragon.js:12:34:12:38 | input | lib/snapdragon.js:17:20:17:24 | input |
|
||||
| lib/snapdragon.js:17:20:17:24 | input | lib/snapdragon.js:15:13:15:16 | this |
|
||||
| lib/snapdragon.js:17:20:17:24 | input | lib/snapdragon.js:15:13:15:16 | this |
|
||||
| lib/snapdragon.js:20:34:20:38 | input | lib/snapdragon.js:25:22:25:26 | input |
|
||||
| lib/snapdragon.js:20:34:20:38 | input | lib/snapdragon.js:25:22:25:26 | input |
|
||||
| lib/snapdragon.js:22:44:22:47 | node | lib/snapdragon.js:23:5:23:8 | node |
|
||||
| lib/snapdragon.js:23:5:23:8 | node | lib/snapdragon.js:23:5:23:12 | node.val |
|
||||
| lib/snapdragon.js:23:5:23:8 | node | lib/snapdragon.js:23:5:23:12 | node.val |
|
||||
| lib/snapdragon.js:25:22:25:26 | input | lib/snapdragon.js:22:44:22:47 | node |
|
||||
| lib/sublib/factory.js:12:26:12:29 | name | lib/sublib/factory.js:13:24:13:27 | name |
|
||||
| lib/sublib/factory.js:12:26:12:29 | name | lib/sublib/factory.js:13:24:13:27 | name |
|
||||
| lib/sublib/factory.js:12:26:12:29 | name | lib/sublib/factory.js:13:24:13:27 | name |
|
||||
@@ -355,6 +386,9 @@ edges
|
||||
| lib/lib.js:8:2:8:17 | /f*g/.test(name) | lib/lib.js:7:19:7:22 | name | lib/lib.js:8:13:8:16 | name | This $@ that depends on $@ may run slow on strings with many repetitions of 'f'. | lib/lib.js:8:3:8:4 | f* | regular expression | lib/lib.js:7:19:7:22 | name | library input |
|
||||
| lib/moduleLib/moduleLib.js:2:2:2:17 | /a*b/.test(name) | lib/moduleLib/moduleLib.js:1:28:1:31 | name | lib/moduleLib/moduleLib.js:2:13:2:16 | name | This $@ that depends on $@ may run slow on strings with many repetitions of 'a'. | lib/moduleLib/moduleLib.js:2:3:2:4 | a* | regular expression | lib/moduleLib/moduleLib.js:1:28:1:31 | name | library input |
|
||||
| lib/otherLib/js/src/index.js:2:2:2:17 | /a*b/.test(name) | lib/otherLib/js/src/index.js:1:28:1:31 | name | lib/otherLib/js/src/index.js:2:13:2:16 | name | This $@ that depends on $@ may run slow on strings with many repetitions of 'a'. | lib/otherLib/js/src/index.js:2:3:2:4 | a* | regular expression | lib/otherLib/js/src/index.js:1:28:1:31 | name | library input |
|
||||
| lib/snapdragon.js:7:15:7:32 | this.match(/aa*$/) | lib/snapdragon.js:3:34:3:38 | input | lib/snapdragon.js:7:15:7:18 | this | This $@ that depends on $@ may run slow on strings starting with 'a' and with many repetitions of 'a'. | lib/snapdragon.js:7:28:7:29 | a* | regular expression | lib/snapdragon.js:3:34:3:38 | input | library input |
|
||||
| lib/snapdragon.js:15:13:15:30 | this.match(/aa*$/) | lib/snapdragon.js:12:34:12:38 | input | lib/snapdragon.js:15:13:15:16 | this | This $@ that depends on $@ may run slow on strings starting with 'a' and with many repetitions of 'a'. | lib/snapdragon.js:15:26:15:27 | a* | regular expression | lib/snapdragon.js:12:34:12:38 | input | library input |
|
||||
| lib/snapdragon.js:23:5:23:26 | node.va ... /aa*$/) | lib/snapdragon.js:20:34:20:38 | input | lib/snapdragon.js:23:5:23:12 | node.val | This $@ that depends on $@ may run slow on strings starting with 'a' and with many repetitions of 'a'. | lib/snapdragon.js:23:22:23:23 | a* | regular expression | lib/snapdragon.js:20:34:20:38 | input | library input |
|
||||
| lib/sublib/factory.js:13:13:13:28 | /f*g/.test(name) | lib/sublib/factory.js:12:26:12:29 | name | lib/sublib/factory.js:13:24:13:27 | name | This $@ that depends on $@ may run slow on strings with many repetitions of 'f'. | lib/sublib/factory.js:13:14:13:15 | f* | regular expression | lib/sublib/factory.js:12:26:12:29 | name | library input |
|
||||
| polynomial-redos.js:7:2:7:34 | tainted ... /g, '') | polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:7:2:7:8 | tainted | This $@ that depends on $@ may run slow on strings with many repetitions of ' '. | polynomial-redos.js:7:24:7:26 | \\s+ | regular expression | polynomial-redos.js:5:16:5:32 | req.query.tainted | a user-provided value |
|
||||
| polynomial-redos.js:8:2:8:23 | tainted ... *, */) | polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:8:2:8:8 | tainted | This $@ that depends on $@ may run slow on strings with many repetitions of ' '. | polynomial-redos.js:8:17:8:18 | * | regular expression | polynomial-redos.js:5:16:5:32 | req.query.tainted | a user-provided value |
|
||||
|
||||
@@ -26,4 +26,6 @@ module.exports.id = id;
|
||||
module.exports.safe = function (x) {
|
||||
var y = id("safe");
|
||||
/f*g/.test(y); // OK
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.snapdragon = require("./snapdragon")
|
||||
@@ -0,0 +1,26 @@
|
||||
var Snapdragon = require("snapdragon");
|
||||
|
||||
module.exports.test1 = function (input) {
|
||||
var snapdragon = new Snapdragon();
|
||||
var ast = snapdragon.parser
|
||||
.set("foo", function () {
|
||||
var m = this.match(/aa*$/); // NOT OK
|
||||
})
|
||||
.parse(input, options);
|
||||
};
|
||||
|
||||
module.exports.test2 = function (input) {
|
||||
var snapdragon = new Snapdragon();
|
||||
snapdragon.parser.set("foo", function () {
|
||||
var m = this.match(/aa*$/); // NOT OK
|
||||
});
|
||||
snapdragon.parse(input, options);
|
||||
};
|
||||
|
||||
module.exports.test3 = function (input) {
|
||||
var snapdragon = new Snapdragon();
|
||||
snapdragon.compiler.set("foo", function (node) {
|
||||
node.val.match(/aa*$/); // NOT OK
|
||||
});
|
||||
snapdragon.compile(input, options);
|
||||
};
|
||||
Reference in New Issue
Block a user