Skip to content

Commit 0c40223

Browse files
committed
v1
1 parent a8aeb1d commit 0c40223

File tree

1 file changed

+44
-43
lines changed
  • javascript/ql/lib/semmle/javascript/frameworks

1 file changed

+44
-43
lines changed

javascript/ql/lib/semmle/javascript/frameworks/TypeORM.qll

Lines changed: 44 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
11
import javascript
22

3-
module Sqlite {
4-
// Gets an expression that constructs or returns a Sqlite database instance.
3+
module TypeOrm {
4+
// Gets an expression that constructs or returns a TypeORM database instance.
55
API::Node dataSource() {
66
result = API::moduleImport("typeorm").getMember("DataSource").getInstance()
77
}
88

9+
// Gets an `QueryRunner`
10+
API::Node queryRunner() { result = dataSource().getMember("createQueryRunner").getReturn() }
11+
912
// Gets `createQueryBuilder` return value from a Active record based Entity
1013
API::Node activeRecordQueryBuilder() {
11-
result =
12-
API::moduleImport("typeorm")
13-
.getMember("Entity")
14-
.getReturn()
15-
.getADecoratedClass()
16-
.getMember("createQueryBuilder")
17-
.getReturn()
14+
result = queryRunner().getMember("manager").getMember("createQueryBuilder").getReceiver()
1815
}
1916

2017
// Gets `createQueryBuilder` return value from a Data Mapper based Entity
@@ -26,7 +23,7 @@ module Sqlite {
2623
// Using repository
2724
dataSource().getMember("getRepository").getReturn(),
2825
// Using entity manager
29-
dataSource().getMember("manager")
26+
dataSource().getMember("manager"), queryRunner().getMember("manager")
3027
].getMember("createQueryBuilder").getReturn()
3128
}
3229

@@ -67,9 +64,9 @@ module Sqlite {
6764

6865
/**
6966
* Gets functions responsible for select expressions
70-
* `orderBy` is not injectable in sqlite, if we want to write a filter we should specify a DataSource parameter string value,
67+
* `orderBy` is not injectable in TypeORM, if we want to write a filter we should specify a DataSource parameter string value,
7168
* which mostly is taken from config files and we will loose many sinks,
72-
* Also many application support multiple DBMSs besides sqlite,
69+
* Also many application support multiple DBMSs besides TypeORM,
7370
* Also Consider it that `Order By` clause is one of the most popular injectable sinks
7471
*/
7572
string selectExpression() {
@@ -78,7 +75,8 @@ module Sqlite {
7875
"select", "addSelect", "from", "where", "andWhere", "orWhere", "having", "orHaving",
7976
"andHaving", "orderBy", "addOrderBy", "distinctOn", "groupBy", "addCommonTableExpression",
8077
"leftJoinAndSelect", "innerJoinAndSelect", "leftJoin", "innerJoin", "leftJoinAndMapOne",
81-
"innerJoinAndMapOne", "leftJoinAndMapMany", "innerJoinAndMapMany"
78+
"innerJoinAndMapOne", "leftJoinAndMapMany", "innerJoinAndMapMany", "orUpdate", "orIgnore",
79+
"values", "set"
8280
]
8381
}
8482

@@ -88,22 +86,19 @@ module Sqlite {
8886
}
8987

9088
/**
91-
* A call to a TypeORM Query Builder method and its successor nodes.
89+
* A call to some successor functions of TypeORM `createQueryBuilder` function which are dangerous
9290
*/
93-
private class QueryCall extends DatabaseAccess, API::CallNode {
91+
private class QueryBuilderCall extends DatabaseAccess, API::CallNode {
9492
API::Node typeOrmNode;
9593

96-
QueryCall() {
97-
(
98-
typeOrmNode = getASuccessorOfBuilderInstance() and
99-
this = typeOrmNode.asSource()
100-
or
101-
// I'm doing following because this = typeOrmNode.asSource()s
102-
// won't let me to get a member in getAQueryArgument
103-
typeOrmNode = getASuccessorOfBrackets() and
104-
typeOrmNode.getMember(selectExpression()).getACall() = this
105-
) and
106-
this.getFile().getLocation().toString().matches("%.ts%")
94+
QueryBuilderCall() {
95+
typeOrmNode = getASuccessorOfBuilderInstance() and
96+
this = typeOrmNode.asSource()
97+
or
98+
// I'm doing following because this = TypeORMNode.asSource()s
99+
// won't let me to get a member in getAQueryArgument
100+
typeOrmNode = getASuccessorOfBrackets() and
101+
typeOrmNode.getMember(selectExpression()).getACall() = this
107102
}
108103

109104
override DataFlow::Node getAResult() {
@@ -126,27 +121,33 @@ module Sqlite {
126121
"addCommonTableExpression"
127122
] and
128123
result = typeOrmNode.getMember(memberName).getParameter(0).asSink()
124+
or
125+
memberName = ["orIgnore", "orUpdate"] and
126+
result = typeOrmNode.getMember(memberName).getParameter([0, 1]).asSink()
127+
or
128+
// following functions if use a function as their input fields,called function parameters which are vulnerable
129+
memberName = ["values", "set"] and
130+
result = typeOrmNode.getMember(memberName).getParameter(0).getAMember().getReturn().asSink()
129131
)
130132
}
131133
}
132134

133-
/** An expression that is passed to the `query` method and hence interpreted as SQL. */
134-
class QueryString extends SQL::SqlString {
135-
QueryString() { this = any(QueryCall qc).getAQueryArgument() }
135+
/**
136+
* A call to a TypeORM `query` function of QueryRunner
137+
*/
138+
private class QueryRunner extends DatabaseAccess, API::CallNode {
139+
QueryRunner() { queryRunner().getMember("query").getACall() = this }
140+
141+
override DataFlow::Node getAResult() { result = this }
142+
143+
override DataFlow::Node getAQueryArgument() { result = this.getArgument(0) }
136144
}
137-
}
138145

139-
predicate test(API::Node n) { n = API::moduleImport("typeorm").getASuccessor*().getMember("where") }
140-
141-
predicate test2(API::Node n) {
142-
n =
143-
API::moduleImport("typeorm")
144-
.getMember("DataSource")
145-
.getInstance()
146-
.getMember("getRepository")
147-
.getReturn()
148-
.getMember("createQueryBuilder")
149-
.getReturn()
150-
.getMember("where")
151-
.getParameter(0)
146+
/** An expression that is passed to the `query` function and hence interpreted as SQL. */
147+
class QueryString extends SQL::SqlString {
148+
QueryString() {
149+
this = any(QueryRunner qc).getAQueryArgument() or
150+
this = any(QueryBuilderCall qc).getAQueryArgument()
151+
}
152+
}
152153
}

0 commit comments

Comments
 (0)