add model for live-server

This commit is contained in:
Erik Krogh Kristensen
2021-08-30 23:23:06 +02:00
parent b509627113
commit cecb6c7bdd
5 changed files with 104 additions and 0 deletions

View File

@@ -1,6 +1,7 @@
import semmle.javascript.frameworks.Express
import semmle.javascript.frameworks.Hapi
import semmle.javascript.frameworks.Koa
import semmle.javascript.frameworks.LiveServer
import semmle.javascript.frameworks.NodeJSLib
import semmle.javascript.frameworks.Micro
import semmle.javascript.frameworks.Restify

View File

@@ -0,0 +1,59 @@
/**
* Provides classes modelling the [live-server](https://npmjs.com/package/live-server) package.
*/
import javascript
private import semmle.javascript.frameworks.ConnectExpressShared::ConnectExpressShared as ConnectExpressShared
private module LiveServer {
/**
* An expression that imports the live-server package, seen as a server-definition.
*/
class ServerDefinition extends HTTP::Servers::StandardServerDefinition {
API::Node imp;
ServerDefinition() {
imp = API::moduleImport("live-server") and
this = imp.getAnImmediateUse().asExpr()
}
API::Node getImportNode() { result = imp }
}
/**
* A live-server middleware definition.
* `live-server` uses the `connect` library under the hood, so the model is based on the `connect` model.
*/
class RouteHandler extends Connect::RouteHandler, DataFlow::FunctionNode {
RouteHandler() { this = any(RouteSetup setup).getARouteHandler() }
override Parameter getRouteHandlerParameter(string kind) {
result = ConnectExpressShared::getRouteHandlerParameter(astNode, kind)
}
}
/**
* The call to `require("live-server").start()`, seen as a route setup.
*/
class RouteSetup extends MethodCallExpr, HTTP::Servers::StandardRouteSetup {
ServerDefinition server;
API::CallNode call;
RouteSetup() {
call = server.getImportNode().getMember("start").getACall() and
this = call.asExpr()
}
override DataFlow::SourceNode getARouteHandler() {
exists(DataFlow::SourceNode middleware |
middleware = call.getParameter(0).getMember("middleware").getAValueReachingRhs()
|
result = middleware.getAMemberCall(["push", "unshift"]).getArgument(0).getAFunctionValue()
or
result = middleware.(DataFlow::ArrayCreationNode).getAnElement().getAFunctionValue()
)
}
override Expr getServer() { result = server }
}
}

View File

@@ -118,6 +118,18 @@ nodes
| formatting.js:7:14:7:53 | require ... , evil) |
| formatting.js:7:14:7:53 | require ... , evil) |
| formatting.js:7:49:7:52 | evil |
| live-server.js:4:11:4:27 | tainted |
| live-server.js:4:21:4:27 | req.url |
| live-server.js:4:21:4:27 | req.url |
| live-server.js:6:13:6:50 | `<html> ... /html>` |
| live-server.js:6:13:6:50 | `<html> ... /html>` |
| live-server.js:6:28:6:34 | tainted |
| live-server.js:10:11:10:27 | tainted |
| live-server.js:10:21:10:27 | req.url |
| live-server.js:10:21:10:27 | req.url |
| live-server.js:12:13:12:50 | `<html> ... /html>` |
| live-server.js:12:13:12:50 | `<html> ... /html>` |
| live-server.js:12:28:12:34 | tainted |
| pages/Next.jsx:8:13:8:19 | req.url |
| pages/Next.jsx:8:13:8:19 | req.url |
| pages/Next.jsx:8:13:8:19 | req.url |
@@ -325,6 +337,16 @@ edges
| formatting.js:6:43:6:46 | evil | formatting.js:6:14:6:47 | util.fo ... , evil) |
| formatting.js:7:49:7:52 | evil | formatting.js:7:14:7:53 | require ... , evil) |
| formatting.js:7:49:7:52 | evil | formatting.js:7:14:7:53 | require ... , evil) |
| live-server.js:4:11:4:27 | tainted | live-server.js:6:28:6:34 | tainted |
| live-server.js:4:21:4:27 | req.url | live-server.js:4:11:4:27 | tainted |
| live-server.js:4:21:4:27 | req.url | live-server.js:4:11:4:27 | tainted |
| live-server.js:6:28:6:34 | tainted | live-server.js:6:13:6:50 | `<html> ... /html>` |
| live-server.js:6:28:6:34 | tainted | live-server.js:6:13:6:50 | `<html> ... /html>` |
| live-server.js:10:11:10:27 | tainted | live-server.js:12:28:12:34 | tainted |
| live-server.js:10:21:10:27 | req.url | live-server.js:10:11:10:27 | tainted |
| live-server.js:10:21:10:27 | req.url | live-server.js:10:11:10:27 | tainted |
| live-server.js:12:28:12:34 | tainted | live-server.js:12:13:12:50 | `<html> ... /html>` |
| live-server.js:12:28:12:34 | tainted | live-server.js:12:13:12:50 | `<html> ... /html>` |
| pages/Next.jsx:8:13:8:19 | req.url | pages/Next.jsx:8:13:8:19 | req.url |
| pages/Next.jsx:15:13:15:19 | req.url | pages/Next.jsx:15:13:15:19 | req.url |
| pages/api/myapi.js:2:14:2:20 | req.url | pages/api/myapi.js:2:14:2:20 | req.url |
@@ -442,6 +464,8 @@ edges
| etherpad.js:11:12:11:19 | response | etherpad.js:9:16:9:30 | req.query.jsonp | etherpad.js:11:12:11:19 | response | Cross-site scripting vulnerability due to $@. | etherpad.js:9:16:9:30 | req.query.jsonp | user-provided value |
| formatting.js:6:14:6:47 | util.fo ... , evil) | formatting.js:4:16:4:29 | req.query.evil | formatting.js:6:14:6:47 | util.fo ... , evil) | Cross-site scripting vulnerability due to $@. | formatting.js:4:16:4:29 | req.query.evil | user-provided value |
| formatting.js:7:14:7:53 | require ... , evil) | formatting.js:4:16:4:29 | req.query.evil | formatting.js:7:14:7:53 | require ... , evil) | Cross-site scripting vulnerability due to $@. | formatting.js:4:16:4:29 | req.query.evil | user-provided value |
| live-server.js:6:13:6:50 | `<html> ... /html>` | live-server.js:4:21:4:27 | req.url | live-server.js:6:13:6:50 | `<html> ... /html>` | Cross-site scripting vulnerability due to $@. | live-server.js:4:21:4:27 | req.url | user-provided value |
| live-server.js:12:13:12:50 | `<html> ... /html>` | live-server.js:10:21:10:27 | req.url | live-server.js:12:13:12:50 | `<html> ... /html>` | Cross-site scripting vulnerability due to $@. | live-server.js:10:21:10:27 | req.url | user-provided value |
| pages/Next.jsx:8:13:8:19 | req.url | pages/Next.jsx:8:13:8:19 | req.url | pages/Next.jsx:8:13:8:19 | req.url | Cross-site scripting vulnerability due to $@. | pages/Next.jsx:8:13:8:19 | req.url | user-provided value |
| pages/Next.jsx:15:13:15:19 | req.url | pages/Next.jsx:15:13:15:19 | req.url | pages/Next.jsx:15:13:15:19 | req.url | Cross-site scripting vulnerability due to $@. | pages/Next.jsx:15:13:15:19 | req.url | user-provided value |
| pages/api/myapi.js:2:14:2:20 | req.url | pages/api/myapi.js:2:14:2:20 | req.url | pages/api/myapi.js:2:14:2:20 | req.url | Cross-site scripting vulnerability due to $@. | pages/api/myapi.js:2:14:2:20 | req.url | user-provided value |

View File

@@ -25,6 +25,8 @@
| ReflectedXssGood3.js:139:12:139:27 | escapeHtml3(url) | Cross-site scripting vulnerability due to $@. | ReflectedXssGood3.js:135:15:135:27 | req.params.id | user-provided value |
| formatting.js:6:14:6:47 | util.fo ... , evil) | Cross-site scripting vulnerability due to $@. | formatting.js:4:16:4:29 | req.query.evil | user-provided value |
| formatting.js:7:14:7:53 | require ... , evil) | Cross-site scripting vulnerability due to $@. | formatting.js:4:16:4:29 | req.query.evil | user-provided value |
| live-server.js:6:13:6:50 | `<html> ... /html>` | Cross-site scripting vulnerability due to $@. | live-server.js:4:21:4:27 | req.url | user-provided value |
| live-server.js:12:13:12:50 | `<html> ... /html>` | Cross-site scripting vulnerability due to $@. | live-server.js:10:21:10:27 | req.url | user-provided value |
| pages/Next.jsx:8:13:8:19 | req.url | Cross-site scripting vulnerability due to $@. | pages/Next.jsx:8:13:8:19 | req.url | user-provided value |
| pages/Next.jsx:15:13:15:19 | req.url | Cross-site scripting vulnerability due to $@. | pages/Next.jsx:15:13:15:19 | req.url | user-provided value |
| pages/api/myapi.js:2:14:2:20 | req.url | Cross-site scripting vulnerability due to $@. | pages/api/myapi.js:2:14:2:20 | req.url | user-provided value |

View File

@@ -0,0 +1,18 @@
var liveServer = require("live-server");
const middleware = [function(req, res, next) {
const tainted = req.url;
res.end(`<html><body>${tainted}</body></html>`); // NOT OK
}];
middleware.push(function(req, res, next) {
const tainted = req.url;
res.end(`<html><body>${tainted}</body></html>`); // NOT OK
});
var params = {
middleware
};
liveServer.start(params);