Skip to content

Commit 5461f94

Browse files
authored
Merge pull request github#12424 from asgerf/js/html-sanitizer-for-sql
JS: Add html sanitizers as a taint step in a few queries
2 parents f53a05b + 05b5aea commit 5461f94

File tree

9 files changed

+70
-0
lines changed

9 files changed

+70
-0
lines changed

javascript/ql/lib/semmle/javascript/security/dataflow/ClientSideUrlRedirectQuery.qll

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ class Configuration extends TaintTracking::Configuration {
4848
f instanceof DocumentUrl and
4949
g instanceof DocumentUrl and
5050
succ.(DataFlow::PropRead).accesses(pred, "href")
51+
or
52+
exists(HtmlSanitizerCall call |
53+
pred = call.getInput() and
54+
succ = call and
55+
f = g
56+
)
5157
}
5258

5359
override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) {

javascript/ql/lib/semmle/javascript/security/dataflow/RequestForgeryCustomizations.qll

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@ module RequestForgery {
7272
succ = url and
7373
pred = url.getArgument(0)
7474
)
75+
or
76+
exists(HtmlSanitizerCall call |
77+
pred = call.getInput() and
78+
succ = call
79+
)
7580
}
7681

7782
private class SinkFromModel extends Sink {

javascript/ql/lib/semmle/javascript/security/dataflow/ServerSideUrlRedirectQuery.qll

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ class Configuration extends TaintTracking::Configuration {
3535
guard instanceof LocalUrlSanitizingGuard or
3636
guard instanceof HostnameSanitizerGuard
3737
}
38+
39+
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
40+
exists(HtmlSanitizerCall call |
41+
pred = call.getInput() and
42+
succ = call
43+
)
44+
}
3845
}
3946

4047
/**

javascript/ql/lib/semmle/javascript/security/dataflow/SqlInjectionQuery.qll

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,10 @@ class Configuration extends TaintTracking::Configuration {
3030
pred = filter.getInput() and
3131
succ = filter.getOutput()
3232
)
33+
or
34+
exists(HtmlSanitizerCall call |
35+
pred = call.getInput() and
36+
succ = call
37+
)
3338
}
3439
}

javascript/ql/lib/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,12 @@ module TaintedPath {
841841
dst = call and
842842
srclabel = dstlabel
843843
)
844+
or
845+
exists(HtmlSanitizerCall call |
846+
src = call.getInput() and
847+
dst = call and
848+
srclabel = dstlabel
849+
)
844850
}
845851

846852
/**
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* The following queries now recognize HTML sanitizers as propagating taint: `js/sql-injection`,
5+
`js/path-injection`, `js/server-side-unvalidated-url-redirection`, `js/client-side-unvalidated-url-redirection`,
6+
and `js/request-forgery`.

javascript/ql/test/query-tests/Security/CWE-089/untyped/DatabaseAccesses.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
| html-sanitizer.js:15:5:17:5 | connect ... K\\n ) |
12
| json-schema-validator.js:27:13:27:27 | doc.find(query) |
23
| json-schema-validator.js:30:13:30:27 | doc.find(query) |
34
| json-schema-validator.js:33:13:33:27 | doc.find(query) |

javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,14 @@ nodes
5050
| graphql.js:120:38:120:48 | `foo ${id}` |
5151
| graphql.js:120:38:120:48 | `foo ${id}` |
5252
| graphql.js:120:45:120:46 | id |
53+
| html-sanitizer.js:13:39:13:44 | param1 |
54+
| html-sanitizer.js:13:39:13:44 | param1 |
55+
| html-sanitizer.js:14:5:14:24 | param1 |
56+
| html-sanitizer.js:14:14:14:24 | xss(param1) |
57+
| html-sanitizer.js:14:18:14:23 | param1 |
58+
| html-sanitizer.js:16:9:16:59 | `SELECT ... param1 |
59+
| html-sanitizer.js:16:9:16:59 | `SELECT ... param1 |
60+
| html-sanitizer.js:16:54:16:59 | param1 |
5361
| json-schema-validator.js:25:15:25:48 | query |
5462
| json-schema-validator.js:25:23:25:48 | JSON.pa ... y.data) |
5563
| json-schema-validator.js:25:34:25:47 | req.query.data |
@@ -466,6 +474,13 @@ edges
466474
| graphql.js:119:16:119:28 | req.params.id | graphql.js:119:11:119:28 | id |
467475
| graphql.js:120:45:120:46 | id | graphql.js:120:38:120:48 | `foo ${id}` |
468476
| graphql.js:120:45:120:46 | id | graphql.js:120:38:120:48 | `foo ${id}` |
477+
| html-sanitizer.js:13:39:13:44 | param1 | html-sanitizer.js:14:18:14:23 | param1 |
478+
| html-sanitizer.js:13:39:13:44 | param1 | html-sanitizer.js:14:18:14:23 | param1 |
479+
| html-sanitizer.js:14:5:14:24 | param1 | html-sanitizer.js:16:54:16:59 | param1 |
480+
| html-sanitizer.js:14:14:14:24 | xss(param1) | html-sanitizer.js:14:5:14:24 | param1 |
481+
| html-sanitizer.js:14:18:14:23 | param1 | html-sanitizer.js:14:14:14:24 | xss(param1) |
482+
| html-sanitizer.js:16:54:16:59 | param1 | html-sanitizer.js:16:9:16:59 | `SELECT ... param1 |
483+
| html-sanitizer.js:16:54:16:59 | param1 | html-sanitizer.js:16:9:16:59 | `SELECT ... param1 |
469484
| json-schema-validator.js:25:15:25:48 | query | json-schema-validator.js:33:22:33:26 | query |
470485
| json-schema-validator.js:25:15:25:48 | query | json-schema-validator.js:33:22:33:26 | query |
471486
| json-schema-validator.js:25:15:25:48 | query | json-schema-validator.js:35:18:35:22 | query |
@@ -924,6 +939,7 @@ edges
924939
| graphql.js:75:46:75:64 | "{ foo" + id + " }" | graphql.js:74:14:74:25 | req.query.id | graphql.js:75:46:75:64 | "{ foo" + id + " }" | This query depends on a $@. | graphql.js:74:14:74:25 | req.query.id | user-provided value |
925940
| graphql.js:84:14:90:8 | `{\\n ... }` | graphql.js:74:14:74:25 | req.query.id | graphql.js:84:14:90:8 | `{\\n ... }` | This query depends on a $@. | graphql.js:74:14:74:25 | req.query.id | user-provided value |
926941
| graphql.js:120:38:120:48 | `foo ${id}` | graphql.js:119:16:119:28 | req.params.id | graphql.js:120:38:120:48 | `foo ${id}` | This query depends on a $@. | graphql.js:119:16:119:28 | req.params.id | user-provided value |
942+
| html-sanitizer.js:16:9:16:59 | `SELECT ... param1 | html-sanitizer.js:13:39:13:44 | param1 | html-sanitizer.js:16:9:16:59 | `SELECT ... param1 | This query depends on a $@. | html-sanitizer.js:13:39:13:44 | param1 | user-provided value |
927943
| json-schema-validator.js:33:22:33:26 | query | json-schema-validator.js:25:34:25:47 | req.query.data | json-schema-validator.js:33:22:33:26 | query | This query depends on a $@. | json-schema-validator.js:25:34:25:47 | req.query.data | user-provided value |
928944
| json-schema-validator.js:35:18:35:22 | query | json-schema-validator.js:25:34:25:47 | req.query.data | json-schema-validator.js:35:18:35:22 | query | This query depends on a $@. | json-schema-validator.js:25:34:25:47 | req.query.data | user-provided value |
929945
| json-schema-validator.js:55:22:55:26 | query | json-schema-validator.js:50:34:50:47 | req.query.data | json-schema-validator.js:55:22:55:26 | query | This query depends on a $@. | json-schema-validator.js:50:34:50:47 | req.query.data | user-provided value |
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
const route = require('koa-route');
2+
const Koa = require('koa');
3+
const mysql = require('mysql2');
4+
const app = new Koa();
5+
const xss = require('xss');
6+
7+
const connection = mysql.createConnection({
8+
host: 'localhost',
9+
user: 'root',
10+
database: 'test'
11+
});
12+
13+
app.use(route.get('/test1', (context, param1) => {
14+
param1 = xss(param1)
15+
connection.query(
16+
`SELECT * FROM \`table\` WHERE \`name\` =` + param1, // NOT OK
17+
);
18+
}));

0 commit comments

Comments
 (0)