Skip to content

Commit 5cfa6e8

Browse files
committed
Add support for route parameters(+ blocks), headers, and cookies in Grape API
1 parent 3252bd3 commit 5cfa6e8

File tree

6 files changed

+239
-23
lines changed

6 files changed

+239
-23
lines changed

ruby/ql/lib/codeql/ruby/frameworks/Grape.qll

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,12 +137,14 @@ private class GrapeParamsCall extends ParamsCallImpl {
137137
)
138138
}
139139
}/**
140-
* A call to `headers` from within a Grape API endpoint.
140+
* A call to `headers` from within a Grape API endpoint or headers block.
141141
* Headers can also be a source of user input.
142142
*/
143143
class GrapeHeadersSource extends Http::Server::RequestInputAccess::Range {
144144
GrapeHeadersSource() {
145145
this.asExpr().getExpr() instanceof GrapeHeadersCall
146+
or
147+
this.asExpr().getExpr() instanceof GrapeHeadersBlockCall
146148
}
147149

148150
override string getSourceType() { result = "Grape::API#headers" }
@@ -179,6 +181,20 @@ class GrapeRequestSource extends Http::Server::RequestInputAccess::Range {
179181
override Http::Server::RequestInputKind getKind() { result = Http::Server::parameterInputKind() }
180182
}
181183

184+
/**
185+
* A call to `route_param` from within a Grape API endpoint.
186+
* Route parameters are extracted from the URL path and can be a source of user input.
187+
*/
188+
class GrapeRouteParamSource extends Http::Server::RequestInputAccess::Range {
189+
GrapeRouteParamSource() {
190+
this.asExpr().getExpr() instanceof GrapeRouteParamCall
191+
}
192+
193+
override string getSourceType() { result = "Grape::API#route_param" }
194+
195+
override Http::Server::RequestInputKind getKind() { result = Http::Server::parameterInputKind() }
196+
}
197+
182198
/**
183199
* A call to `request` from within a Grape API endpoint.
184200
*/
@@ -194,6 +210,80 @@ private class GrapeRequestCall extends MethodCall {
194210
}
195211
}
196212

213+
/**
214+
* A call to `route_param` from within a Grape API endpoint.
215+
*/
216+
private class GrapeRouteParamCall extends MethodCall {
217+
GrapeRouteParamCall() {
218+
exists(GrapeEndpoint endpoint |
219+
this.getParent+() = endpoint.getBody().asExpr().getExpr() and
220+
this.getMethodName() = "route_param"
221+
)
222+
or
223+
// Also handle cases where route_param is called on an instance of a Grape API class
224+
this = grapeAPIInstance().getAMethodCall("route_param").asExpr().getExpr()
225+
}
226+
}
227+
228+
/**
229+
* A call to `headers` block within a Grape API class.
230+
* This is different from the headers() method call - this is the DSL block for defining header requirements.
231+
*/
232+
private class GrapeHeadersBlockCall extends MethodCall {
233+
GrapeHeadersBlockCall() {
234+
exists(GrapeAPIClass api |
235+
this.getParent+() = api.getADeclaration() and
236+
this.getMethodName() = "headers" and
237+
exists(this.getBlock())
238+
)
239+
}
240+
}
241+
242+
/**
243+
* A call to `cookies` block within a Grape API class.
244+
* This DSL block defines cookie requirements and those cookies are user-controlled.
245+
*/
246+
private class GrapeCookiesBlockCall extends MethodCall {
247+
GrapeCookiesBlockCall() {
248+
exists(GrapeAPIClass api |
249+
this.getParent+() = api.getADeclaration() and
250+
this.getMethodName() = "cookies" and
251+
exists(this.getBlock())
252+
)
253+
}
254+
}
255+
256+
/**
257+
* A call to `cookies` method from within a Grape API endpoint or cookies block.
258+
* Similar to headers, cookies can be accessed as a method and are user-controlled input.
259+
*/
260+
class GrapeCookiesSource extends Http::Server::RequestInputAccess::Range {
261+
GrapeCookiesSource() {
262+
this.asExpr().getExpr() instanceof GrapeCookiesCall
263+
or
264+
this.asExpr().getExpr() instanceof GrapeCookiesBlockCall
265+
}
266+
267+
override string getSourceType() { result = "Grape::API#cookies" }
268+
269+
override Http::Server::RequestInputKind getKind() { result = Http::Server::cookieInputKind() }
270+
}
271+
272+
/**
273+
* A call to `cookies` method from within a Grape API endpoint.
274+
*/
275+
private class GrapeCookiesCall extends MethodCall {
276+
GrapeCookiesCall() {
277+
exists(GrapeEndpoint endpoint |
278+
this.getParent+() = endpoint.getBody().asCallableAstNode() and
279+
this.getMethodName() = "cookies"
280+
)
281+
or
282+
// Also handle cases where cookies is called on an instance of a Grape API class
283+
this = grapeAPIInstance().getAMethodCall("cookies").asExpr().getExpr()
284+
}
285+
}
286+
197287
/**
198288
* A method defined within a `helpers` block in a Grape API class.
199289
* These methods become available in endpoint contexts through Grape's DSL.
Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,40 @@
11
grapeAPIClasses
2-
| app.rb:1:1:48:3 | MyAPI |
3-
| app.rb:50:1:54:3 | AdminAPI |
2+
| app.rb:1:1:90:3 | MyAPI |
3+
| app.rb:92:1:96:3 | AdminAPI |
44
grapeEndpoints
5-
| app.rb:1:1:48:3 | MyAPI | app.rb:7:3:11:5 | call to get | GET | /hello/:name |
6-
| app.rb:1:1:48:3 | MyAPI | app.rb:17:3:20:5 | call to post | POST | /messages |
7-
| app.rb:1:1:48:3 | MyAPI | app.rb:23:3:27:5 | call to put | PUT | /update/:id |
8-
| app.rb:1:1:48:3 | MyAPI | app.rb:30:3:32:5 | call to delete | DELETE | /items/:id |
9-
| app.rb:1:1:48:3 | MyAPI | app.rb:35:3:37:5 | call to patch | PATCH | /items/:id |
10-
| app.rb:1:1:48:3 | MyAPI | app.rb:40:3:42:5 | call to head | HEAD | /status |
11-
| app.rb:1:1:48:3 | MyAPI | app.rb:45:3:47:5 | call to options | OPTIONS | /info |
12-
| app.rb:50:1:54:3 | AdminAPI | app.rb:51:3:53:5 | call to get | GET | /admin |
5+
| app.rb:1:1:90:3 | MyAPI | app.rb:7:3:11:5 | call to get | GET | /hello/:name |
6+
| app.rb:1:1:90:3 | MyAPI | app.rb:17:3:20:5 | call to post | POST | /messages |
7+
| app.rb:1:1:90:3 | MyAPI | app.rb:23:3:27:5 | call to put | PUT | /update/:id |
8+
| app.rb:1:1:90:3 | MyAPI | app.rb:30:3:32:5 | call to delete | DELETE | /items/:id |
9+
| app.rb:1:1:90:3 | MyAPI | app.rb:35:3:37:5 | call to patch | PATCH | /items/:id |
10+
| app.rb:1:1:90:3 | MyAPI | app.rb:40:3:42:5 | call to head | HEAD | /status |
11+
| app.rb:1:1:90:3 | MyAPI | app.rb:45:3:47:5 | call to options | OPTIONS | /info |
12+
| app.rb:1:1:90:3 | MyAPI | app.rb:50:3:54:5 | call to get | GET | /users/:user_id/posts/:post_id |
13+
| app.rb:1:1:90:3 | MyAPI | app.rb:78:3:82:5 | call to get | GET | /cookie_test |
14+
| app.rb:1:1:90:3 | MyAPI | app.rb:85:3:89:5 | call to get | GET | /header_test |
15+
| app.rb:92:1:96:3 | AdminAPI | app.rb:93:3:95:5 | call to get | GET | /admin |
1316
grapeParams
1417
| app.rb:8:12:8:17 | call to params |
1518
| app.rb:14:3:16:5 | call to params |
1619
| app.rb:18:11:18:16 | call to params |
1720
| app.rb:24:10:24:15 | call to params |
1821
| app.rb:31:5:31:10 | call to params |
1922
| app.rb:36:5:36:10 | call to params |
20-
| app.rb:52:5:52:10 | call to params |
23+
| app.rb:60:12:60:17 | call to params |
24+
| app.rb:94:5:94:10 | call to params |
2125
grapeHeaders
2226
| app.rb:9:18:9:24 | call to headers |
2327
| app.rb:46:5:46:11 | call to headers |
28+
| app.rb:66:3:69:5 | call to headers |
29+
| app.rb:86:12:86:18 | call to headers |
30+
| app.rb:87:14:87:20 | call to headers |
2431
grapeRequest
2532
| app.rb:25:12:25:18 | call to request |
33+
grapeRouteParam
34+
| app.rb:51:15:51:35 | call to route_param |
35+
| app.rb:52:15:52:36 | call to route_param |
36+
| app.rb:57:3:63:5 | call to route_param |
37+
grapeCookies
38+
| app.rb:72:3:75:5 | call to cookies |
39+
| app.rb:79:15:79:21 | call to cookies |
40+
| app.rb:80:16:80:22 | call to cookies |

ruby/ql/test/library-tests/frameworks/grape/Grape.ql

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,8 @@ query predicate grapeParams(GrapeParamsSource params) { any() }
1515

1616
query predicate grapeHeaders(GrapeHeadersSource headers) { any() }
1717

18-
query predicate grapeRequest(GrapeRequestSource request) { any() }
18+
query predicate grapeRequest(GrapeRequestSource request) { any() }
19+
20+
query predicate grapeRouteParam(GrapeRouteParamSource routeParam) { any() }
21+
22+
query predicate grapeCookies(GrapeCookiesSource cookies) { any() }

ruby/ql/test/library-tests/frameworks/grape/app.rb

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,48 @@ class MyAPI < Grape::API
4545
options '/info' do
4646
headers['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
4747
end
48+
49+
desc 'Route param endpoint'
50+
get '/users/:user_id/posts/:post_id' do
51+
user_id = route_param(:user_id)
52+
post_id = route_param('post_id')
53+
{ user_id: user_id, post_id: post_id }
54+
end
55+
56+
desc 'Route param block pattern'
57+
route_param :id do
58+
get do
59+
# params[:id] is user input from the path parameter
60+
id = params[:id]
61+
{ id: id }
62+
end
63+
end
64+
65+
# Headers block for defining expected headers
66+
headers do
67+
requires :Authorization, type: String
68+
optional 'X-Custom-Header', type: String
69+
end
70+
71+
# Cookies block for defining expected cookies
72+
cookies do
73+
requires :session_id, type: String
74+
optional :tracking_id, type: String
75+
end
76+
77+
desc 'Endpoint that uses cookies method'
78+
get '/cookie_test' do
79+
session = cookies[:session_id]
80+
tracking = cookies['tracking_id']
81+
{ session: session, tracking: tracking }
82+
end
83+
84+
desc 'Endpoint that uses headers method'
85+
get '/header_test' do
86+
auth = headers[:Authorization]
87+
custom = headers['X-Custom-Header']
88+
{ auth: auth, custom: custom }
89+
end
4890
end
4991

5092
class AdminAPI < Grape::API

ruby/ql/test/query-tests/security/cwe-089/ArelInjection.rb

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,39 @@ def vulnerable_helper(user_id)
3333
end
3434
end
3535

36+
# Headers and cookies blocks for DSL testing
37+
headers do
38+
requires :Authorization, type: String
39+
end
40+
41+
cookies do
42+
requires :session_id, type: String
43+
end
44+
45+
get '/comprehensive_test/:user_id' do
46+
# BAD: Comprehensive test using all Grape input sources in one SQL query
47+
user_id = params[:user_id] # params taint source
48+
route_id = route_param(:user_id) # route_param taint source
49+
auth = headers[:Authorization] # headers taint source
50+
session = cookies[:session_id] # cookies taint source
51+
body_data = request.body.read # request taint source
52+
53+
# All sources flow to SQL injection
54+
Arel.sql("SELECT * FROM users WHERE id = #{user_id} AND route_id = #{route_id} AND auth = #{auth} AND session = #{session} AND data = #{body_data}")
55+
end
56+
3657
get '/helper_test' do
37-
# This should be detected as SQL injection via helper method
58+
# BAD: Test helper method dataflow
3859
user_id = params[:user_id]
3960
vulnerable_helper(user_id)
4061
end
62+
63+
# Test route_param block pattern
64+
route_param :id do
65+
get do
66+
# BAD: params[:id] should be user input from the path
67+
user_id = params[:id]
68+
Arel.sql("SELECT * FROM users WHERE id = #{user_id}")
69+
end
70+
end
4171
end

ruby/ql/test/query-tests/security/cwe-089/SqlInjection.expected

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,24 @@ edges
8989
| ArelInjection.rb:22:9:22:14 | call to params | ArelInjection.rb:22:9:22:21 | ...[...] | provenance | |
9090
| ArelInjection.rb:22:9:22:21 | ...[...] | ArelInjection.rb:22:5:22:5 | x | provenance | |
9191
| ArelInjection.rb:30:29:30:35 | user_id | ArelInjection.rb:32:18:32:60 | "SELECT * FROM users WHERE id ..." | provenance | AdditionalTaintStep |
92-
| ArelInjection.rb:38:7:38:13 | user_id | ArelInjection.rb:39:25:39:31 | user_id | provenance | |
93-
| ArelInjection.rb:38:17:38:22 | call to params | ArelInjection.rb:38:17:38:32 | ...[...] | provenance | |
94-
| ArelInjection.rb:38:17:38:32 | ...[...] | ArelInjection.rb:38:7:38:13 | user_id | provenance | |
95-
| ArelInjection.rb:39:25:39:31 | user_id | ArelInjection.rb:30:29:30:35 | user_id | provenance | AdditionalTaintStep |
92+
| ArelInjection.rb:47:7:47:13 | user_id | ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | provenance | AdditionalTaintStep |
93+
| ArelInjection.rb:47:17:47:22 | call to params | ArelInjection.rb:47:17:47:32 | ...[...] | provenance | |
94+
| ArelInjection.rb:47:17:47:32 | ...[...] | ArelInjection.rb:47:7:47:13 | user_id | provenance | |
95+
| ArelInjection.rb:48:7:48:14 | route_id | ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | provenance | AdditionalTaintStep |
96+
| ArelInjection.rb:48:18:48:38 | call to route_param | ArelInjection.rb:48:7:48:14 | route_id | provenance | |
97+
| ArelInjection.rb:49:7:49:10 | auth | ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | provenance | AdditionalTaintStep |
98+
| ArelInjection.rb:49:14:49:20 | call to headers | ArelInjection.rb:49:14:49:36 | ...[...] | provenance | |
99+
| ArelInjection.rb:49:14:49:36 | ...[...] | ArelInjection.rb:49:7:49:10 | auth | provenance | |
100+
| ArelInjection.rb:50:7:50:13 | session | ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | provenance | AdditionalTaintStep |
101+
| ArelInjection.rb:50:17:50:23 | call to cookies | ArelInjection.rb:50:17:50:36 | ...[...] | provenance | |
102+
| ArelInjection.rb:50:17:50:36 | ...[...] | ArelInjection.rb:50:7:50:13 | session | provenance | |
103+
| ArelInjection.rb:59:7:59:13 | user_id | ArelInjection.rb:60:25:60:31 | user_id | provenance | |
104+
| ArelInjection.rb:59:17:59:22 | call to params | ArelInjection.rb:59:17:59:32 | ...[...] | provenance | |
105+
| ArelInjection.rb:59:17:59:32 | ...[...] | ArelInjection.rb:59:7:59:13 | user_id | provenance | |
106+
| ArelInjection.rb:60:25:60:31 | user_id | ArelInjection.rb:30:29:30:35 | user_id | provenance | AdditionalTaintStep |
107+
| ArelInjection.rb:67:9:67:15 | user_id | ArelInjection.rb:68:18:68:60 | "SELECT * FROM users WHERE id ..." | provenance | AdditionalTaintStep |
108+
| ArelInjection.rb:67:19:67:24 | call to params | ArelInjection.rb:67:19:67:29 | ...[...] | provenance | |
109+
| ArelInjection.rb:67:19:67:29 | ...[...] | ArelInjection.rb:67:9:67:15 | user_id | provenance | |
96110
| PgInjection.rb:6:5:6:8 | name | PgInjection.rb:13:5:13:8 | qry1 : String | provenance | AdditionalTaintStep |
97111
| PgInjection.rb:6:5:6:8 | name | PgInjection.rb:19:5:19:8 | qry2 : String | provenance | AdditionalTaintStep |
98112
| PgInjection.rb:6:5:6:8 | name | PgInjection.rb:31:5:31:8 | qry3 : String | provenance | AdditionalTaintStep |
@@ -232,10 +246,26 @@ nodes
232246
| ArelInjection.rb:23:14:23:52 | "SELECT * FROM users WHERE nam..." | semmle.label | "SELECT * FROM users WHERE nam..." |
233247
| ArelInjection.rb:30:29:30:35 | user_id | semmle.label | user_id |
234248
| ArelInjection.rb:32:18:32:60 | "SELECT * FROM users WHERE id ..." | semmle.label | "SELECT * FROM users WHERE id ..." |
235-
| ArelInjection.rb:38:7:38:13 | user_id | semmle.label | user_id |
236-
| ArelInjection.rb:38:17:38:22 | call to params | semmle.label | call to params |
237-
| ArelInjection.rb:38:17:38:32 | ...[...] | semmle.label | ...[...] |
238-
| ArelInjection.rb:39:25:39:31 | user_id | semmle.label | user_id |
249+
| ArelInjection.rb:47:7:47:13 | user_id | semmle.label | user_id |
250+
| ArelInjection.rb:47:17:47:22 | call to params | semmle.label | call to params |
251+
| ArelInjection.rb:47:17:47:32 | ...[...] | semmle.label | ...[...] |
252+
| ArelInjection.rb:48:7:48:14 | route_id | semmle.label | route_id |
253+
| ArelInjection.rb:48:18:48:38 | call to route_param | semmle.label | call to route_param |
254+
| ArelInjection.rb:49:7:49:10 | auth | semmle.label | auth |
255+
| ArelInjection.rb:49:14:49:20 | call to headers | semmle.label | call to headers |
256+
| ArelInjection.rb:49:14:49:36 | ...[...] | semmle.label | ...[...] |
257+
| ArelInjection.rb:50:7:50:13 | session | semmle.label | session |
258+
| ArelInjection.rb:50:17:50:23 | call to cookies | semmle.label | call to cookies |
259+
| ArelInjection.rb:50:17:50:36 | ...[...] | semmle.label | ...[...] |
260+
| ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | semmle.label | "SELECT * FROM users WHERE id ..." |
261+
| ArelInjection.rb:59:7:59:13 | user_id | semmle.label | user_id |
262+
| ArelInjection.rb:59:17:59:22 | call to params | semmle.label | call to params |
263+
| ArelInjection.rb:59:17:59:32 | ...[...] | semmle.label | ...[...] |
264+
| ArelInjection.rb:60:25:60:31 | user_id | semmle.label | user_id |
265+
| ArelInjection.rb:67:9:67:15 | user_id | semmle.label | user_id |
266+
| ArelInjection.rb:67:19:67:24 | call to params | semmle.label | call to params |
267+
| ArelInjection.rb:67:19:67:29 | ...[...] | semmle.label | ...[...] |
268+
| ArelInjection.rb:68:18:68:60 | "SELECT * FROM users WHERE id ..." | semmle.label | "SELECT * FROM users WHERE id ..." |
239269
| PgInjection.rb:6:5:6:8 | name | semmle.label | name |
240270
| PgInjection.rb:6:12:6:17 | call to params | semmle.label | call to params |
241271
| PgInjection.rb:6:12:6:24 | ...[...] | semmle.label | ...[...] |
@@ -296,7 +326,12 @@ subpaths
296326
| ArelInjection.rb:15:20:15:61 | "SELECT * FROM users WHERE nam..." | ArelInjection.rb:13:12:13:17 | call to params | ArelInjection.rb:15:20:15:61 | "SELECT * FROM users WHERE nam..." | This SQL query depends on a $@. | ArelInjection.rb:13:12:13:17 | call to params | user-provided value |
297327
| ArelInjection.rb:16:39:16:80 | "SELECT * FROM users WHERE nam..." | ArelInjection.rb:13:12:13:17 | call to params | ArelInjection.rb:16:39:16:80 | "SELECT * FROM users WHERE nam..." | This SQL query depends on a $@. | ArelInjection.rb:13:12:13:17 | call to params | user-provided value |
298328
| ArelInjection.rb:23:14:23:52 | "SELECT * FROM users WHERE nam..." | ArelInjection.rb:22:9:22:14 | call to params | ArelInjection.rb:23:14:23:52 | "SELECT * FROM users WHERE nam..." | This SQL query depends on a $@. | ArelInjection.rb:22:9:22:14 | call to params | user-provided value |
299-
| ArelInjection.rb:32:18:32:60 | "SELECT * FROM users WHERE id ..." | ArelInjection.rb:38:17:38:22 | call to params | ArelInjection.rb:32:18:32:60 | "SELECT * FROM users WHERE id ..." | This SQL query depends on a $@. | ArelInjection.rb:38:17:38:22 | call to params | user-provided value |
329+
| ArelInjection.rb:32:18:32:60 | "SELECT * FROM users WHERE id ..." | ArelInjection.rb:59:17:59:22 | call to params | ArelInjection.rb:32:18:32:60 | "SELECT * FROM users WHERE id ..." | This SQL query depends on a $@. | ArelInjection.rb:59:17:59:22 | call to params | user-provided value |
330+
| ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | ArelInjection.rb:47:17:47:22 | call to params | ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | This SQL query depends on a $@. | ArelInjection.rb:47:17:47:22 | call to params | user-provided value |
331+
| ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | ArelInjection.rb:48:18:48:38 | call to route_param | ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | This SQL query depends on a $@. | ArelInjection.rb:48:18:48:38 | call to route_param | user-provided value |
332+
| ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | ArelInjection.rb:49:14:49:20 | call to headers | ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | This SQL query depends on a $@. | ArelInjection.rb:49:14:49:20 | call to headers | user-provided value |
333+
| ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | ArelInjection.rb:50:17:50:23 | call to cookies | ArelInjection.rb:54:16:54:153 | "SELECT * FROM users WHERE id ..." | This SQL query depends on a $@. | ArelInjection.rb:50:17:50:23 | call to cookies | user-provided value |
334+
| ArelInjection.rb:68:18:68:60 | "SELECT * FROM users WHERE id ..." | ArelInjection.rb:67:19:67:24 | call to params | ArelInjection.rb:68:18:68:60 | "SELECT * FROM users WHERE id ..." | This SQL query depends on a $@. | ArelInjection.rb:67:19:67:24 | call to params | user-provided value |
300335
| PgInjection.rb:14:15:14:18 | qry1 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:14:15:14:18 | qry1 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value |
301336
| PgInjection.rb:15:21:15:24 | qry1 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:15:21:15:24 | qry1 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value |
302337
| PgInjection.rb:20:22:20:25 | qry2 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:20:22:20:25 | qry2 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value |

0 commit comments

Comments
 (0)