mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
Merge pull request #10663 from pwntester/restify_improvements
Javascript: Improve Restify support and add new Spife support
This commit is contained in:
@@ -35,4 +35,3 @@
|
||||
| restify.js:9:5:9:17 | req.trailer() | header |
|
||||
| restify.js:10:5:10:16 | req.header() | header |
|
||||
| restify.js:11:5:11:11 | req.url | url |
|
||||
| restify.js:12:5:12:15 | req.cookies | cookie |
|
||||
|
||||
@@ -299,11 +299,13 @@ test_RemoteFlowSources
|
||||
| src/http.js:30:28:30:32 | chunk |
|
||||
| src/http.js:40:23:40:30 | authInfo |
|
||||
| src/http.js:45:23:45:27 | error |
|
||||
| src/http.js:63:17:63:33 | req.query.myParam |
|
||||
| src/http.js:73:18:73:22 | chunk |
|
||||
| src/http.js:82:18:82:22 | chunk |
|
||||
| src/https.js:6:26:6:32 | req.url |
|
||||
| src/https.js:8:3:8:20 | req.headers.cookie |
|
||||
| src/https.js:9:3:9:17 | req.headers.foo |
|
||||
| src/indirect2.js:10:12:10:25 | req.params.key |
|
||||
| src/indirect.js:17:28:17:34 | req.url |
|
||||
test_RouteHandler
|
||||
| createServer.js:2:20:2:41 | functio ... res) {} | createServer.js:2:1:2:42 | https.c ... es) {}) |
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
var restify = require('restify');
|
||||
const restifyPlugins = require('restify-plugins');
|
||||
var clients = require('restify-clients');
|
||||
|
||||
const opts = {
|
||||
formatters: {
|
||||
'text/plain': function(req, res, body) { // test: formatter
|
||||
if (body instanceof Error) {
|
||||
return '<html><body>' + body.message + '</body></html>'; // test: stackTraceExposureSink
|
||||
} else {
|
||||
return '<html><body>' + body + req.params.name + '</body></html>'; // test: source, stackTraceExposureSink, !xssSink, !xss
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const _server = restify.createServer(opts)
|
||||
|
||||
const server = restify.createServer({
|
||||
formatters: {
|
||||
'text/html': function(req, res, body) { // test: formatter
|
||||
if (body instanceof Error) {
|
||||
return '<html><body>' + body.message + '</body></html>'; // test: stackTraceExposureSink, xssSink
|
||||
} else {
|
||||
return '<html><body>' + body + req.params.name + '</body></html>'; // test: source, stackTraceExposureSink, xssSink, xss
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// The pre handler chain is executed before routing. That means these handlers will execute for an incoming request even if it’s for a route that you did not register.
|
||||
server.pre(restify.plugins.pre.dedupeSlashes());
|
||||
server.pre(function(req, res, next) { // test: handler
|
||||
return next();
|
||||
});
|
||||
|
||||
// The use handler chains is executed after a route has been chosen to service the request.
|
||||
server.use(restifyPlugins.jsonBodyParser({ mapParams: true })); // TODO: prototype pollution?
|
||||
server.use(restifyPlugins.acceptParser(server.acceptable));
|
||||
server.use(restifyPlugins.queryParser({ mapParams: true })); // TODO: prototype pollution?
|
||||
server.use(restifyPlugins.fullResponse());
|
||||
server.use(function(req, res, next) { // test: handler
|
||||
return next();
|
||||
});
|
||||
function filter(req, res, next) { // test: handler
|
||||
return next();
|
||||
}
|
||||
function filter1(req, res, next) { // test: handler
|
||||
return next();
|
||||
}
|
||||
function filter2(req, res, next) { // test: handler
|
||||
return next();
|
||||
}
|
||||
function filter3(req, res, next) { // test: handler
|
||||
return next();
|
||||
}
|
||||
function filter4(req, res, next) { // test: handler
|
||||
return next();
|
||||
}
|
||||
function filter5(req, res, next) { // test: handler
|
||||
return next();
|
||||
}
|
||||
function filter6(req, res, next) { // test: handler
|
||||
return next();
|
||||
}
|
||||
const handlers = [filter5, filter6];
|
||||
server.use(filter); // test: setup
|
||||
server.use(filter1, filter2); // test: setup
|
||||
server.use([filter3, filter4]); // test: setup
|
||||
server.use(handlers); // setup
|
||||
|
||||
function respond(req, res, next) { // test: handler
|
||||
res.send('hello ' + req.params.name); // test: source, stackTraceExposureSink
|
||||
res.send('hello ' + req.params["name"]); // test: source, stackTraceExposureSink
|
||||
res.send('hello ' + req.query.name); // test: source, stackTraceExposureSink
|
||||
res.send('hello ' + req.params[0]); // test: source, stackTraceExposureSink
|
||||
|
||||
res.redirect({
|
||||
hostname: req.params.name, // test: source, redirectSink
|
||||
pathname: '/bar',
|
||||
port: 80,
|
||||
secure: true,
|
||||
permanent: true,
|
||||
query: {
|
||||
a: 1
|
||||
}
|
||||
}, next);
|
||||
res.redirect(301, req.params.name, next); // test: source, redirectSink
|
||||
res.redirect(req.params.name, next); // test: source, redirectSink
|
||||
next();
|
||||
}
|
||||
server.get('/hello/:name', respond); // test: setup
|
||||
server.head('/hello/:name', respond); // test: setup
|
||||
server.get('/', function(req, res, next) { // test: setup, handler
|
||||
res.send('home')
|
||||
return next();
|
||||
});
|
||||
|
||||
server.get('/foo', // test: setup
|
||||
function(req, res, next) { // test: handler
|
||||
req.someData = req.params.name; // test: source
|
||||
return next();
|
||||
},
|
||||
function(req, res, next) { // test: handler
|
||||
res.header("Content-Type", "text/html"); // test: headerDefinition
|
||||
res.send(req.someData); // test: stackTraceExposureSink, xssSink, xss
|
||||
return next();
|
||||
}
|
||||
);
|
||||
|
||||
server.get('/foo2', // test: setup
|
||||
[function(req, res, next) { // test: handler
|
||||
req.someData = 'foo';
|
||||
return next();
|
||||
},
|
||||
function(req, res, next) { // test: handler
|
||||
res.send(req.someData); // test: stackTraceExposureSink
|
||||
return next();
|
||||
}]
|
||||
);
|
||||
|
||||
function xss(req, res, next) { // test: handler
|
||||
res.header("Content-Type", "text/html"); // test: headerDefinition
|
||||
res.send('hello ' + req.query.name); // test: source, stackTraceExposureSink, xssSink, xss
|
||||
next();
|
||||
}
|
||||
|
||||
function xss2(req, res, next) { // test: candidateHandler
|
||||
next()
|
||||
}
|
||||
|
||||
function xss3(req, res, next) { // test: handler
|
||||
res.header("Content-Type", "text/html"); // test: headerDefinition
|
||||
res.send('hello ' + req.header("foo")); // test: source, stackTraceExposureSink, xssSink, !xss
|
||||
next();
|
||||
}
|
||||
|
||||
function xss4(req, res, next) { // test: handler
|
||||
var body = req.params.name; // test: source
|
||||
res.writeHead(200, {
|
||||
'Content-Length': Buffer.byteLength(body),
|
||||
'Content-Type': 'text/html'
|
||||
});
|
||||
res.write(body); // test: stackTraceExposureSink, xssSink, xss
|
||||
res.end();
|
||||
next();
|
||||
}
|
||||
|
||||
server["get"]('/xss', xss); // test: setup
|
||||
["get", "head"].forEach(method => {
|
||||
server[method]('/xss2', xss2);
|
||||
});
|
||||
server["get"]('/xss3', xss3); // test: setup
|
||||
server["get"]('/xss4', xss4); // test: setup
|
||||
|
||||
|
||||
server.get('/testv2', function(req, res, next) { // test: handler
|
||||
res.set({
|
||||
"Content-Type": "text/html",
|
||||
"access-control-allow-origin": "*", // test: corsMiconfigurationSink
|
||||
"access-control-allow-headers": "Content-Type, Authorization, Content-Length, X-Requested-With",
|
||||
"access-control-allow-methods": "GET, POST, PUT, DELETE, OPTIONS",
|
||||
"access-control-allow-credentials": "true"
|
||||
})
|
||||
res.send('hello ' + req.params.name); // test: source, stackTraceExposureSink, xssSink, xss
|
||||
clients.createJsonClient({
|
||||
url: req.params.uri, // test: source, ssrfSink
|
||||
});
|
||||
clients.createJsonClient(req.params.uri); // test: source, ssrfSink
|
||||
|
||||
next();
|
||||
})
|
||||
|
||||
server.get('/hello2/:name', restify.plugins.conditionalHandler([ // test: setup
|
||||
{ version: ['2.0.0', '2.1.0', '2.2.0'], handler: sendV2 }
|
||||
]));
|
||||
|
||||
server.get('/version/test', restify.plugins.conditionalHandler([ //test: setup
|
||||
{
|
||||
version: ['2.0.0', '2.1.0', '2.2.0'],
|
||||
handler: function(req, res, next) { // test: candidateHandler
|
||||
res.send(200, {
|
||||
requestedVersion: req.version(),
|
||||
matchedVersion: req.matchedVersion()
|
||||
});
|
||||
return next();
|
||||
}
|
||||
}
|
||||
]));
|
||||
|
||||
server.on('InternalServer', function(req, res, err, callback) { // test: setup, handler
|
||||
return callback();
|
||||
});
|
||||
|
||||
server.on('restifyError', function(req, res, err, callback) { // test: setup, handler
|
||||
return callback();
|
||||
});
|
||||
server.on('after', function(req, res, route, error) { // test: setup, handler
|
||||
});
|
||||
server.on('pre', function(req, res) { // test: setup, handler
|
||||
});
|
||||
server.on('routed', function(req, res, route) { // test: setup, handler
|
||||
res.header("Content-Type", "text/plain")
|
||||
res.send(req.params.foo) // test: source, !xssSink, !xss
|
||||
});
|
||||
server.on('uncaughtException', function(req, res, route, err) { // test: setup, handler
|
||||
res.header("Content-Type", "text/html")
|
||||
res.send(req.params.foo) // test: source, xssSink, xss
|
||||
});
|
||||
|
||||
|
||||
server.listen(8080, function() {
|
||||
console.log('%s listening at %s', server.name, server.url);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
passingPositiveTests
|
||||
| PASSED | candidateHandler | src/index.js:127:33:127:57 | // test ... Handler |
|
||||
| PASSED | candidateHandler | src/index.js:180:42:180:66 | // test ... Handler |
|
||||
| PASSED | corsMiconfigurationSink | src/index.js:159:41:159:72 | // test ... ionSink |
|
||||
| PASSED | handler | src/index.js:32:39:32:54 | // test: handler |
|
||||
| PASSED | handler | src/index.js:41:39:41:54 | // test: handler |
|
||||
| PASSED | handler | src/index.js:44:35:44:50 | // test: handler |
|
||||
| PASSED | handler | src/index.js:47:36:47:51 | // test: handler |
|
||||
| PASSED | handler | src/index.js:50:36:50:51 | // test: handler |
|
||||
| PASSED | handler | src/index.js:53:36:53:51 | // test: handler |
|
||||
| PASSED | handler | src/index.js:56:36:56:51 | // test: handler |
|
||||
| PASSED | handler | src/index.js:59:36:59:51 | // test: handler |
|
||||
| PASSED | handler | src/index.js:62:36:62:51 | // test: handler |
|
||||
| PASSED | handler | src/index.js:71:36:71:51 | // test: handler |
|
||||
| PASSED | handler | src/index.js:93:44:93:66 | // test ... handler |
|
||||
| PASSED | handler | src/index.js:99:30:99:45 | // test: handler |
|
||||
| PASSED | handler | src/index.js:103:30:103:45 | // test: handler |
|
||||
| PASSED | handler | src/index.js:111:31:111:46 | // test: handler |
|
||||
| PASSED | handler | src/index.js:115:30:115:45 | // test: handler |
|
||||
| PASSED | handler | src/index.js:121:32:121:47 | // test: handler |
|
||||
| PASSED | handler | src/index.js:131:33:131:48 | // test: handler |
|
||||
| PASSED | handler | src/index.js:137:33:137:48 | // test: handler |
|
||||
| PASSED | handler | src/index.js:156:50:156:65 | // test: handler |
|
||||
| PASSED | handler | src/index.js:190:65:190:87 | // test ... handler |
|
||||
| PASSED | handler | src/index.js:194:63:194:85 | // test ... handler |
|
||||
| PASSED | handler | src/index.js:197:55:197:77 | // test ... handler |
|
||||
| PASSED | handler | src/index.js:199:39:199:61 | // test ... handler |
|
||||
| PASSED | handler | src/index.js:201:49:201:71 | // test ... handler |
|
||||
| PASSED | handler | src/index.js:205:65:205:87 | // test ... handler |
|
||||
| PASSED | headerDefinition | src/index.js:104:46:104:70 | // test ... inition |
|
||||
| PASSED | headerDefinition | src/index.js:122:44:122:68 | // test ... inition |
|
||||
| PASSED | headerDefinition | src/index.js:132:44:132:68 | // test ... inition |
|
||||
| PASSED | redirectSink | src/index.js:78:32:78:60 | // test ... ectSink |
|
||||
| PASSED | redirectSink | src/index.js:87:45:87:73 | // test ... ectSink |
|
||||
| PASSED | redirectSink | src/index.js:88:40:88:68 | // test ... ectSink |
|
||||
| PASSED | setup | src/index.js:66:21:66:34 | // test: setup |
|
||||
| PASSED | setup | src/index.js:67:31:67:44 | // test: setup |
|
||||
| PASSED | setup | src/index.js:68:33:68:46 | // test: setup |
|
||||
| PASSED | setup | src/index.js:91:38:91:51 | // test: setup |
|
||||
| PASSED | setup | src/index.js:92:39:92:52 | // test: setup |
|
||||
| PASSED | setup | src/index.js:93:44:93:66 | // test ... handler |
|
||||
| PASSED | setup | src/index.js:98:20:98:33 | // test: setup |
|
||||
| PASSED | setup | src/index.js:110:21:110:34 | // test: setup |
|
||||
| PASSED | setup | src/index.js:148:29:148:42 | // test: setup |
|
||||
| PASSED | setup | src/index.js:152:31:152:44 | // test: setup |
|
||||
| PASSED | setup | src/index.js:153:31:153:44 | // test: setup |
|
||||
| PASSED | setup | src/index.js:173:66:173:79 | // test: setup |
|
||||
| PASSED | setup | src/index.js:177:66:177:78 | //test: setup |
|
||||
| PASSED | setup | src/index.js:190:65:190:87 | // test ... handler |
|
||||
| PASSED | setup | src/index.js:194:63:194:85 | // test ... handler |
|
||||
| PASSED | setup | src/index.js:197:55:197:77 | // test ... handler |
|
||||
| PASSED | setup | src/index.js:199:39:199:61 | // test ... handler |
|
||||
| PASSED | setup | src/index.js:201:49:201:71 | // test ... handler |
|
||||
| PASSED | setup | src/index.js:205:65:205:87 | // test ... handler |
|
||||
| PASSED | source | src/index.js:11:76:11:130 | // test ... k, !xss |
|
||||
| PASSED | source | src/index.js:24:76:24:128 | // test ... nk, xss |
|
||||
| PASSED | source | src/index.js:72:41:72:80 | // test ... reSink |
|
||||
| PASSED | source | src/index.js:73:44:73:82 | // test ... ureSink |
|
||||
| PASSED | source | src/index.js:74:40:74:78 | // test ... ureSink |
|
||||
| PASSED | source | src/index.js:75:39:75:77 | // test ... ureSink |
|
||||
| PASSED | source | src/index.js:78:32:78:60 | // test ... ectSink |
|
||||
| PASSED | source | src/index.js:87:45:87:73 | // test ... ectSink |
|
||||
| PASSED | source | src/index.js:88:40:88:68 | // test ... ectSink |
|
||||
| PASSED | source | src/index.js:100:37:100:51 | // test: source |
|
||||
| PASSED | source | src/index.js:123:40:123:92 | // test ... nk, xss |
|
||||
| PASSED | source | src/index.js:133:43:133:96 | // test ... k, !xss |
|
||||
| PASSED | source | src/index.js:138:31:138:45 | // test: source |
|
||||
| PASSED | source | src/index.js:164:41:164:93 | // test ... nk, xss |
|
||||
| PASSED | source | src/index.js:166:26:166:50 | // test ... srfSink |
|
||||
| PASSED | source | src/index.js:168:45:168:69 | // test ... srfSink |
|
||||
| PASSED | source | src/index.js:203:28:203:58 | // test ... k, !xss |
|
||||
| PASSED | source | src/index.js:207:28:207:56 | // test ... nk, xss |
|
||||
| PASSED | ssrfSink | src/index.js:166:26:166:50 | // test ... srfSink |
|
||||
| PASSED | ssrfSink | src/index.js:168:45:168:69 | // test ... srfSink |
|
||||
| PASSED | stackTraceExposureSink | src/index.js:9:66:9:96 | // test ... ureSink |
|
||||
| PASSED | stackTraceExposureSink | src/index.js:11:76:11:130 | // test ... k, !xss |
|
||||
| PASSED | stackTraceExposureSink | src/index.js:22:66:22:105 | // test ... xssSink |
|
||||
| PASSED | stackTraceExposureSink | src/index.js:24:76:24:128 | // test ... nk, xss |
|
||||
| PASSED | stackTraceExposureSink | src/index.js:72:41:72:80 | // test ... reSink |
|
||||
| PASSED | stackTraceExposureSink | src/index.js:73:44:73:82 | // test ... ureSink |
|
||||
| PASSED | stackTraceExposureSink | src/index.js:74:40:74:78 | // test ... ureSink |
|
||||
| PASSED | stackTraceExposureSink | src/index.js:75:39:75:77 | // test ... ureSink |
|
||||
| PASSED | stackTraceExposureSink | src/index.js:105:29:105:73 | // test ... nk, xss |
|
||||
| PASSED | stackTraceExposureSink | src/index.js:116:29:116:59 | // test ... ureSink |
|
||||
| PASSED | stackTraceExposureSink | src/index.js:123:40:123:92 | // test ... nk, xss |
|
||||
| PASSED | stackTraceExposureSink | src/index.js:133:43:133:96 | // test ... k, !xss |
|
||||
| PASSED | stackTraceExposureSink | src/index.js:143:20:143:64 | // test ... nk, xss |
|
||||
| PASSED | stackTraceExposureSink | src/index.js:164:41:164:93 | // test ... nk, xss |
|
||||
| PASSED | xss | src/index.js:24:76:24:128 | // test ... nk, xss |
|
||||
| PASSED | xss | src/index.js:105:29:105:73 | // test ... nk, xss |
|
||||
| PASSED | xss | src/index.js:123:40:123:92 | // test ... nk, xss |
|
||||
| PASSED | xss | src/index.js:143:20:143:64 | // test ... nk, xss |
|
||||
| PASSED | xss | src/index.js:164:41:164:93 | // test ... nk, xss |
|
||||
| PASSED | xss | src/index.js:207:28:207:56 | // test ... nk, xss |
|
||||
| PASSED | xssSink | src/index.js:22:66:22:105 | // test ... xssSink |
|
||||
| PASSED | xssSink | src/index.js:24:76:24:128 | // test ... nk, xss |
|
||||
| PASSED | xssSink | src/index.js:105:29:105:73 | // test ... nk, xss |
|
||||
| PASSED | xssSink | src/index.js:123:40:123:92 | // test ... nk, xss |
|
||||
| PASSED | xssSink | src/index.js:133:43:133:96 | // test ... k, !xss |
|
||||
| PASSED | xssSink | src/index.js:143:20:143:64 | // test ... nk, xss |
|
||||
| PASSED | xssSink | src/index.js:164:41:164:93 | // test ... nk, xss |
|
||||
| PASSED | xssSink | src/index.js:207:28:207:56 | // test ... nk, xss |
|
||||
failingPositiveTests
|
||||
passingNegativeTests
|
||||
| PASSED | !xss | src/index.js:11:76:11:130 | // test ... k, !xss |
|
||||
| PASSED | !xss | src/index.js:133:43:133:96 | // test ... k, !xss |
|
||||
| PASSED | !xss | src/index.js:203:28:203:58 | // test ... k, !xss |
|
||||
| PASSED | !xssSink | src/index.js:11:76:11:130 | // test ... k, !xss |
|
||||
| PASSED | !xssSink | src/index.js:203:28:203:58 | // test ... k, !xss |
|
||||
failingNegativeTests
|
||||
229
javascript/ql/test/library-tests/frameworks/Restify2/tests.ql
Normal file
229
javascript/ql/test/library-tests/frameworks/Restify2/tests.ql
Normal file
@@ -0,0 +1,229 @@
|
||||
import javascript
|
||||
import semmle.javascript.security.dataflow.CleartextStorageCustomizations
|
||||
import semmle.javascript.security.dataflow.CorsMisconfigurationForCredentialsCustomizations
|
||||
import semmle.javascript.security.dataflow.StackTraceExposureCustomizations
|
||||
import semmle.javascript.security.dataflow.ServerSideUrlRedirectCustomizations
|
||||
import semmle.javascript.security.dataflow.RequestForgeryCustomizations
|
||||
import semmle.javascript.security.dataflow.ReflectedXssCustomizations
|
||||
import semmle.javascript.security.dataflow.ReflectedXssQuery as XssConfig
|
||||
|
||||
class InlineTest extends LineComment {
|
||||
string tests;
|
||||
|
||||
InlineTest() { tests = this.getText().regexpCapture("\\s*test:(.*)", 1) }
|
||||
|
||||
string getPositiveTest() {
|
||||
result = tests.trim().splitAt(",").trim() and not result.matches("!%")
|
||||
}
|
||||
|
||||
string getNegativeTest() { result = tests.trim().splitAt(",").trim() and result.matches("!%") }
|
||||
|
||||
predicate hasPositiveTest(string test) { test = this.getPositiveTest() }
|
||||
|
||||
predicate hasNegativeTest(string test) { test = this.getNegativeTest() }
|
||||
|
||||
predicate inNode(DataFlow::Node n) {
|
||||
this.getLocation().getFile() = n.getFile() and
|
||||
this.getLocation().getStartLine() = n.getStartLine()
|
||||
}
|
||||
}
|
||||
|
||||
query predicate passingPositiveTests(string res, string expectation, InlineTest t) {
|
||||
res = "PASSED" and
|
||||
t.hasPositiveTest(expectation) and
|
||||
(
|
||||
expectation = "headerDefinition" and
|
||||
exists(Http::HeaderDefinition n | t.inNode(n))
|
||||
or
|
||||
expectation = "cookieDefinition" and
|
||||
exists(Http::CookieDefinition n | t.inNode(n))
|
||||
or
|
||||
expectation = "templateInstantiation" and
|
||||
exists(Templating::TemplateInstantiation::Range n | t.inNode(n))
|
||||
or
|
||||
expectation = "source" and
|
||||
exists(RemoteFlowSource n | t.inNode(n))
|
||||
or
|
||||
expectation = "setup" and
|
||||
exists(Http::RouteSetup n | t.inNode(n))
|
||||
or
|
||||
expectation = "handler" and
|
||||
exists(Http::RouteHandler n | t.inNode(n))
|
||||
or
|
||||
expectation = "candidateHandler" and
|
||||
exists(Http::RouteHandlerCandidate n | t.inNode(n))
|
||||
or
|
||||
expectation = "xssSink" and
|
||||
exists(ReflectedXss::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "xss" and
|
||||
exists(XssConfig::Configuration cfg, DataFlow::Node sink |
|
||||
cfg.hasFlow(_, sink) and t.inNode(sink)
|
||||
)
|
||||
or
|
||||
expectation = "cleartextStorageSink" and
|
||||
exists(CleartextStorage::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "corsMiconfigurationSink" and
|
||||
exists(CorsMisconfigurationForCredentials::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "stackTraceExposureSink" and
|
||||
exists(StackTraceExposure::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "redirectSink" and
|
||||
exists(ServerSideUrlRedirect::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "ssrfSink" and
|
||||
exists(RequestForgery::Sink n | t.inNode(n))
|
||||
)
|
||||
}
|
||||
|
||||
query predicate failingPositiveTests(string res, string expectation, InlineTest t) {
|
||||
res = "FAILED" and
|
||||
t.hasPositiveTest(expectation) and
|
||||
(
|
||||
expectation = "headerDefinition" and
|
||||
not exists(Http::HeaderDefinition n | t.inNode(n))
|
||||
or
|
||||
expectation = "cookieDefinition" and
|
||||
not exists(Http::CookieDefinition n | t.inNode(n))
|
||||
or
|
||||
expectation = "templateInstantiation" and
|
||||
not exists(Templating::TemplateInstantiation::Range n | t.inNode(n))
|
||||
or
|
||||
expectation = "source" and
|
||||
not exists(RemoteFlowSource n | t.inNode(n))
|
||||
or
|
||||
expectation = "setup" and
|
||||
not exists(Http::RouteSetup n | t.inNode(n))
|
||||
or
|
||||
expectation = "handler" and
|
||||
not exists(Http::RouteHandler n | t.inNode(n))
|
||||
or
|
||||
expectation = "candidateHandler" and
|
||||
not exists(Http::RouteHandlerCandidate n | t.inNode(n))
|
||||
or
|
||||
expectation = "xssSink" and
|
||||
not exists(ReflectedXss::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "xss" and
|
||||
not exists(XssConfig::Configuration cfg, DataFlow::Node sink |
|
||||
cfg.hasFlow(_, sink) and t.inNode(sink)
|
||||
)
|
||||
or
|
||||
expectation = "cleartextStorageSink" and
|
||||
not exists(CleartextStorage::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "corsMiconfigurationSink" and
|
||||
not exists(CorsMisconfigurationForCredentials::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "stackTraceExposureSink" and
|
||||
not exists(StackTraceExposure::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "redirectSink" and
|
||||
not exists(ServerSideUrlRedirect::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "ssrfSink" and
|
||||
not exists(RequestForgery::Sink n | t.inNode(n))
|
||||
)
|
||||
}
|
||||
|
||||
query predicate passingNegativeTests(string res, string expectation, InlineTest t) {
|
||||
res = "PASSED" and
|
||||
t.hasNegativeTest(expectation) and
|
||||
(
|
||||
expectation = "!headerDefinition" and
|
||||
not exists(Http::HeaderDefinition n | t.inNode(n))
|
||||
or
|
||||
expectation = "!cookieDefinition" and
|
||||
not exists(Http::CookieDefinition n | t.inNode(n))
|
||||
or
|
||||
expectation = "!templateInstantiation" and
|
||||
not exists(Templating::TemplateInstantiation::Range n | t.inNode(n))
|
||||
or
|
||||
expectation = "!source" and
|
||||
not exists(RemoteFlowSource n | t.inNode(n))
|
||||
or
|
||||
expectation = "!setup" and
|
||||
not exists(Http::RouteSetup n | t.inNode(n))
|
||||
or
|
||||
expectation = "!handler" and
|
||||
not exists(Http::RouteHandler n | t.inNode(n))
|
||||
or
|
||||
expectation = "!candidateHandler" and
|
||||
not exists(Http::RouteHandlerCandidate n | t.inNode(n))
|
||||
or
|
||||
expectation = "!xssSink" and
|
||||
not exists(ReflectedXss::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "!xss" and
|
||||
not exists(XssConfig::Configuration cfg, DataFlow::Node sink |
|
||||
cfg.hasFlow(_, sink) and t.inNode(sink)
|
||||
)
|
||||
or
|
||||
expectation = "!cleartextStorageSink" and
|
||||
not exists(CleartextStorage::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "!corsMiconfigurationSink" and
|
||||
not exists(CorsMisconfigurationForCredentials::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "!stackTraceExposureSink" and
|
||||
not exists(StackTraceExposure::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "!redirectSink" and
|
||||
not exists(ServerSideUrlRedirect::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "!ssrfSink" and
|
||||
not exists(RequestForgery::Sink n | t.inNode(n))
|
||||
)
|
||||
}
|
||||
|
||||
query predicate failingNegativeTests(string res, string expectation, InlineTest t) {
|
||||
res = "FAILED" and
|
||||
t.hasNegativeTest(expectation) and
|
||||
(
|
||||
expectation = "!headerDefinition" and
|
||||
exists(Http::HeaderDefinition n | t.inNode(n))
|
||||
or
|
||||
expectation = "!cookieDefinition" and
|
||||
exists(Http::CookieDefinition n | t.inNode(n))
|
||||
or
|
||||
expectation = "!templateInstantiation" and
|
||||
exists(Templating::TemplateInstantiation::Range n | t.inNode(n))
|
||||
or
|
||||
expectation = "!source" and
|
||||
exists(RemoteFlowSource n | t.inNode(n))
|
||||
or
|
||||
expectation = "!setup" and
|
||||
exists(Http::RouteSetup n | t.inNode(n))
|
||||
or
|
||||
expectation = "!handler" and
|
||||
exists(Http::RouteHandler n | t.inNode(n))
|
||||
or
|
||||
expectation = "!candidateHandler" and
|
||||
exists(Http::RouteHandlerCandidate n | t.inNode(n))
|
||||
or
|
||||
expectation = "!xssSink" and
|
||||
exists(ReflectedXss::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "!xss" and
|
||||
exists(XssConfig::Configuration cfg, DataFlow::Node sink |
|
||||
cfg.hasFlow(_, sink) and t.inNode(sink)
|
||||
)
|
||||
or
|
||||
expectation = "!cleartextStorageSink" and
|
||||
exists(CleartextStorage::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "!corsMiconfigurationSink" and
|
||||
exists(CorsMisconfigurationForCredentials::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "!stackTraceExposureSink" and
|
||||
exists(StackTraceExposure::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "!redirectSink" and
|
||||
exists(ServerSideUrlRedirect::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "!ssrfSink" and
|
||||
exists(RequestForgery::Sink n | t.inNode(n))
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
'use strict'
|
||||
|
||||
const routes = require('@npm/spife/routing')
|
||||
|
||||
module.exports = routes`
|
||||
GET / homepage
|
||||
GET /test1 test1
|
||||
GET /test1 test2
|
||||
GET /test4 test4
|
||||
GET /test5 test5
|
||||
GET /test6 test6
|
||||
GET /raw1 raw1
|
||||
GET /raw2 raw2
|
||||
POST /body parseBody
|
||||
GET /redirect/:redirect_url redirect
|
||||
POST /packages/new createPackage
|
||||
`(require('../views'))
|
||||
|
||||
|
||||
const a = routes`GET /packages/package/${p} viewPackage`(require('../views')) // test:routeSetup
|
||||
|
||||
const b = routes`GET / list`({ ...require('../views'), ...require('../views/orgs') }) // test: routeSetup
|
||||
|
||||
const c = routes`POST /message handleMessage`({ handleMessage: console.log }) // test: routeSetup
|
||||
|
||||
const d = routes`GET /version versionHandler`({ versionHandler: (req, context) => { console.log(req) } }) // test: routeSetup
|
||||
|
||||
const e = routes`GET / handler`({ handler: async (req, context) => { console.log(req) } }) // test: routeSetup
|
||||
@@ -0,0 +1,46 @@
|
||||
'use strict'
|
||||
|
||||
const { Environment, FileSystemLoader } = require('nunjucks')
|
||||
const Loader = require('@npm/spife/templates/loader')
|
||||
const path = require('path')
|
||||
|
||||
const isDev = !new Set(['prod', 'production', 'stag', 'staging']).has(
|
||||
process.env.NODE_ENV
|
||||
)
|
||||
|
||||
const templateDirs = [path.join(__dirname, '..', 'templates')]
|
||||
const nunjucksEnv = new Environment(new FileSystemLoader(templateDirs))
|
||||
const nunjucksLoader = new Loader({
|
||||
dirs: templateDirs,
|
||||
load (resolved) {
|
||||
const template = nunjucksEnv.getTemplate(resolved.path, true)
|
||||
return context => {
|
||||
return template.render(context)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
module.exports = {
|
||||
DEBUG: process.env.DEBUG,
|
||||
ENABLE_FORM_PARSING: false,
|
||||
METRICS: process.env.METRICS,
|
||||
MIDDLEWARE: [
|
||||
'@npm/spife/middleware/debug',
|
||||
['@npm/spife/middleware/template', [
|
||||
nunjucksLoader
|
||||
], [
|
||||
// template context processors go here
|
||||
]],
|
||||
'@npm/spife/middleware/common',
|
||||
'@npm/spife/middleware/logging',
|
||||
'@npm/spife/middleware/metrics',
|
||||
'@npm/spife/middleware/monitor',
|
||||
'@npm/spife/middleware/hot-reload',
|
||||
['@npm/spife/middleware/csrf', { secureCookie: !isDev }]
|
||||
],
|
||||
NAME: 'nunjucks-example',
|
||||
NODE_ENV: process.env.NODE_ENV,
|
||||
PORT: 8124,
|
||||
ROUTER: './routes/index.js',
|
||||
HOT: true
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
'use strict'
|
||||
|
||||
const reply = require('@npm/spife/reply')
|
||||
const validate = require('@npm/spife/decorators/validate')
|
||||
const joi = require('@npm/spife/joi')
|
||||
const concat = require('concat-stream')
|
||||
|
||||
const createPackageSchema = joi.object().keys({
|
||||
contents: joi.string().max(200).required(),
|
||||
destination: joi.any().valid([
|
||||
joi.object({
|
||||
name: joi.string().max(200).required(),
|
||||
address: joi.string().max(200).required()
|
||||
}),
|
||||
joi.string().min(1)
|
||||
])
|
||||
})
|
||||
|
||||
module.exports = { homepage, parseBody, raw1, raw2, test1, test2, test3, test4, test5, test6, redirect, createPackage: validate.body(createPackageSchema, createPackage), }
|
||||
|
||||
function sink(obj) { console.log(obj) }
|
||||
|
||||
function createPackage(req, context) { // test: handler
|
||||
const tainted = req.validatedBody.get('destination') // test: source
|
||||
sink(taitned)
|
||||
}
|
||||
|
||||
function homepage(req, context) { // test: handler
|
||||
sink(req.cookie("test")) // test: source
|
||||
sink(req.cookies().test) // test: source
|
||||
sink(req.headers.test) // test: source
|
||||
sink(req.rawHeaders[0]) // test: source
|
||||
sink(req.raw.headers) // test: source
|
||||
sink(req.url) // test: source
|
||||
sink(req.urlObject.pathname) // test: source
|
||||
sink(context.get('package')) // test: source
|
||||
sink(context)
|
||||
return reply.template('home', { target: req.query.name }) // test: source, templateInstantiation, stackTraceExposureSink, responseBody
|
||||
}
|
||||
|
||||
function raw1(req, context) { // test: handler
|
||||
sink(req.query.name) // test: source
|
||||
return reply(req.query.name, 200, { // test: source, xssSink, stackTraceExposureSink, xss
|
||||
"content-type": "text/html", // test: headerDefinition
|
||||
"access-control-allow-origin": "*", // test: corsMiconfigurationSink, headerDefinition
|
||||
"access-control-allow-headers": "Content-Type, Authorization, Content-Length, X-Requested-With", // test: headerDefinition
|
||||
"access-control-allow-methods": "GET, POST, PUT, DELETE, OPTIONS", // test: headerDefinition
|
||||
"access-control-allow-credentials": "true" //test: headerDefinition
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
function redirect(req, context) { // test: handler
|
||||
return reply.redirect(context.get('redirect_url')) // test: redirectSink, source
|
||||
}
|
||||
function raw2(req, context) { // test: handler
|
||||
return reply.cookie({ "test": req.query.name }, "test", req.query.name, { "httpOnly": false, "secure": false }) // test: source, cleartextStorageSink, stackTraceExposureSink, cookieDefinition
|
||||
}
|
||||
|
||||
function test1(req, context) { // test: handler
|
||||
switch (req.accept.type(['json', 'html', 'plain'])) {
|
||||
case 'json':
|
||||
return { "some": req.query.name } // test: source, stackTraceExposureSink
|
||||
case 'html':
|
||||
return reply.header('<p>' + req.query.name + '</p>', 'content-type', 'text/html') // test: source, xssSink, stackTraceExposureSink, xss, headerDefinition
|
||||
case 'plain':
|
||||
return reply.header('<p>' + req.query.name + '</p>', { 'content-type': 'text/plain' }) // test: source, stackTraceExposureSink, !xssSink, !xss, headerDefinition, headerDefinition
|
||||
}
|
||||
return 'well, I guess you just want plaintext.'
|
||||
}
|
||||
|
||||
function test2(req, context) { // test: handler
|
||||
switch (req.accept.type(['json', 'html'])) {
|
||||
case 'json':
|
||||
return { "some": req.query.name } // test: source, stackTraceExposureSink
|
||||
case 'html':
|
||||
return reply.header('<p>' + req.query.name + '</p>', { 'content-type': 'text/plain' }) // test: source, stackTraceExposureSink, !xssSink, !xss, headerDefinition
|
||||
}
|
||||
return 'well, I guess you just want plaintext.'
|
||||
}
|
||||
|
||||
function test3(req, context) { // test: candidateHandler
|
||||
return reply('<p>' + req.query.name + '</p>')
|
||||
}
|
||||
|
||||
function test4(req, context) { // test: handler
|
||||
const body = req.body // test: source
|
||||
const newPackument = body['package-json']
|
||||
const message = `INFO: User invited to package ${newPackument._id} successfully.`
|
||||
return reply(message, 200, { 'npm-notice': message }) // test: stackTraceExposureSink, !xssSink, !xss, headerDefinition
|
||||
}
|
||||
|
||||
function test5(req, context) { // test: handler
|
||||
const body = req.body // test: source
|
||||
const newPackument = body['package-json']
|
||||
const message = `INFO: User invited to package ${newPackument._id} successfully.`
|
||||
return reply(message, 200) // test: stackTraceExposureSink, !xssSink, !xss
|
||||
}
|
||||
|
||||
function test6(req, context) { // test: handler
|
||||
const body = req.body // test: source
|
||||
const newPackument = body['package-json']
|
||||
const message = `INFO: User invited to package ${newPackument._id} successfully.`
|
||||
if (message.contains('foo')) {
|
||||
return reply(message, 200, { 'npm-notice': message }) // test: stackTraceExposureSink, !xssSink, !xss, headerDefinition
|
||||
} else {
|
||||
return reply(message, 200, { 'npm-notice': message, 'content-type': 'text/html' }) // test: stackTraceExposureSink, xssSink, xss, headerDefinition
|
||||
}
|
||||
}
|
||||
|
||||
function parseBody(req, context) {
|
||||
return req.body.then(data => { // test: source, stackTraceExposureSink
|
||||
sink(data.name)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
passingPositiveTests
|
||||
| PASSED | candidateHandler | lib/views/index.js:82:32:82:56 | // test ... Handler |
|
||||
| PASSED | cleartextStorageSink | lib/views/index.js:57:115:57:193 | // test ... inition |
|
||||
| PASSED | cookieDefinition | lib/views/index.js:57:115:57:193 | // test ... inition |
|
||||
| PASSED | corsMiconfigurationSink | lib/views/index.js:45:41:45:90 | // test ... inition |
|
||||
| PASSED | handler | lib/views/index.js:23:40:23:55 | // test: handler |
|
||||
| PASSED | handler | lib/views/index.js:28:35:28:50 | // test: handler |
|
||||
| PASSED | handler | lib/views/index.js:41:31:41:46 | // test: handler |
|
||||
| PASSED | handler | lib/views/index.js:53:35:53:50 | // test: handler |
|
||||
| PASSED | handler | lib/views/index.js:56:31:56:46 | // test: handler |
|
||||
| PASSED | handler | lib/views/index.js:60:32:60:47 | // test: handler |
|
||||
| PASSED | handler | lib/views/index.js:72:32:72:47 | // test: handler |
|
||||
| PASSED | handler | lib/views/index.js:86:32:86:47 | // test: handler |
|
||||
| PASSED | handler | lib/views/index.js:93:32:93:47 | // test: handler |
|
||||
| PASSED | handler | lib/views/index.js:100:32:100:47 | // test: handler |
|
||||
| PASSED | headerDefinition | lib/views/index.js:44:34:44:58 | // test ... inition |
|
||||
| PASSED | headerDefinition | lib/views/index.js:45:41:45:90 | // test ... inition |
|
||||
| PASSED | headerDefinition | lib/views/index.js:46:102:46:126 | // test ... inition |
|
||||
| PASSED | headerDefinition | lib/views/index.js:47:72:47:96 | // test ... inition |
|
||||
| PASSED | headerDefinition | lib/views/index.js:48:48:48:71 | //test: ... inition |
|
||||
| PASSED | headerDefinition | lib/views/index.js:65:89:65:159 | // test ... inition |
|
||||
| PASSED | headerDefinition | lib/views/index.js:67:94:67:184 | // test ... inition |
|
||||
| PASSED | headerDefinition | lib/views/index.js:77:94:77:166 | // test ... inition |
|
||||
| PASSED | headerDefinition | lib/views/index.js:90:57:90:121 | // test ... inition |
|
||||
| PASSED | headerDefinition | lib/views/index.js:105:59:105:123 | // test ... inition |
|
||||
| PASSED | headerDefinition | lib/views/index.js:107:88:107:150 | // test ... inition |
|
||||
| PASSED | redirectSink | lib/views/index.js:54:54:54:82 | // test ... source |
|
||||
| PASSED | responseBody | lib/views/index.js:38:61:38:136 | // test ... nseBody |
|
||||
| PASSED | routeSetup | lib/routes/index.js:20:79:20:96 | // test:routeSetup |
|
||||
| PASSED | routeSetup | lib/routes/index.js:22:87:22:105 | // test: routeSetup |
|
||||
| PASSED | routeSetup | lib/routes/index.js:24:81:24:99 | // test: routeSetup |
|
||||
| PASSED | routeSetup | lib/routes/index.js:26:107:26:125 | // test: routeSetup |
|
||||
| PASSED | routeSetup | lib/routes/index.js:28:92:28:110 | // test: routeSetup |
|
||||
| PASSED | source | lib/views/index.js:24:56:24:70 | // test: source |
|
||||
| PASSED | source | lib/views/index.js:29:28:29:42 | // test: source |
|
||||
| PASSED | source | lib/views/index.js:30:28:30:42 | // test: source |
|
||||
| PASSED | source | lib/views/index.js:31:26:31:40 | // test: source |
|
||||
| PASSED | source | lib/views/index.js:32:27:32:41 | // test: source |
|
||||
| PASSED | source | lib/views/index.js:33:25:33:39 | // test: source |
|
||||
| PASSED | source | lib/views/index.js:34:17:34:31 | // test: source |
|
||||
| PASSED | source | lib/views/index.js:35:32:35:46 | // test: source |
|
||||
| PASSED | source | lib/views/index.js:36:32:36:46 | // test: source |
|
||||
| PASSED | source | lib/views/index.js:38:61:38:136 | // test ... nseBody |
|
||||
| PASSED | source | lib/views/index.js:42:24:42:38 | // test: source |
|
||||
| PASSED | source | lib/views/index.js:43:39:43:91 | // test ... nk, xss |
|
||||
| PASSED | source | lib/views/index.js:54:54:54:82 | // test ... source |
|
||||
| PASSED | source | lib/views/index.js:57:115:57:193 | // test ... inition |
|
||||
| PASSED | source | lib/views/index.js:63:41:63:79 | // test ... ureSink |
|
||||
| PASSED | source | lib/views/index.js:65:89:65:159 | // test ... inition |
|
||||
| PASSED | source | lib/views/index.js:67:94:67:184 | // test ... inition |
|
||||
| PASSED | source | lib/views/index.js:75:41:75:79 | // test ... ureSink |
|
||||
| PASSED | source | lib/views/index.js:77:94:77:166 | // test ... inition |
|
||||
| PASSED | source | lib/views/index.js:87:25:87:39 | // test: source |
|
||||
| PASSED | source | lib/views/index.js:94:25:94:39 | // test: source |
|
||||
| PASSED | source | lib/views/index.js:101:25:101:39 | // test: source |
|
||||
| PASSED | source | lib/views/index.js:112:34:112:72 | // test ... ureSink |
|
||||
| PASSED | stackTraceExposureSink | lib/views/index.js:38:61:38:136 | // test ... nseBody |
|
||||
| PASSED | stackTraceExposureSink | lib/views/index.js:43:39:43:91 | // test ... nk, xss |
|
||||
| PASSED | stackTraceExposureSink | lib/views/index.js:57:115:57:193 | // test ... inition |
|
||||
| PASSED | stackTraceExposureSink | lib/views/index.js:63:41:63:79 | // test ... ureSink |
|
||||
| PASSED | stackTraceExposureSink | lib/views/index.js:65:89:65:159 | // test ... inition |
|
||||
| PASSED | stackTraceExposureSink | lib/views/index.js:67:94:67:184 | // test ... inition |
|
||||
| PASSED | stackTraceExposureSink | lib/views/index.js:75:41:75:79 | // test ... ureSink |
|
||||
| PASSED | stackTraceExposureSink | lib/views/index.js:77:94:77:166 | // test ... inition |
|
||||
| PASSED | stackTraceExposureSink | lib/views/index.js:90:57:90:121 | // test ... inition |
|
||||
| PASSED | stackTraceExposureSink | lib/views/index.js:97:30:97:76 | // test ... k, !xss |
|
||||
| PASSED | stackTraceExposureSink | lib/views/index.js:105:59:105:123 | // test ... inition |
|
||||
| PASSED | stackTraceExposureSink | lib/views/index.js:107:88:107:150 | // test ... inition |
|
||||
| PASSED | stackTraceExposureSink | lib/views/index.js:112:34:112:72 | // test ... ureSink |
|
||||
| PASSED | templateInstantiation | lib/views/index.js:38:61:38:136 | // test ... nseBody |
|
||||
| PASSED | xss | lib/views/index.js:43:39:43:91 | // test ... nk, xss |
|
||||
| PASSED | xss | lib/views/index.js:65:89:65:159 | // test ... inition |
|
||||
| PASSED | xss | lib/views/index.js:107:88:107:150 | // test ... inition |
|
||||
| PASSED | xssSink | lib/views/index.js:43:39:43:91 | // test ... nk, xss |
|
||||
| PASSED | xssSink | lib/views/index.js:65:89:65:159 | // test ... inition |
|
||||
| PASSED | xssSink | lib/views/index.js:107:88:107:150 | // test ... inition |
|
||||
failingPositiveTests
|
||||
passingNegativeTests
|
||||
| PASSED | !xss | lib/views/index.js:67:94:67:184 | // test ... inition |
|
||||
| PASSED | !xss | lib/views/index.js:77:94:77:166 | // test ... inition |
|
||||
| PASSED | !xss | lib/views/index.js:90:57:90:121 | // test ... inition |
|
||||
| PASSED | !xss | lib/views/index.js:97:30:97:76 | // test ... k, !xss |
|
||||
| PASSED | !xss | lib/views/index.js:105:59:105:123 | // test ... inition |
|
||||
| PASSED | !xssSink | lib/views/index.js:67:94:67:184 | // test ... inition |
|
||||
| PASSED | !xssSink | lib/views/index.js:77:94:77:166 | // test ... inition |
|
||||
| PASSED | !xssSink | lib/views/index.js:90:57:90:121 | // test ... inition |
|
||||
| PASSED | !xssSink | lib/views/index.js:97:30:97:76 | // test ... k, !xss |
|
||||
| PASSED | !xssSink | lib/views/index.js:105:59:105:123 | // test ... inition |
|
||||
failingNegativeTests
|
||||
253
javascript/ql/test/library-tests/frameworks/Spife/tests.ql
Normal file
253
javascript/ql/test/library-tests/frameworks/Spife/tests.ql
Normal file
@@ -0,0 +1,253 @@
|
||||
import javascript
|
||||
import semmle.javascript.security.dataflow.CleartextStorageCustomizations
|
||||
import semmle.javascript.security.dataflow.CorsMisconfigurationForCredentialsCustomizations
|
||||
import semmle.javascript.security.dataflow.StackTraceExposureCustomizations
|
||||
import semmle.javascript.security.dataflow.ServerSideUrlRedirectCustomizations
|
||||
import semmle.javascript.security.dataflow.RequestForgeryCustomizations
|
||||
import semmle.javascript.security.dataflow.ReflectedXssCustomizations
|
||||
import semmle.javascript.security.dataflow.ReflectedXssQuery as XssConfig
|
||||
|
||||
class InlineTest extends LineComment {
|
||||
string tests;
|
||||
|
||||
InlineTest() { tests = this.getText().regexpCapture("\\s*test:(.*)", 1) }
|
||||
|
||||
string getPositiveTest() {
|
||||
result = tests.trim().splitAt(",").trim() and not result.matches("!%")
|
||||
}
|
||||
|
||||
string getNegativeTest() { result = tests.trim().splitAt(",").trim() and result.matches("!%") }
|
||||
|
||||
predicate hasPositiveTest(string test) { test = this.getPositiveTest() }
|
||||
|
||||
predicate hasNegativeTest(string test) { test = this.getNegativeTest() }
|
||||
|
||||
predicate inNode(DataFlow::Node n) {
|
||||
this.getLocation().getFile() = n.getFile() and
|
||||
this.getLocation().getStartLine() = n.getStartLine()
|
||||
}
|
||||
}
|
||||
|
||||
query predicate passingPositiveTests(string res, string expectation, InlineTest t) {
|
||||
res = "PASSED" and
|
||||
t.hasPositiveTest(expectation) and
|
||||
(
|
||||
expectation = "responseBody" and
|
||||
exists(Http::ResponseBody n | t.inNode(n))
|
||||
or
|
||||
expectation = "headerDefinition" and
|
||||
exists(DataFlow::Node n, Http::ExplicitHeaderDefinition h |
|
||||
t.inNode(n) and
|
||||
h.definesHeaderValue(_, n)
|
||||
)
|
||||
or
|
||||
expectation = "cookieDefinition" and
|
||||
exists(Http::CookieDefinition n | t.inNode(n))
|
||||
or
|
||||
expectation = "templateInstantiation" and
|
||||
exists(Templating::TemplateInstantiation::Range n | t.inNode(n))
|
||||
or
|
||||
expectation = "source" and
|
||||
exists(RemoteFlowSource n | t.inNode(n))
|
||||
or
|
||||
expectation = "routeSetup" and
|
||||
exists(Http::RouteSetup n | t.inNode(n))
|
||||
or
|
||||
expectation = "handler" and
|
||||
exists(Http::RouteHandler n | t.inNode(n))
|
||||
or
|
||||
expectation = "candidateHandler" and
|
||||
exists(Http::RouteHandlerCandidate n | t.inNode(n))
|
||||
or
|
||||
expectation = "xssSink" and
|
||||
exists(ReflectedXss::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "xss" and
|
||||
exists(XssConfig::Configuration cfg, DataFlow::Node sink |
|
||||
cfg.hasFlow(_, sink) and t.inNode(sink)
|
||||
)
|
||||
or
|
||||
expectation = "cleartextStorageSink" and
|
||||
exists(CleartextStorage::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "corsMiconfigurationSink" and
|
||||
exists(CorsMisconfigurationForCredentials::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "stackTraceExposureSink" and
|
||||
exists(StackTraceExposure::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "redirectSink" and
|
||||
exists(ServerSideUrlRedirect::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "ssrfSink" and
|
||||
exists(RequestForgery::Sink n | t.inNode(n))
|
||||
)
|
||||
}
|
||||
|
||||
query predicate failingPositiveTests(string res, string expectation, InlineTest t) {
|
||||
res = "FAILED" and
|
||||
t.hasPositiveTest(expectation) and
|
||||
(
|
||||
expectation = "responseBody" and
|
||||
not exists(Http::ResponseBody n | t.inNode(n))
|
||||
or
|
||||
expectation = "headerDefinition" and
|
||||
not exists(DataFlow::Node n, Http::ExplicitHeaderDefinition h |
|
||||
t.inNode(n) and
|
||||
h.definesHeaderValue(_, n)
|
||||
)
|
||||
or
|
||||
expectation = "cookieDefinition" and
|
||||
not exists(Http::CookieDefinition n | t.inNode(n))
|
||||
or
|
||||
expectation = "templateInstantiation" and
|
||||
not exists(Templating::TemplateInstantiation::Range n | t.inNode(n))
|
||||
or
|
||||
expectation = "source" and
|
||||
not exists(RemoteFlowSource n | t.inNode(n))
|
||||
or
|
||||
expectation = "routeSetup" and
|
||||
not exists(Http::RouteSetup n | t.inNode(n))
|
||||
or
|
||||
expectation = "handler" and
|
||||
not exists(Http::RouteHandler n | t.inNode(n))
|
||||
or
|
||||
expectation = "candidateHandler" and
|
||||
not exists(Http::RouteHandlerCandidate n | t.inNode(n))
|
||||
or
|
||||
expectation = "xssSink" and
|
||||
not exists(ReflectedXss::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "xss" and
|
||||
not exists(XssConfig::Configuration cfg, DataFlow::Node sink |
|
||||
cfg.hasFlow(_, sink) and t.inNode(sink)
|
||||
)
|
||||
or
|
||||
expectation = "cleartextStorageSink" and
|
||||
not exists(CleartextStorage::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "corsMiconfigurationSink" and
|
||||
not exists(CorsMisconfigurationForCredentials::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "stackTraceExposureSink" and
|
||||
not exists(StackTraceExposure::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "redirectSink" and
|
||||
not exists(ServerSideUrlRedirect::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "ssrfSink" and
|
||||
not exists(RequestForgery::Sink n | t.inNode(n))
|
||||
)
|
||||
}
|
||||
|
||||
query predicate passingNegativeTests(string res, string expectation, InlineTest t) {
|
||||
res = "PASSED" and
|
||||
t.hasNegativeTest(expectation) and
|
||||
(
|
||||
expectation = "!responseBody" and
|
||||
not exists(Http::ResponseBody n | t.inNode(n))
|
||||
or
|
||||
expectation = "!headerDefinition" and
|
||||
not exists(DataFlow::Node n, Http::ExplicitHeaderDefinition h |
|
||||
t.inNode(n) and
|
||||
h.definesHeaderValue(_, n)
|
||||
)
|
||||
or
|
||||
expectation = "!cookieDefinition" and
|
||||
not exists(Http::CookieDefinition n | t.inNode(n))
|
||||
or
|
||||
expectation = "!templateInstantiation" and
|
||||
not exists(Templating::TemplateInstantiation::Range n | t.inNode(n))
|
||||
or
|
||||
expectation = "!source" and
|
||||
not exists(RemoteFlowSource n | t.inNode(n))
|
||||
or
|
||||
expectation = "!routeSetup" and
|
||||
not exists(Http::RouteSetup n | t.inNode(n))
|
||||
or
|
||||
expectation = "!handler" and
|
||||
not exists(Http::RouteHandler n | t.inNode(n))
|
||||
or
|
||||
expectation = "!candidateHandler" and
|
||||
not exists(Http::RouteHandlerCandidate n | t.inNode(n))
|
||||
or
|
||||
expectation = "!xssSink" and
|
||||
not exists(ReflectedXss::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "!xss" and
|
||||
not exists(XssConfig::Configuration cfg, DataFlow::Node sink |
|
||||
cfg.hasFlow(_, sink) and t.inNode(sink)
|
||||
)
|
||||
or
|
||||
expectation = "!cleartextStorageSink" and
|
||||
not exists(CleartextStorage::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "!corsMiconfigurationSink" and
|
||||
not exists(CorsMisconfigurationForCredentials::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "!stackTraceExposureSink" and
|
||||
not exists(StackTraceExposure::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "!redirectSink" and
|
||||
not exists(ServerSideUrlRedirect::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "!ssrfSink" and
|
||||
not exists(RequestForgery::Sink n | t.inNode(n))
|
||||
)
|
||||
}
|
||||
|
||||
query predicate failingNegativeTests(string res, string expectation, InlineTest t) {
|
||||
res = "FAILED" and
|
||||
t.hasNegativeTest(expectation) and
|
||||
(
|
||||
expectation = "!responseBody" and
|
||||
exists(Http::ResponseBody n | t.inNode(n))
|
||||
or
|
||||
expectation = "!headerDefinition" and
|
||||
not exists(DataFlow::Node n, Http::ExplicitHeaderDefinition h |
|
||||
t.inNode(n) and
|
||||
h.definesHeaderValue(_, n)
|
||||
)
|
||||
or
|
||||
expectation = "!cookieDefinition" and
|
||||
exists(Http::CookieDefinition n | t.inNode(n))
|
||||
or
|
||||
expectation = "!templateInstantiation" and
|
||||
exists(Templating::TemplateInstantiation::Range n | t.inNode(n))
|
||||
or
|
||||
expectation = "!source" and
|
||||
exists(RemoteFlowSource n | t.inNode(n))
|
||||
or
|
||||
expectation = "!routeSetup" and
|
||||
exists(Http::RouteSetup n | t.inNode(n))
|
||||
or
|
||||
expectation = "!handler" and
|
||||
exists(Http::RouteHandler n | t.inNode(n))
|
||||
or
|
||||
expectation = "!candidateHandler" and
|
||||
exists(Http::RouteHandlerCandidate n | t.inNode(n))
|
||||
or
|
||||
expectation = "!xssSink" and
|
||||
exists(ReflectedXss::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "!xss" and
|
||||
exists(XssConfig::Configuration cfg, DataFlow::Node sink |
|
||||
cfg.hasFlow(_, sink) and t.inNode(sink)
|
||||
)
|
||||
or
|
||||
expectation = "!cleartextStorageSink" and
|
||||
exists(CleartextStorage::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "!corsMiconfigurationSink" and
|
||||
exists(CorsMisconfigurationForCredentials::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "!stackTraceExposureSink" and
|
||||
exists(StackTraceExposure::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "!redirectSink" and
|
||||
exists(ServerSideUrlRedirect::Sink n | t.inNode(n))
|
||||
or
|
||||
expectation = "!ssrfSink" and
|
||||
exists(RequestForgery::Sink n | t.inNode(n))
|
||||
)
|
||||
}
|
||||
@@ -11,10 +11,16 @@ test_RequestInputAccess
|
||||
| src/test.js:19:5:19:26 | request ... ('bar') | header | src/test.js:12:19:22:1 | functio ... okie;\\n} |
|
||||
| src/test.js:20:5:20:25 | request ... ('baz') | header | src/test.js:12:19:22:1 | functio ... okie;\\n} |
|
||||
test_RouteHandler_getAResponseHeader
|
||||
| src/test.js:6:1:6:21 | functio ... er1(){} | content-type | src/test.js:6:1:6:21 | functio ... er1(){} |
|
||||
| src/test.js:9:19:11:1 | functio ... ition\\n} | content-type | src/test.js:9:19:11:1 | functio ... ition\\n} |
|
||||
| src/test.js:9:19:11:1 | functio ... ition\\n} | header1 | src/test.js:10:5:10:34 | respons ... 1', '') |
|
||||
| src/test.js:12:19:22:1 | functio ... okie;\\n} | content-type | src/test.js:12:19:22:1 | functio ... okie;\\n} |
|
||||
| src/test.js:12:19:22:1 | functio ... okie;\\n} | header2 | src/test.js:13:5:13:37 | respons ... 2', '') |
|
||||
test_HeaderDefinition_defines
|
||||
| src/test.js:6:1:6:21 | functio ... er1(){} | content-type | application/json |
|
||||
| src/test.js:9:19:11:1 | functio ... ition\\n} | content-type | application/json |
|
||||
| src/test.js:10:5:10:34 | respons ... 1', '') | header1 | |
|
||||
| src/test.js:12:19:22:1 | functio ... okie;\\n} | content-type | application/json |
|
||||
| src/test.js:13:5:13:37 | respons ... 2', '') | header2 | |
|
||||
test_ResponseExpr
|
||||
| src/test.js:9:46:9:53 | response | src/test.js:9:19:11:1 | functio ... ition\\n} |
|
||||
@@ -24,14 +30,20 @@ test_ResponseExpr
|
||||
| src/test.js:12:46:12:53 | response | src/test.js:12:19:22:1 | functio ... okie;\\n} |
|
||||
| src/test.js:13:5:13:12 | response | src/test.js:12:19:22:1 | functio ... okie;\\n} |
|
||||
test_HeaderDefinition
|
||||
| src/test.js:6:1:6:21 | functio ... er1(){} | src/test.js:6:1:6:21 | functio ... er1(){} |
|
||||
| src/test.js:9:19:11:1 | functio ... ition\\n} | src/test.js:9:19:11:1 | functio ... ition\\n} |
|
||||
| src/test.js:10:5:10:34 | respons ... 1', '') | src/test.js:9:19:11:1 | functio ... ition\\n} |
|
||||
| src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:12:19:22:1 | functio ... okie;\\n} |
|
||||
| src/test.js:13:5:13:37 | respons ... 2', '') | src/test.js:12:19:22:1 | functio ... okie;\\n} |
|
||||
test_RouteSetup_getServer
|
||||
| src/test.js:7:1:7:26 | server2 ... ndler1) | src/test.js:4:15:4:36 | restify ... erver() |
|
||||
| src/test.js:9:1:11:2 | server2 ... tion\\n}) | src/test.js:4:15:4:36 | restify ... erver() |
|
||||
| src/test.js:12:1:22:2 | server2 ... kie;\\n}) | src/test.js:4:15:4:36 | restify ... erver() |
|
||||
test_HeaderDefinition_getAHeaderName
|
||||
| src/test.js:6:1:6:21 | functio ... er1(){} | content-type |
|
||||
| src/test.js:9:19:11:1 | functio ... ition\\n} | content-type |
|
||||
| src/test.js:10:5:10:34 | respons ... 1', '') | header1 |
|
||||
| src/test.js:12:19:22:1 | functio ... okie;\\n} | content-type |
|
||||
| src/test.js:13:5:13:37 | respons ... 2', '') | header2 |
|
||||
test_ServerDefinition
|
||||
| src/test.js:1:15:1:47 | require ... erver() |
|
||||
|
||||
Reference in New Issue
Block a user