Skip to content

Commit 12079cd

Browse files
committed
JS: Recognize RegExps in JSON schemas
1 parent 7afa755 commit 12079cd

File tree

4 files changed

+71
-0
lines changed

4 files changed

+71
-0
lines changed

javascript/ql/src/semmle/javascript/JsonSchema.qll

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,34 @@ module JsonSchema {
1717
boolean getPolarity() { result = true }
1818
}
1919

20+
/** A data flow node that is used a JSON schema. */
21+
abstract class SchemaRoot extends DataFlow::Node {
22+
}
23+
24+
/** An object literal with a `$schema` property indicating it is the root of a JSON schema. */
25+
private class SchemaNodeByTag extends SchemaRoot, DataFlow::ObjectLiteralNode {
26+
SchemaNodeByTag() {
27+
getAPropertyWrite("$schema").getRhs().getStringValue().matches("%//json-schema.org%")
28+
}
29+
}
30+
31+
/** Gets a data flow node that is part of a JSON schema. */
32+
private DataFlow::SourceNode getAPartOfJsonSchema(DataFlow::TypeBackTracker t) {
33+
t.start() and
34+
result = any(SchemaRoot n).getALocalSource()
35+
or
36+
result = getAPartOfJsonSchema(t.continue()).getAPropertySource()
37+
or
38+
exists(DataFlow::TypeBackTracker t2 |
39+
result = getAPartOfJsonSchema(t2).backtrack(t2, t)
40+
)
41+
}
42+
43+
/** Gets a data flow node that is part of a JSON schema. */
44+
DataFlow::SourceNode getAPartOfJsonSchema() {
45+
result = getAPartOfJsonSchema(DataFlow::TypeBackTracker::end())
46+
}
47+
2048
/** Provides a model of the `ajv` library. */
2149
module Ajv {
2250
/** A method on `Ajv` that returns `this`. */
@@ -91,5 +119,11 @@ module JsonSchema {
91119
/** Gets the ajv instance doing the validation. */
92120
Instance getAjvInstance() { result = instance }
93121
}
122+
123+
private class AjvSchemaNode extends SchemaRoot {
124+
AjvSchemaNode() {
125+
this = any(Instance i).ref().getMember(["addSchema", "validate", "compile", "compileAsync"]).getParameter(0).getARhs()
126+
}
127+
}
94128
}
95129
}

javascript/ql/src/semmle/javascript/Regexp.qll

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -865,6 +865,14 @@ predicate isInterpretedAsRegExp(DataFlow::Node source) {
865865
// because `String.prototype.search` returns a number
866866
not exists(PropAccess p | p.getBase() = mce.getEnclosingExpr())
867867
)
868+
or
869+
exists(DataFlow::SourceNode schema |
870+
schema = JsonSchema::getAPartOfJsonSchema()
871+
|
872+
source = schema.getAPropertyWrite("pattern").getRhs()
873+
or
874+
source = schema.getAPropertySource("patternProperties").getAPropertyWrite().getPropertyNameExpr().flow()
875+
)
868876
)
869877
}
870878

javascript/ql/test/query-tests/Performance/ReDoS/ReDoS.expected

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
| highlight.js:30:13:30:25 | (?:\\\\.\|[^`])+ | This part of the regular expression may cause exponential backtracking on strings starting with '`' and containing many repetitions of '\\\\_'. |
1313
| highlight.js:34:25:34:27 | \\w* | This part of the regular expression may cause exponential backtracking on strings starting with '?A' and containing many repetitions of 'A'. |
1414
| highlight.js:38:35:38:40 | [^()]* | This part of the regular expression may cause exponential backtracking on strings starting with 'A((' and containing many repetitions of '')('. |
15+
| jsonschema.js:5:15:5:21 | (a?a?)* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'a'. |
16+
| jsonschema.js:15:23:15:29 | (a?a?)* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'a'. |
17+
| jsonschema.js:20:18:20:24 | (a?a?)* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'a'. |
1518
| polynomial-redos.js:17:5:17:6 | .* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of ','. |
1619
| polynomial-redos.js:41:52:41:63 | [\\x21-\\x7E]* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of '?'. |
1720
| polynomial-redos.js:46:33:46:45 | [a-zA-Z_0-9]* | This part of the regular expression may cause exponential backtracking on strings starting with 'A' and containing many repetitions of 'A'. |
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import Ajv from 'ajv';
2+
3+
let thing = {
4+
type: 'string',
5+
pattern: '(a?a?)*b' // NOT OK
6+
}
7+
new Ajv().addSchema(thing, 'thing');
8+
9+
export default {
10+
$schema: "http://json-schema.org/draft-07/schema#",
11+
type: "object",
12+
properties: {
13+
foo: {
14+
type: "string",
15+
pattern: "(a?a?)*b" // NOT OK
16+
},
17+
bar: {
18+
type: "object",
19+
patternProperties: {
20+
"(a?a?)*b": { // NOT OK
21+
type: "number"
22+
}
23+
}
24+
}
25+
}
26+
};

0 commit comments

Comments
 (0)