Skip to content

Commit 89e9ee4

Browse files
committed
Convert from GrapeHelperMethodTaintStep extends AdditionalTaintStep to a simplified GrapeHelperMethodTarget extends AdditionalCallTarget
1 parent 141b470 commit 89e9ee4

File tree

4 files changed

+49
-32
lines changed

4 files changed

+49
-32
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
---
22
category: feature
33
---
4-
* Initial modeling for the Ruby Grape framework in `Grape.qll` have been added to detect API endpoints, parameters, and headers within Grape API classes.
4+
* Initial modeling for the Ruby Grape framework in `Grape.qll` has been added to detect API endpoints, parameters, and headers within Grape API classes.

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

Lines changed: 14 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
*/
44

55
private import codeql.ruby.AST
6+
private import codeql.ruby.CFG
67
private import codeql.ruby.Concepts
78
private import codeql.ruby.controlflow.CfgNodes
89
private import codeql.ruby.DataFlow
@@ -301,32 +302,20 @@ private class GrapeHelperMethod extends Method {
301302
}
302303

303304
/**
304-
* Additional taint step to model dataflow from method arguments to parameters
305-
* and from return values back to call sites for Grape helper methods defined in `helpers` blocks.
306-
* This bridges the gap where standard dataflow doesn't recognize the Grape DSL semantics.
305+
* Additional call-target to resolve helper method calls defined in `helpers` blocks.
306+
*
307+
* This class is responsible for resolving calls to helper methods defined in
308+
* `helpers` blocks, allowing the dataflow framework to accurately track
309+
* the flow of information between these methods and their call sites.
307310
*/
308-
private class GrapeHelperMethodTaintStep extends AdditionalTaintStep {
309-
override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
310-
// Map arguments to parameters for helper method calls
311-
exists(GrapeHelperMethod helperMethod, MethodCall call, int i |
312-
// Find calls to helper methods from within Grape endpoints or other helper methods
313-
call.getMethodName() = helperMethod.getName() and
314-
exists(GrapeApiClass api | call.getParent+() = api.getADeclaration()) and
315-
// Map argument to parameter
316-
nodeFrom.asExpr().getExpr() = call.getArgument(i) and
317-
nodeTo.asParameter() = helperMethod.getParameter(i)
318-
)
319-
or
320-
// Model implicit return values: the last expression in a helper method flows to the call site
321-
exists(GrapeHelperMethod helperMethod, MethodCall helperCall, Expr lastExpr |
322-
// Find calls to helper methods from within Grape endpoints or other helper methods
323-
helperCall.getMethodName() = helperMethod.getName() and
324-
exists(GrapeApiClass api | helperCall.getParent+() = api.getADeclaration()) and
325-
// Get the last expression in the helper method (Ruby's implicit return)
326-
lastExpr = helperMethod.getLastStmt() and
327-
// Flow from the last expression in the helper method to the call site
328-
nodeFrom.asExpr().getExpr() = lastExpr and
329-
nodeTo.asExpr().getExpr() = helperCall
311+
private class GrapeHelperMethodTarget extends AdditionalCallTarget {
312+
override DataFlowCallable viableTarget(CfgNodes::ExprNodes::CallCfgNode call) {
313+
// Find calls to helper methods from within Grape endpoints or other helper methods
314+
exists(GrapeHelperMethod helperMethod, MethodCall mc |
315+
result.asCfgScope() = helperMethod and
316+
mc = call.getAstNode() and
317+
mc.getMethodName() = helperMethod.getName() and
318+
mc.getParent+() = helperMethod.getApiClass().getADeclaration()
330319
)
331320
}
332321
}

ruby/ql/test/library-tests/frameworks/grape/Flow.expected

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
models
22
edges
33
| app.rb:103:13:103:18 | call to params | app.rb:103:13:103:70 | call to select | provenance | |
4-
| app.rb:103:13:103:70 | call to select | app.rb:149:21:149:31 | call to user_params | provenance | AdditionalTaintStep |
5-
| app.rb:103:13:103:70 | call to select | app.rb:165:21:165:31 | call to user_params | provenance | AdditionalTaintStep |
6-
| app.rb:107:13:107:32 | call to source | app.rb:143:18:143:43 | call to vulnerable_helper | provenance | AdditionalTaintStep |
7-
| app.rb:111:13:111:33 | call to source | app.rb:150:25:150:37 | call to simple_helper | provenance | AdditionalTaintStep |
4+
| app.rb:103:13:103:18 | call to params | app.rb:103:13:103:70 | call to select : [collection] [element] | provenance | |
5+
| app.rb:103:13:103:70 | call to select | app.rb:149:21:149:31 | call to user_params | provenance | |
6+
| app.rb:103:13:103:70 | call to select | app.rb:165:21:165:31 | call to user_params | provenance | |
7+
| app.rb:103:13:103:70 | call to select : [collection] [element] | app.rb:149:21:149:31 | call to user_params : [collection] [element] | provenance | |
8+
| app.rb:103:13:103:70 | call to select : [collection] [element] | app.rb:165:21:165:31 | call to user_params : [collection] [element] | provenance | |
9+
| app.rb:107:13:107:32 | call to source | app.rb:143:18:143:43 | call to vulnerable_helper | provenance | |
10+
| app.rb:107:13:107:32 | call to source | app.rb:143:18:143:43 | call to vulnerable_helper | provenance | |
11+
| app.rb:111:13:111:33 | call to source | app.rb:150:25:150:37 | call to simple_helper | provenance | |
12+
| app.rb:111:13:111:33 | call to source | app.rb:150:25:150:37 | call to simple_helper | provenance | |
813
| app.rb:126:9:126:15 | user_id | app.rb:133:14:133:20 | user_id | provenance | |
914
| app.rb:126:19:126:24 | call to params | app.rb:126:19:126:34 | ...[...] | provenance | |
1015
| app.rb:126:19:126:34 | ...[...] | app.rb:126:9:126:15 | user_id | provenance | |
@@ -17,20 +22,31 @@ edges
1722
| app.rb:129:19:129:25 | call to cookies | app.rb:129:19:129:38 | ...[...] | provenance | |
1823
| app.rb:129:19:129:38 | ...[...] | app.rb:129:9:129:15 | session | provenance | |
1924
| app.rb:143:9:143:14 | result | app.rb:144:14:144:19 | result | provenance | |
25+
| app.rb:143:9:143:14 | result | app.rb:144:14:144:19 | result | provenance | |
26+
| app.rb:143:18:143:43 | call to vulnerable_helper | app.rb:143:9:143:14 | result | provenance | |
2027
| app.rb:143:18:143:43 | call to vulnerable_helper | app.rb:143:9:143:14 | result | provenance | |
2128
| app.rb:149:9:149:17 | user_data | app.rb:151:14:151:22 | user_data | provenance | |
29+
| app.rb:149:9:149:17 | user_data : [collection] [element] | app.rb:151:14:151:22 | user_data | provenance | |
2230
| app.rb:149:21:149:31 | call to user_params | app.rb:149:9:149:17 | user_data | provenance | |
31+
| app.rb:149:21:149:31 | call to user_params : [collection] [element] | app.rb:149:9:149:17 | user_data : [collection] [element] | provenance | |
2332
| app.rb:150:9:150:21 | simple_result | app.rb:152:14:152:26 | simple_result | provenance | |
33+
| app.rb:150:9:150:21 | simple_result | app.rb:152:14:152:26 | simple_result | provenance | |
34+
| app.rb:150:25:150:37 | call to simple_helper | app.rb:150:9:150:21 | simple_result | provenance | |
2435
| app.rb:150:25:150:37 | call to simple_helper | app.rb:150:9:150:21 | simple_result | provenance | |
2536
| app.rb:159:13:159:19 | user_id | app.rb:160:18:160:24 | user_id | provenance | |
2637
| app.rb:159:23:159:28 | call to params | app.rb:159:23:159:33 | ...[...] | provenance | |
2738
| app.rb:159:23:159:33 | ...[...] | app.rb:159:13:159:19 | user_id | provenance | |
2839
| app.rb:165:9:165:17 | user_data | app.rb:166:14:166:22 | user_data | provenance | |
40+
| app.rb:165:9:165:17 | user_data : [collection] [element] | app.rb:166:14:166:22 | user_data | provenance | |
2941
| app.rb:165:21:165:31 | call to user_params | app.rb:165:9:165:17 | user_data | provenance | |
42+
| app.rb:165:21:165:31 | call to user_params : [collection] [element] | app.rb:165:9:165:17 | user_data : [collection] [element] | provenance | |
3043
nodes
3144
| app.rb:103:13:103:18 | call to params | semmle.label | call to params |
3245
| app.rb:103:13:103:70 | call to select | semmle.label | call to select |
46+
| app.rb:103:13:103:70 | call to select : [collection] [element] | semmle.label | call to select : [collection] [element] |
3347
| app.rb:107:13:107:32 | call to source | semmle.label | call to source |
48+
| app.rb:107:13:107:32 | call to source | semmle.label | call to source |
49+
| app.rb:111:13:111:33 | call to source | semmle.label | call to source |
3450
| app.rb:111:13:111:33 | call to source | semmle.label | call to source |
3551
| app.rb:126:9:126:15 | user_id | semmle.label | user_id |
3652
| app.rb:126:19:126:24 | call to params | semmle.label | call to params |
@@ -48,20 +64,30 @@ nodes
4864
| app.rb:135:14:135:17 | auth | semmle.label | auth |
4965
| app.rb:136:14:136:20 | session | semmle.label | session |
5066
| app.rb:143:9:143:14 | result | semmle.label | result |
67+
| app.rb:143:9:143:14 | result | semmle.label | result |
5168
| app.rb:143:18:143:43 | call to vulnerable_helper | semmle.label | call to vulnerable_helper |
69+
| app.rb:143:18:143:43 | call to vulnerable_helper | semmle.label | call to vulnerable_helper |
70+
| app.rb:144:14:144:19 | result | semmle.label | result |
5271
| app.rb:144:14:144:19 | result | semmle.label | result |
5372
| app.rb:149:9:149:17 | user_data | semmle.label | user_data |
73+
| app.rb:149:9:149:17 | user_data : [collection] [element] | semmle.label | user_data : [collection] [element] |
5474
| app.rb:149:21:149:31 | call to user_params | semmle.label | call to user_params |
75+
| app.rb:149:21:149:31 | call to user_params : [collection] [element] | semmle.label | call to user_params : [collection] [element] |
5576
| app.rb:150:9:150:21 | simple_result | semmle.label | simple_result |
77+
| app.rb:150:9:150:21 | simple_result | semmle.label | simple_result |
78+
| app.rb:150:25:150:37 | call to simple_helper | semmle.label | call to simple_helper |
5679
| app.rb:150:25:150:37 | call to simple_helper | semmle.label | call to simple_helper |
5780
| app.rb:151:14:151:22 | user_data | semmle.label | user_data |
5881
| app.rb:152:14:152:26 | simple_result | semmle.label | simple_result |
82+
| app.rb:152:14:152:26 | simple_result | semmle.label | simple_result |
5983
| app.rb:159:13:159:19 | user_id | semmle.label | user_id |
6084
| app.rb:159:23:159:28 | call to params | semmle.label | call to params |
6185
| app.rb:159:23:159:33 | ...[...] | semmle.label | ...[...] |
6286
| app.rb:160:18:160:24 | user_id | semmle.label | user_id |
6387
| app.rb:165:9:165:17 | user_data | semmle.label | user_data |
88+
| app.rb:165:9:165:17 | user_data : [collection] [element] | semmle.label | user_data : [collection] [element] |
6489
| app.rb:165:21:165:31 | call to user_params | semmle.label | call to user_params |
90+
| app.rb:165:21:165:31 | call to user_params : [collection] [element] | semmle.label | call to user_params : [collection] [element] |
6591
| app.rb:166:14:166:22 | user_data | semmle.label | user_data |
6692
subpaths
6793
testFailures
@@ -71,7 +97,9 @@ testFailures
7197
| app.rb:135:14:135:17 | auth | app.rb:128:16:128:22 | call to headers | app.rb:135:14:135:17 | auth | $@ | app.rb:128:16:128:22 | call to headers | call to headers |
7298
| app.rb:136:14:136:20 | session | app.rb:129:19:129:25 | call to cookies | app.rb:136:14:136:20 | session | $@ | app.rb:129:19:129:25 | call to cookies | call to cookies |
7399
| app.rb:144:14:144:19 | result | app.rb:107:13:107:32 | call to source | app.rb:144:14:144:19 | result | $@ | app.rb:107:13:107:32 | call to source | call to source |
100+
| app.rb:144:14:144:19 | result | app.rb:107:13:107:32 | call to source | app.rb:144:14:144:19 | result | $@ | app.rb:107:13:107:32 | call to source | call to source |
74101
| app.rb:151:14:151:22 | user_data | app.rb:103:13:103:18 | call to params | app.rb:151:14:151:22 | user_data | $@ | app.rb:103:13:103:18 | call to params | call to params |
75102
| app.rb:152:14:152:26 | simple_result | app.rb:111:13:111:33 | call to source | app.rb:152:14:152:26 | simple_result | $@ | app.rb:111:13:111:33 | call to source | call to source |
103+
| app.rb:152:14:152:26 | simple_result | app.rb:111:13:111:33 | call to source | app.rb:152:14:152:26 | simple_result | $@ | app.rb:111:13:111:33 | call to source | call to source |
76104
| app.rb:160:18:160:24 | user_id | app.rb:159:23:159:28 | call to params | app.rb:160:18:160:24 | user_id | $@ | app.rb:159:23:159:28 | call to params | call to params |
77105
| app.rb:166:14:166:22 | user_data | app.rb:103:13:103:18 | call to params | app.rb:166:14:166:22 | user_data | $@ | app.rb:103:13:103:18 | call to params | call to params |

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,15 +141,15 @@ def simple_helper
141141
# Test helper method parameter passing dataflow
142142
user_id = params[:user_id]
143143
result = vulnerable_helper(user_id)
144-
sink result # $ hasTaintFlow=paramHelper
144+
sink result # $ hasValueFlow=paramHelper
145145
end
146146

147147
post '/users' do
148148
# Test helper method return dataflow
149149
user_data = user_params
150150
simple_result = simple_helper
151151
sink user_data # $ hasTaintFlow
152-
sink simple_result # $ hasTaintFlow=simpleHelper
152+
sink simple_result # $ hasValueFlow=simpleHelper
153153
end
154154

155155
# Test route_param block pattern

0 commit comments

Comments
 (0)