Merge branch 'amammad-js-JWT' of https://github.com/amammad/codeql into amammad-js-JWT

This commit is contained in:
am0o0
2024-06-06 14:04:46 +02:00
15585 changed files with 1445070 additions and 827541 deletions

View File

@@ -0,0 +1,22 @@
passingPositiveTests
| PASSED | CommandInjection | tests.js:11:46:11:70 | // test ... jection |
| PASSED | CommandInjection | tests.js:12:43:12:67 | // test ... jection |
| PASSED | CommandInjection | tests.js:13:63:13:87 | // test ... jection |
| PASSED | CommandInjection | tests.js:14:62:14:86 | // test ... jection |
| PASSED | CommandInjection | tests.js:15:60:15:84 | // test ... jection |
| PASSED | CommandInjection | tests.js:17:45:17:69 | // test ... jection |
| PASSED | CommandInjection | tests.js:18:42:18:66 | // test ... jection |
| PASSED | CommandInjection | tests.js:19:62:19:86 | // test ... jection |
| PASSED | CommandInjection | tests.js:20:63:20:87 | // test ... jection |
| PASSED | CommandInjection | tests.js:21:60:21:84 | // test ... jection |
| PASSED | CommandInjection | tests.js:23:43:23:67 | // test ... jection |
| PASSED | CommandInjection | tests.js:24:40:24:64 | // test ... jection |
| PASSED | CommandInjection | tests.js:25:40:25:64 | // test ... jection |
| PASSED | CommandInjection | tests.js:26:60:26:84 | // test ... jection |
| PASSED | CommandInjection | tests.js:28:41:28:65 | // test ... jection |
| PASSED | CommandInjection | tests.js:29:58:29:82 | // test ... jection |
| PASSED | CommandInjection | tests.js:31:51:31:75 | // test ... jection |
| PASSED | CommandInjection | tests.js:32:68:32:92 | // test ... jection |
| PASSED | CommandInjection | tests.js:34:49:34:73 | // test ... jection |
| PASSED | CommandInjection | tests.js:35:66:35:90 | // test ... jection |
failingPositiveTests

View File

@@ -0,0 +1,36 @@
import { execa, execaSync, execaCommand, execaCommandSync, $ } from 'execa';
import http from 'node:http'
import url from 'url'
http.createServer(async function (req, res) {
let cmd = url.parse(req.url, true).query["cmd"][0];
let arg1 = url.parse(req.url, true).query["arg1"];
let arg2 = url.parse(req.url, true).query["arg2"];
let arg3 = url.parse(req.url, true).query["arg3"];
await $`${cmd} ${arg1} ${arg2} ${arg3}`; // test: CommandInjection
await $`ssh ${arg1} ${arg2} ${arg3}`; // test: CommandInjection
$({ shell: false }).sync`${cmd} ${arg1} ${arg2} ${arg3}`; // test: CommandInjection
$({ shell: true }).sync`${cmd} ${arg1} ${arg2} ${arg3}`; // test: CommandInjection
$({ shell: false }).sync`ssh ${arg1} ${arg2} ${arg3}`; // test: CommandInjection
$.sync`${cmd} ${arg1} ${arg2} ${arg3}`; // test: CommandInjection
$.sync`ssh ${arg1} ${arg2} ${arg3}`; // test: CommandInjection
await $({ shell: true })`${cmd} ${arg1} ${arg2} ${arg3}` // test: CommandInjection
await $({ shell: false })`${cmd} ${arg1} ${arg2} ${arg3}` // test: CommandInjection
await $({ shell: false })`ssh ${arg1} ${arg2} ${arg3}` // test: CommandInjection
await execa(cmd, [arg1, arg2, arg3]); // test: CommandInjection
await execa(cmd, { shell: true }); // test: CommandInjection
await execa(cmd, { shell: true }); // test: CommandInjection
await execa(cmd, [arg1, arg2, arg3], { shell: true }); // test: CommandInjection
execaSync(cmd, [arg1, arg2, arg3]); // test: CommandInjection
execaSync(cmd, [arg1, arg2, arg3], { shell: true }); // test: CommandInjection
await execaCommand(cmd + arg1 + arg2 + arg3); // test: CommandInjection
await execaCommand(cmd + arg1 + arg2 + arg3, { shell: true }); // test: CommandInjection
execaCommandSync(cmd + arg1 + arg2 + arg3); // test: CommandInjection
execaCommandSync(cmd + arg1 + arg2 + arg3, { shell: true }); // test: CommandInjection
});

View File

@@ -0,0 +1,38 @@
import javascript
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("!%")
}
predicate hasPositiveTest(string test) { test = this.getPositiveTest() }
predicate inNode(DataFlow::Node n) {
this.getLocation().getFile() = n.getFile() and
this.getLocation().getStartLine() = n.getStartLine()
}
}
import experimental.semmle.javascript.Execa
query predicate passingPositiveTests(string res, string expectation, InlineTest t) {
res = "PASSED" and
t.hasPositiveTest(expectation) and
expectation = "CommandInjection" and
exists(SystemCommandExecution n |
t.inNode(n.getArgumentList()) or t.inNode(n.getACommandArgument())
)
}
query predicate failingPositiveTests(string res, string expectation, InlineTest t) {
res = "FAILED" and
t.hasPositiveTest(expectation) and
expectation = "CommandInjection" and
not exists(SystemCommandExecution n |
t.inNode(n.getArgumentList()) or t.inNode(n.getACommandArgument())
)
}

View File

@@ -0,0 +1,6 @@
passingPositiveTests
| PASSED | PathInjection | tests.js:9:43:9:64 | // test ... jection |
| PASSED | PathInjection | tests.js:12:50:12:71 | // test ... jection |
| PASSED | PathInjection | tests.js:15:61:15:82 | // test ... jection |
| PASSED | PathInjection | tests.js:18:73:18:94 | // test ... jection |
failingPositiveTests

View File

@@ -0,0 +1,19 @@
import { execa, $ } from 'execa';
import http from 'node:http'
import url from 'url'
http.createServer(async function (req, res) {
let filePath = url.parse(req.url, true).query["filePath"][0];
// Piping to stdin from a file
await $({ inputFile: filePath })`cat` // test: PathInjection
// Piping to stdin from a file
await execa('cat', { inputFile: filePath }); // test: PathInjection
// Piping Stdout to file
await execa('echo', ['example3']).pipeStdout(filePath); // test: PathInjection
// Piping all of command output to file
await execa('echo', ['example4'], { all: true }).pipeAll(filePath); // test: PathInjection
});

View File

@@ -0,0 +1,34 @@
import javascript
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("!%")
}
predicate hasPositiveTest(string test) { test = this.getPositiveTest() }
predicate inNode(DataFlow::Node n) {
this.getLocation().getFile() = n.getFile() and
this.getLocation().getStartLine() = n.getStartLine()
}
}
import experimental.semmle.javascript.Execa
query predicate passingPositiveTests(string res, string expectation, InlineTest t) {
res = "PASSED" and
t.hasPositiveTest(expectation) and
expectation = "PathInjection" and
exists(FileSystemReadAccess n | t.inNode(n.getAPathArgument()))
}
query predicate failingPositiveTests(string res, string expectation, InlineTest t) {
res = "FAILED" and
t.hasPositiveTest(expectation) and
expectation = "PathInjection" and
not exists(FileSystemReadAccess n | t.inNode(n.getAPathArgument()))
}

View File

@@ -0,0 +1,234 @@
nodes
| busybus.js:9:30:9:33 | file |
| busybus.js:9:30:9:33 | file |
| busybus.js:9:36:9:39 | info |
| busybus.js:9:36:9:39 | info |
| busybus.js:10:19:10:50 | { filen ... eType } |
| busybus.js:10:19:10:57 | encoding |
| busybus.js:10:19:10:57 | filename |
| busybus.js:10:19:10:57 | mimeType |
| busybus.js:10:21:10:28 | filename |
| busybus.js:10:31:10:38 | encoding |
| busybus.js:10:41:10:48 | mimeType |
| busybus.js:10:54:10:57 | info |
| busybus.js:12:18:12:25 | filename |
| busybus.js:12:18:12:25 | filename |
| busybus.js:12:28:12:35 | encoding |
| busybus.js:12:28:12:35 | encoding |
| busybus.js:12:38:12:45 | mimeType |
| busybus.js:12:38:12:45 | mimeType |
| busybus.js:13:23:13:23 | z |
| busybus.js:13:31:13:36 | sink() |
| busybus.js:13:31:13:36 | sink() |
| busybus.js:15:30:15:33 | data |
| busybus.js:15:30:15:33 | data |
| busybus.js:16:22:16:25 | data |
| busybus.js:16:22:16:25 | data |
| busybus.js:22:25:22:42 | data |
| busybus.js:22:32:22:42 | this.read() |
| busybus.js:22:32:22:42 | this.read() |
| busybus.js:23:26:23:29 | data |
| busybus.js:23:26:23:29 | data |
| busybus.js:27:25:27:28 | name |
| busybus.js:27:25:27:28 | name |
| busybus.js:27:31:27:33 | val |
| busybus.js:27:31:27:33 | val |
| busybus.js:27:36:27:39 | info |
| busybus.js:27:36:27:39 | info |
| busybus.js:28:18:28:21 | name |
| busybus.js:28:18:28:21 | name |
| busybus.js:28:24:28:26 | val |
| busybus.js:28:24:28:26 | val |
| busybus.js:28:29:28:32 | info |
| busybus.js:28:29:28:32 | info |
| dicer.js:12:23:12:26 | part |
| dicer.js:12:23:12:26 | part |
| dicer.js:13:19:13:24 | sink() |
| dicer.js:13:19:13:24 | sink() |
| dicer.js:14:28:14:33 | header |
| dicer.js:14:28:14:33 | header |
| dicer.js:16:22:16:27 | header |
| dicer.js:16:22:16:30 | header[h] |
| dicer.js:16:22:16:30 | header[h] |
| dicer.js:19:26:19:29 | data |
| dicer.js:19:26:19:29 | data |
| dicer.js:20:18:20:21 | data |
| dicer.js:20:18:20:21 | data |
| formidable.js:7:11:7:25 | [fields, files] |
| formidable.js:7:11:7:49 | fields |
| formidable.js:7:11:7:49 | files |
| formidable.js:7:12:7:17 | fields |
| formidable.js:7:20:7:24 | files |
| formidable.js:7:29:7:49 | await f ... se(req) |
| formidable.js:7:35:7:49 | form.parse(req) |
| formidable.js:7:35:7:49 | form.parse(req) |
| formidable.js:8:10:8:15 | fields |
| formidable.js:8:10:8:15 | fields |
| formidable.js:8:18:8:22 | files |
| formidable.js:8:18:8:22 | files |
| formidable.js:9:27:9:34 | formname |
| formidable.js:9:27:9:34 | formname |
| formidable.js:9:37:9:40 | file |
| formidable.js:9:37:9:40 | file |
| formidable.js:10:14:10:21 | formname |
| formidable.js:10:14:10:21 | formname |
| formidable.js:10:24:10:27 | file |
| formidable.js:10:24:10:27 | file |
| formidable.js:12:22:12:29 | formname |
| formidable.js:12:22:12:29 | formname |
| formidable.js:12:32:12:35 | file |
| formidable.js:12:32:12:35 | file |
| formidable.js:13:14:13:21 | formname |
| formidable.js:13:14:13:21 | formname |
| formidable.js:13:24:13:27 | file |
| formidable.js:13:24:13:27 | file |
| formidable.js:15:23:15:31 | fieldName |
| formidable.js:15:23:15:31 | fieldName |
| formidable.js:15:34:15:43 | fieldValue |
| formidable.js:15:34:15:43 | fieldValue |
| formidable.js:16:14:16:22 | fieldName |
| formidable.js:16:14:16:22 | fieldName |
| formidable.js:16:25:16:34 | fieldValue |
| formidable.js:16:25:16:34 | fieldValue |
| multiparty.js:8:22:8:25 | part |
| multiparty.js:8:22:8:25 | part |
| multiparty.js:9:14:9:17 | part |
| multiparty.js:9:14:9:17 | part |
| multiparty.js:10:19:10:24 | sink() |
| multiparty.js:10:19:10:24 | sink() |
| multiparty.js:14:37:14:42 | fields |
| multiparty.js:14:37:14:42 | fields |
| multiparty.js:14:45:14:49 | files |
| multiparty.js:14:45:14:49 | files |
| multiparty.js:15:14:15:19 | fields |
| multiparty.js:15:14:15:19 | fields |
| multiparty.js:15:22:15:26 | files |
| multiparty.js:15:22:15:26 | files |
edges
| busybus.js:9:30:9:33 | file | busybus.js:13:23:13:23 | z |
| busybus.js:9:30:9:33 | file | busybus.js:13:23:13:23 | z |
| busybus.js:9:36:9:39 | info | busybus.js:10:54:10:57 | info |
| busybus.js:9:36:9:39 | info | busybus.js:10:54:10:57 | info |
| busybus.js:10:19:10:50 | { filen ... eType } | busybus.js:10:21:10:28 | filename |
| busybus.js:10:19:10:50 | { filen ... eType } | busybus.js:10:31:10:38 | encoding |
| busybus.js:10:19:10:50 | { filen ... eType } | busybus.js:10:41:10:48 | mimeType |
| busybus.js:10:19:10:57 | encoding | busybus.js:12:28:12:35 | encoding |
| busybus.js:10:19:10:57 | encoding | busybus.js:12:28:12:35 | encoding |
| busybus.js:10:19:10:57 | filename | busybus.js:12:18:12:25 | filename |
| busybus.js:10:19:10:57 | filename | busybus.js:12:18:12:25 | filename |
| busybus.js:10:19:10:57 | mimeType | busybus.js:12:38:12:45 | mimeType |
| busybus.js:10:19:10:57 | mimeType | busybus.js:12:38:12:45 | mimeType |
| busybus.js:10:21:10:28 | filename | busybus.js:10:19:10:57 | filename |
| busybus.js:10:31:10:38 | encoding | busybus.js:10:19:10:57 | encoding |
| busybus.js:10:41:10:48 | mimeType | busybus.js:10:19:10:57 | mimeType |
| busybus.js:10:54:10:57 | info | busybus.js:10:19:10:50 | { filen ... eType } |
| busybus.js:13:23:13:23 | z | busybus.js:13:31:13:36 | sink() |
| busybus.js:13:23:13:23 | z | busybus.js:13:31:13:36 | sink() |
| busybus.js:15:30:15:33 | data | busybus.js:16:22:16:25 | data |
| busybus.js:15:30:15:33 | data | busybus.js:16:22:16:25 | data |
| busybus.js:15:30:15:33 | data | busybus.js:16:22:16:25 | data |
| busybus.js:15:30:15:33 | data | busybus.js:16:22:16:25 | data |
| busybus.js:22:25:22:42 | data | busybus.js:23:26:23:29 | data |
| busybus.js:22:25:22:42 | data | busybus.js:23:26:23:29 | data |
| busybus.js:22:32:22:42 | this.read() | busybus.js:22:25:22:42 | data |
| busybus.js:22:32:22:42 | this.read() | busybus.js:22:25:22:42 | data |
| busybus.js:27:25:27:28 | name | busybus.js:28:18:28:21 | name |
| busybus.js:27:25:27:28 | name | busybus.js:28:18:28:21 | name |
| busybus.js:27:25:27:28 | name | busybus.js:28:18:28:21 | name |
| busybus.js:27:25:27:28 | name | busybus.js:28:18:28:21 | name |
| busybus.js:27:31:27:33 | val | busybus.js:28:24:28:26 | val |
| busybus.js:27:31:27:33 | val | busybus.js:28:24:28:26 | val |
| busybus.js:27:31:27:33 | val | busybus.js:28:24:28:26 | val |
| busybus.js:27:31:27:33 | val | busybus.js:28:24:28:26 | val |
| busybus.js:27:36:27:39 | info | busybus.js:28:29:28:32 | info |
| busybus.js:27:36:27:39 | info | busybus.js:28:29:28:32 | info |
| busybus.js:27:36:27:39 | info | busybus.js:28:29:28:32 | info |
| busybus.js:27:36:27:39 | info | busybus.js:28:29:28:32 | info |
| dicer.js:12:23:12:26 | part | dicer.js:13:19:13:24 | sink() |
| dicer.js:12:23:12:26 | part | dicer.js:13:19:13:24 | sink() |
| dicer.js:12:23:12:26 | part | dicer.js:13:19:13:24 | sink() |
| dicer.js:12:23:12:26 | part | dicer.js:13:19:13:24 | sink() |
| dicer.js:14:28:14:33 | header | dicer.js:16:22:16:27 | header |
| dicer.js:14:28:14:33 | header | dicer.js:16:22:16:27 | header |
| dicer.js:16:22:16:27 | header | dicer.js:16:22:16:30 | header[h] |
| dicer.js:16:22:16:27 | header | dicer.js:16:22:16:30 | header[h] |
| dicer.js:19:26:19:29 | data | dicer.js:20:18:20:21 | data |
| dicer.js:19:26:19:29 | data | dicer.js:20:18:20:21 | data |
| dicer.js:19:26:19:29 | data | dicer.js:20:18:20:21 | data |
| dicer.js:19:26:19:29 | data | dicer.js:20:18:20:21 | data |
| formidable.js:7:11:7:25 | [fields, files] | formidable.js:7:12:7:17 | fields |
| formidable.js:7:11:7:25 | [fields, files] | formidable.js:7:20:7:24 | files |
| formidable.js:7:11:7:49 | fields | formidable.js:8:10:8:15 | fields |
| formidable.js:7:11:7:49 | fields | formidable.js:8:10:8:15 | fields |
| formidable.js:7:11:7:49 | files | formidable.js:8:18:8:22 | files |
| formidable.js:7:11:7:49 | files | formidable.js:8:18:8:22 | files |
| formidable.js:7:12:7:17 | fields | formidable.js:7:11:7:49 | fields |
| formidable.js:7:20:7:24 | files | formidable.js:7:11:7:49 | files |
| formidable.js:7:29:7:49 | await f ... se(req) | formidable.js:7:11:7:25 | [fields, files] |
| formidable.js:7:35:7:49 | form.parse(req) | formidable.js:7:29:7:49 | await f ... se(req) |
| formidable.js:7:35:7:49 | form.parse(req) | formidable.js:7:29:7:49 | await f ... se(req) |
| formidable.js:9:27:9:34 | formname | formidable.js:10:14:10:21 | formname |
| formidable.js:9:27:9:34 | formname | formidable.js:10:14:10:21 | formname |
| formidable.js:9:27:9:34 | formname | formidable.js:10:14:10:21 | formname |
| formidable.js:9:27:9:34 | formname | formidable.js:10:14:10:21 | formname |
| formidable.js:9:37:9:40 | file | formidable.js:10:24:10:27 | file |
| formidable.js:9:37:9:40 | file | formidable.js:10:24:10:27 | file |
| formidable.js:9:37:9:40 | file | formidable.js:10:24:10:27 | file |
| formidable.js:9:37:9:40 | file | formidable.js:10:24:10:27 | file |
| formidable.js:12:22:12:29 | formname | formidable.js:13:14:13:21 | formname |
| formidable.js:12:22:12:29 | formname | formidable.js:13:14:13:21 | formname |
| formidable.js:12:22:12:29 | formname | formidable.js:13:14:13:21 | formname |
| formidable.js:12:22:12:29 | formname | formidable.js:13:14:13:21 | formname |
| formidable.js:12:32:12:35 | file | formidable.js:13:24:13:27 | file |
| formidable.js:12:32:12:35 | file | formidable.js:13:24:13:27 | file |
| formidable.js:12:32:12:35 | file | formidable.js:13:24:13:27 | file |
| formidable.js:12:32:12:35 | file | formidable.js:13:24:13:27 | file |
| formidable.js:15:23:15:31 | fieldName | formidable.js:16:14:16:22 | fieldName |
| formidable.js:15:23:15:31 | fieldName | formidable.js:16:14:16:22 | fieldName |
| formidable.js:15:23:15:31 | fieldName | formidable.js:16:14:16:22 | fieldName |
| formidable.js:15:23:15:31 | fieldName | formidable.js:16:14:16:22 | fieldName |
| formidable.js:15:34:15:43 | fieldValue | formidable.js:16:25:16:34 | fieldValue |
| formidable.js:15:34:15:43 | fieldValue | formidable.js:16:25:16:34 | fieldValue |
| formidable.js:15:34:15:43 | fieldValue | formidable.js:16:25:16:34 | fieldValue |
| formidable.js:15:34:15:43 | fieldValue | formidable.js:16:25:16:34 | fieldValue |
| multiparty.js:8:22:8:25 | part | multiparty.js:9:14:9:17 | part |
| multiparty.js:8:22:8:25 | part | multiparty.js:9:14:9:17 | part |
| multiparty.js:8:22:8:25 | part | multiparty.js:9:14:9:17 | part |
| multiparty.js:8:22:8:25 | part | multiparty.js:9:14:9:17 | part |
| multiparty.js:8:22:8:25 | part | multiparty.js:10:19:10:24 | sink() |
| multiparty.js:8:22:8:25 | part | multiparty.js:10:19:10:24 | sink() |
| multiparty.js:8:22:8:25 | part | multiparty.js:10:19:10:24 | sink() |
| multiparty.js:8:22:8:25 | part | multiparty.js:10:19:10:24 | sink() |
| multiparty.js:14:37:14:42 | fields | multiparty.js:15:14:15:19 | fields |
| multiparty.js:14:37:14:42 | fields | multiparty.js:15:14:15:19 | fields |
| multiparty.js:14:37:14:42 | fields | multiparty.js:15:14:15:19 | fields |
| multiparty.js:14:37:14:42 | fields | multiparty.js:15:14:15:19 | fields |
| multiparty.js:14:45:14:49 | files | multiparty.js:15:22:15:26 | files |
| multiparty.js:14:45:14:49 | files | multiparty.js:15:22:15:26 | files |
| multiparty.js:14:45:14:49 | files | multiparty.js:15:22:15:26 | files |
| multiparty.js:14:45:14:49 | files | multiparty.js:15:22:15:26 | files |
#select
| busybus.js:12:18:12:25 | filename | busybus.js:9:36:9:39 | info | busybus.js:12:18:12:25 | filename | This entity depends on a $@. | busybus.js:9:36:9:39 | info | user-provided value |
| busybus.js:12:28:12:35 | encoding | busybus.js:9:36:9:39 | info | busybus.js:12:28:12:35 | encoding | This entity depends on a $@. | busybus.js:9:36:9:39 | info | user-provided value |
| busybus.js:12:38:12:45 | mimeType | busybus.js:9:36:9:39 | info | busybus.js:12:38:12:45 | mimeType | This entity depends on a $@. | busybus.js:9:36:9:39 | info | user-provided value |
| busybus.js:13:31:13:36 | sink() | busybus.js:9:30:9:33 | file | busybus.js:13:31:13:36 | sink() | This entity depends on a $@. | busybus.js:9:30:9:33 | file | user-provided value |
| busybus.js:16:22:16:25 | data | busybus.js:15:30:15:33 | data | busybus.js:16:22:16:25 | data | This entity depends on a $@. | busybus.js:15:30:15:33 | data | user-provided value |
| busybus.js:23:26:23:29 | data | busybus.js:22:32:22:42 | this.read() | busybus.js:23:26:23:29 | data | This entity depends on a $@. | busybus.js:22:32:22:42 | this.read() | user-provided value |
| busybus.js:28:18:28:21 | name | busybus.js:27:25:27:28 | name | busybus.js:28:18:28:21 | name | This entity depends on a $@. | busybus.js:27:25:27:28 | name | user-provided value |
| busybus.js:28:24:28:26 | val | busybus.js:27:31:27:33 | val | busybus.js:28:24:28:26 | val | This entity depends on a $@. | busybus.js:27:31:27:33 | val | user-provided value |
| busybus.js:28:29:28:32 | info | busybus.js:27:36:27:39 | info | busybus.js:28:29:28:32 | info | This entity depends on a $@. | busybus.js:27:36:27:39 | info | user-provided value |
| dicer.js:13:19:13:24 | sink() | dicer.js:12:23:12:26 | part | dicer.js:13:19:13:24 | sink() | This entity depends on a $@. | dicer.js:12:23:12:26 | part | user-provided value |
| dicer.js:16:22:16:30 | header[h] | dicer.js:14:28:14:33 | header | dicer.js:16:22:16:30 | header[h] | This entity depends on a $@. | dicer.js:14:28:14:33 | header | user-provided value |
| dicer.js:20:18:20:21 | data | dicer.js:19:26:19:29 | data | dicer.js:20:18:20:21 | data | This entity depends on a $@. | dicer.js:19:26:19:29 | data | user-provided value |
| formidable.js:8:10:8:15 | fields | formidable.js:7:35:7:49 | form.parse(req) | formidable.js:8:10:8:15 | fields | This entity depends on a $@. | formidable.js:7:35:7:49 | form.parse(req) | user-provided value |
| formidable.js:8:18:8:22 | files | formidable.js:7:35:7:49 | form.parse(req) | formidable.js:8:18:8:22 | files | This entity depends on a $@. | formidable.js:7:35:7:49 | form.parse(req) | user-provided value |
| formidable.js:10:14:10:21 | formname | formidable.js:9:27:9:34 | formname | formidable.js:10:14:10:21 | formname | This entity depends on a $@. | formidable.js:9:27:9:34 | formname | user-provided value |
| formidable.js:10:24:10:27 | file | formidable.js:9:37:9:40 | file | formidable.js:10:24:10:27 | file | This entity depends on a $@. | formidable.js:9:37:9:40 | file | user-provided value |
| formidable.js:13:14:13:21 | formname | formidable.js:12:22:12:29 | formname | formidable.js:13:14:13:21 | formname | This entity depends on a $@. | formidable.js:12:22:12:29 | formname | user-provided value |
| formidable.js:13:24:13:27 | file | formidable.js:12:32:12:35 | file | formidable.js:13:24:13:27 | file | This entity depends on a $@. | formidable.js:12:32:12:35 | file | user-provided value |
| formidable.js:16:14:16:22 | fieldName | formidable.js:15:23:15:31 | fieldName | formidable.js:16:14:16:22 | fieldName | This entity depends on a $@. | formidable.js:15:23:15:31 | fieldName | user-provided value |
| formidable.js:16:25:16:34 | fieldValue | formidable.js:15:34:15:43 | fieldValue | formidable.js:16:25:16:34 | fieldValue | This entity depends on a $@. | formidable.js:15:34:15:43 | fieldValue | user-provided value |
| multiparty.js:9:14:9:17 | part | multiparty.js:8:22:8:25 | part | multiparty.js:9:14:9:17 | part | This entity depends on a $@. | multiparty.js:8:22:8:25 | part | user-provided value |
| multiparty.js:10:19:10:24 | sink() | multiparty.js:8:22:8:25 | part | multiparty.js:10:19:10:24 | sink() | This entity depends on a $@. | multiparty.js:8:22:8:25 | part | user-provided value |
| multiparty.js:15:14:15:19 | fields | multiparty.js:14:37:14:42 | fields | multiparty.js:15:14:15:19 | fields | This entity depends on a $@. | multiparty.js:14:37:14:42 | fields | user-provided value |
| multiparty.js:15:22:15:26 | files | multiparty.js:14:45:14:49 | files | multiparty.js:15:22:15:26 | files | This entity depends on a $@. | multiparty.js:14:45:14:49 | files | user-provided value |

View File

@@ -0,0 +1,34 @@
/**
* @name Remote Form Flow Sources
* @description Using remote user controlled sources from Forms
* @kind path-problem
* @problem.severity error
* @security-severity 5
* @precision high
* @id js/remote-flow-source
* @tags correctness
* security
*/
import javascript
import DataFlow::PathGraph
import experimental.semmle.javascript.FormParsers
/**
* A taint-tracking configuration for test
*/
class Configuration extends TaintTracking::Configuration {
Configuration() { this = "RemoteFlowSourcesOUserForm" }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) {
sink = API::moduleImport("sink").getAParameter().asSink() or
sink = API::moduleImport("sink").getReturn().asSource()
}
}
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "This entity depends on a $@.", source.getNode(),
"user-provided value"

View File

@@ -0,0 +1,33 @@
const http = require('http');
const zlib = require('node:zlib');
const busboy = require('busboy');
const sink = require('sink');
http.createServer((req, res) => {
if (req.method === 'POST') {
const bb = busboy({ headers: req.headers });
bb.on('file', (name, file, info) => {
const { filename, encoding, mimeType } = info;
const z = zlib.createGzip();
sink(filename, encoding, mimeType) // sink
file.pipe(z).pipe(sink())
file.on('data', (data) => {
sink(data)
})
file.on('readable', function () {
// There is some data to read now.
let data;
while ((data = this.read()) !== null) {
sink(data)
}
});
});
bb.on('field', (name, val, info) => {
sink(name, val, info)
});
}
}).listen(8000, () => {
console.log('Listening for requests');
});

View File

@@ -0,0 +1,25 @@
const { inspect } = require('util');
const http = require('http');
const Dicer = require('dicer');
const sink = require('sink');
const PORT = 8080;
http.createServer((req, res) => {
let m;
const dicer = new Dicer({ boundary: m[1] || m[2] });
dicer.on('part', (part) => {
part.pipe(sink())
part.on('header', (header) => {
for (h in header) {
sink(header[h])
}
});
part.on('data', (data) => {
sink(data)
});
});
}).listen(PORT, () => {
console.log(`Listening for requests on port ${PORT}`);
});

View File

@@ -0,0 +1,22 @@
import http from 'node:http';
import formidable from 'formidable';
const sink = require('sink');
const server = http.createServer(async (req, res) => {
const form = formidable({});
const [fields, files] = await form.parse(req);
sink(fields, files)
form.on('fileBegin', (formname, file) => {
sink(formname, file)
});
form.on('file', (formname, file) => {
sink(formname, file)
});
form.on('field', (fieldName, fieldValue) => {
sink(fieldName, fieldValue)
});
});
server.listen(8080, () => {
console.log('Server listening on http://localhost:8080/ ...');
});

View File

@@ -0,0 +1,19 @@
var multiparty = require('multiparty');
var http = require('http');
var util = require('util');
const sink = require('sink');
http.createServer(function (req, res) {
var form = new multiparty.Form();
form.on('part', (part) => {
sink(part)
part.pipe(sink())
});
var form2 = new multiparty.Form();
form2.parse(req, function (err, fields, files) {
sink(fields, files)
});
form2.parse(req);
}).listen(8080);

View File

@@ -0,0 +1,220 @@
import {
BaseEntity, Brackets, DataSource, JoinColumn, NotBrackets
, OneToOne, Entity, PrimaryGeneratedColumn, Column, SelectQueryBuilder, InsertQueryBuilder
} from "typeorm";
@Entity()
export class UserActiveRecord extends BaseEntity {
@PrimaryGeneratedColumn()
id: number
@Column()
firstName: string
@Column()
lastName: string
@Column()
age: number
static findByName(firstName: string, lastName: string) {
return this.createQueryBuilder("user")
.where("user.firstName = " + firstName) // test: SQLInjectionPoint
.andWhere("user.lastName = " + lastName) // test: SQLInjectionPoint
.getMany()
}
}
@Entity()
export class Profile {
@PrimaryGeneratedColumn()
id: number
@Column()
gender: string
@Column()
photo: string
}
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number
@Column()
name: string
@OneToOne(() => Profile)
@JoinColumn()
profile: Profile
}
@Entity()
export class User2 {
@PrimaryGeneratedColumn()
id: number
@Column()
firstName: string
@Column()
lastName: string
@Column()
age: number
}
export const AppDataSource = new DataSource({
type: "sqlite",
database: "database.sqlite",
synchronize: true,
logging: false,
entities: [User, User2, Profile, UserActiveRecord],
migrations: [],
subscribers: [],
})
function makePaginationQuery<T>(q: SelectQueryBuilder<T>): SelectQueryBuilder<T> {
return q;
}
AppDataSource.initialize().then(async () => {
const BadInput = "A user controllable Remote Source like `' 1=1 --` "
// Active record
await UserActiveRecord.findByName(BadInput, "Saw")
// data mapper
const selectQueryBuilder = makePaginationQuery<User>(AppDataSource
.createQueryBuilder(User, "User").select());
selectQueryBuilder.where(BadInput).getMany().then(result => { // test: SQLInjectionPoint
console.log(result)
});
const selectQueryBuilder2 = makePaginationQuery<User>(AppDataSource
.createQueryBuilder(User, "User"));
selectQueryBuilder2.where(BadInput).getMany().then(result => { // test: SQLInjectionPoint
console.log(result)
});
const insertQueryBuilder: InsertQueryBuilder<User2> = AppDataSource
.createQueryBuilder(User2, "User2").insert();
insertQueryBuilder.into(User2)
.values({
firstName: "Timber",
lastName: () => BadInput, // test: SQLInjectionPoint
age: 33,
}).execute().then(result => {
console.log(result)
})
AppDataSource
.createQueryBuilder(User2, "User")
.insert()
.into(User2)
.values({
firstName: "Timber",
lastName: () => BadInput, // test: SQLInjectionPoint
age: 33,
})
.orUpdate(
[BadInput, BadInput], // test: SQLInjectionPoint
[BadInput], // test: SQLInjectionPoint
)
.getQueryAndParameters()
await AppDataSource.getRepository(User2).createQueryBuilder("user2")
.update(User2)
.set({ firstName: () => BadInput, lastName: "Saw2", age: 12 }) // test: SQLInjectionPoint
.where(BadInput,) // test: SQLInjectionPoint
.execute()
await AppDataSource.getRepository(User2).createQueryBuilder('user2')
.delete()
.from(User2)
.where(BadInput) // test: SQLInjectionPoint
.execute()
const queryRunner = AppDataSource.createQueryRunner()
await queryRunner.query(BadInput) // test: SQLInjectionPoint
await queryRunner.manager
.createQueryBuilder(User2, "User")
.select(BadInput) // test: SQLInjectionPoint
.where(BadInput).execute() // test: SQLInjectionPoint
await AppDataSource
.createQueryBuilder(User, "User")
.innerJoin("User.profile", "profile", BadInput, { // test: SQLInjectionPoint
id: 2,
}).getMany().then(res => console.log(res))
await AppDataSource
.createQueryBuilder(User, "User")
.leftJoinAndMapOne("User.profile", "profile", "profile", BadInput, { // test: SQLInjectionPoint
id: 2,
}).getMany().then(res => console.log(res))
await AppDataSource
.createQueryBuilder(User2, "User2")
.where((qb) => {
const subQuery = qb
.subQuery()
.select(BadInput) // test: SQLInjectionPoint
.from(User2, "user2")
.where(BadInput) // test: SQLInjectionPoint
.getQuery()
return "User2.id IN " + subQuery
})
.setParameter("registered", true)
.getMany()
// Using repository
await AppDataSource.getRepository(User2).createQueryBuilder("User2").where("User2.id =:kind" + BadInput, { kind: 1 }).getMany()
// Using DataSource
await AppDataSource
.createQueryBuilder()
.select(BadInput) // test: SQLInjectionPoint
.from(User2, "User2")
.where(BadInput, { id: 1 }) // test: SQLInjectionPoint
.getMany()
// Using entity manager
await AppDataSource.manager
.createQueryBuilder(User2, "User2").where("User2.id =:kind" + BadInput, { kind: '1' }).getMany() // test: SQLInjectionPoint
await AppDataSource
.createQueryBuilder(User2, "User2")
.leftJoinAndSelect("user.photos", "photo", BadInput).getMany() // test: SQLInjectionPoint
await AppDataSource
.createQueryBuilder(User2, "User2").groupBy("User2.id").having(BadInput).getMany() // test: SQLInjectionPoint
// orderBy
// it is a little bit restrictive, e.g. sqlite don't support it at all
await AppDataSource
.createQueryBuilder(User2, "User2").where(BadInput, { // test: SQLInjectionPoint
firstName: "Timber",
})
.where(
new Brackets((qb) => {
qb.where(BadInput).orWhere(BadInput); // test: SQLInjectionPoint
})
)
.orderBy(BadInput).orWhere(BadInput).getMany() // test: SQLInjectionPoint
// relation
AppDataSource.createQueryBuilder().relation(User, "name")
.of(User)
.select().where(BadInput).getMany().then(results => { // test: SQLInjectionPoint
console.log(results)
})
// Brackets
await AppDataSource.createQueryBuilder(User2, "User2")
.where(BadInput) // test: SQLInjectionPoint
.andWhere(
new Brackets((qb) => {
qb.where(BadInput).orWhere(BadInput); // test: SQLInjectionPoint
})
).andWhere(
new NotBrackets((qb) => {
qb.where(BadInput).orWhere(BadInput) // test: SQLInjectionPoint
}),
).getMany()
}).catch(error => console.log(error))

View File

@@ -0,0 +1,32 @@
passingPositiveTests
| PASSED | SQLInjectionPoint | test.ts:19:54:19:79 | // test ... onPoint |
| PASSED | SQLInjectionPoint | test.ts:20:55:20:80 | // test ... onPoint |
| PASSED | SQLInjectionPoint | test.ts:82:70:82:95 | // test ... onPoint |
| PASSED | SQLInjectionPoint | test.ts:88:70:88:95 | // test ... onPoint |
| PASSED | SQLInjectionPoint | test.ts:97:41:97:66 | // test ... onPoint |
| PASSED | SQLInjectionPoint | test.ts:111:41:111:66 | // test ... onPoint |
| PASSED | SQLInjectionPoint | test.ts:115:37:115:62 | // test ... onPoint |
| PASSED | SQLInjectionPoint | test.ts:116:27:116:52 | // test ... onPoint |
| PASSED | SQLInjectionPoint | test.ts:122:74:122:99 | // test ... onPoint |
| PASSED | SQLInjectionPoint | test.ts:123:29:123:54 | // test ... onPoint |
| PASSED | SQLInjectionPoint | test.ts:129:28:129:53 | // test ... onPoint |
| PASSED | SQLInjectionPoint | test.ts:134:41:134:66 | // test ... onPoint |
| PASSED | SQLInjectionPoint | test.ts:138:29:138:54 | // test ... onPoint |
| PASSED | SQLInjectionPoint | test.ts:139:38:139:63 | // test ... onPoint |
| PASSED | SQLInjectionPoint | test.ts:143:61:143:86 | // test ... onPoint |
| PASSED | SQLInjectionPoint | test.ts:149:80:149:105 | // test ... onPoint |
| PASSED | SQLInjectionPoint | test.ts:159:37:159:62 | // test ... onPoint |
| PASSED | SQLInjectionPoint | test.ts:161:36:161:61 | // test ... onPoint |
| PASSED | SQLInjectionPoint | test.ts:175:29:175:54 | // test ... onPoint |
| PASSED | SQLInjectionPoint | test.ts:177:39:177:64 | // test ... onPoint |
| PASSED | SQLInjectionPoint | test.ts:182:108:182:133 | // test ... onPoint |
| PASSED | SQLInjectionPoint | test.ts:185:74:185:99 | // test ... onPoint |
| PASSED | SQLInjectionPoint | test.ts:187:94:187:119 | // test ... onPoint |
| PASSED | SQLInjectionPoint | test.ts:191:65:191:90 | // test ... onPoint |
| PASSED | SQLInjectionPoint | test.ts:196:57:196:82 | // test ... onPoint |
| PASSED | SQLInjectionPoint | test.ts:199:58:199:83 | // test ... onPoint |
| PASSED | SQLInjectionPoint | test.ts:204:65:204:90 | // test ... onPoint |
| PASSED | SQLInjectionPoint | test.ts:210:28:210:53 | // test ... onPoint |
| PASSED | SQLInjectionPoint | test.ts:213:56:213:81 | // test ... onPoint |
| PASSED | SQLInjectionPoint | test.ts:217:56:217:81 | // test ... onPoint |
failingPositiveTests

View File

@@ -0,0 +1,34 @@
import javascript
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("!%")
}
predicate hasPositiveTest(string test) { test = this.getPositiveTest() }
predicate inNode(DataFlow::Node n) {
this.getLocation().getFile() = n.getFile() and
this.getLocation().getStartLine() = n.getStartLine()
}
}
import experimental.semmle.javascript.SQL
query predicate passingPositiveTests(string res, string expectation, InlineTest t) {
res = "PASSED" and
t.hasPositiveTest(expectation) and
expectation = "SQLInjectionPoint" and
exists(SQL::SqlString n | t.inNode(n))
}
query predicate failingPositiveTests(string res, string expectation, InlineTest t) {
res = "FAILED" and
t.hasPositiveTest(expectation) and
expectation = "SQLInjectionPoint" and
not exists(SQL::SqlString n | t.inNode(n))
}

View File

@@ -0,0 +1,15 @@
{
"compilerOptions": {
"lib": [
"es5",
"es6"
],
"target": "es6",
"module": "commonjs",
"moduleResolution": "node",
"outDir": "./build",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"sourceMap": true
}
}