Skip to content

Commit 8119a27

Browse files
authored
Merge pull request github#16185 from alexrford/rb/conditions-arr0
Ruby: ActiveRecord - refine `conditions` argument as an SQLi sink
2 parents a006c29 + 98a6d0f commit 8119a27

File tree

3 files changed

+248
-226
lines changed

3 files changed

+248
-226
lines changed

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,14 @@ private predicate sqlFragmentArgumentInner(DataFlow::CallNode call, DataFlow::No
195195
or
196196
// This format was supported until Rails 2.3.8
197197
call = activeRecordQueryBuilderCall(["all", "find", "first", "last"]) and
198-
sink = call.getKeywordArgument("conditions")
198+
exists(DataFlow::LocalSourceNode sn |
199+
sn = call.getKeywordArgument("conditions").getALocalSource()
200+
|
201+
sink = sn.(DataFlow::ArrayLiteralNode).getElement(0)
202+
or
203+
sn.(DataFlow::LiteralNode).asLiteralAstNode() instanceof StringlikeLiteral and
204+
sink = sn
205+
)
199206
or
200207
call = activeRecordQueryBuilderCall("reload") and
201208
sink = call.getKeywordArgument("lock")

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@ class User < ApplicationRecord
88
def self.authenticate(name, pass)
99
# BAD: possible untrusted input interpolated into SQL fragment
1010
find(:first, :conditions => "name='#{name}' and pass='#{pass}'")
11+
# BAD: interpolation in array argument
12+
find(:first, conditions: ["name='#{name}' and pass='#{pass}'"])
13+
# GOOD: using SQL parameters
14+
find(:first, conditions: ["name = ? and pass = ?", name, pass])
15+
# BAD: interpolation with flow
16+
conds = "name=#{name}"
17+
find(:first, conditions: conds)
1118
end
1219

1320
def self.from(user_group_id)
@@ -117,7 +124,7 @@ def some_request_handler
117124

118125
# BAD: executes `SELECT users.* FROM #{params[:tab]}`
119126
# where `params[:tab]` is unsanitized
120-
User.all.from(params[:tab])
127+
User.all.from(params[:tab])
121128
# BAD: executes `SELECT "users".* FROM (SELECT "users".* FROM "users") #{params[:sq]}
122129
User.all.from(User.all, params[:sq])
123130
end

0 commit comments

Comments
 (0)