Skip to content

Commit

Permalink
Merge pull request #16185 from alexrford/rb/conditions-arr0
Browse files Browse the repository at this point in the history
Ruby: ActiveRecord - refine `conditions` argument as an SQLi sink
  • Loading branch information
alexrford authored May 22, 2024
2 parents a006c29 + 98a6d0f commit 8119a27
Show file tree
Hide file tree
Showing 3 changed files with 248 additions and 226 deletions.
9 changes: 8 additions & 1 deletion ruby/ql/lib/codeql/ruby/frameworks/ActiveRecord.qll
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,14 @@ private predicate sqlFragmentArgumentInner(DataFlow::CallNode call, DataFlow::No
or
// This format was supported until Rails 2.3.8
call = activeRecordQueryBuilderCall(["all", "find", "first", "last"]) and
sink = call.getKeywordArgument("conditions")
exists(DataFlow::LocalSourceNode sn |
sn = call.getKeywordArgument("conditions").getALocalSource()
|
sink = sn.(DataFlow::ArrayLiteralNode).getElement(0)
or
sn.(DataFlow::LiteralNode).asLiteralAstNode() instanceof StringlikeLiteral and
sink = sn
)
or
call = activeRecordQueryBuilderCall("reload") and
sink = call.getKeywordArgument("lock")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ class User < ApplicationRecord
def self.authenticate(name, pass)
# BAD: possible untrusted input interpolated into SQL fragment
find(:first, :conditions => "name='#{name}' and pass='#{pass}'")
# BAD: interpolation in array argument
find(:first, conditions: ["name='#{name}' and pass='#{pass}'"])
# GOOD: using SQL parameters
find(:first, conditions: ["name = ? and pass = ?", name, pass])
# BAD: interpolation with flow
conds = "name=#{name}"
find(:first, conditions: conds)
end

def self.from(user_group_id)
Expand Down Expand Up @@ -117,7 +124,7 @@ def some_request_handler

# BAD: executes `SELECT users.* FROM #{params[:tab]}`
# where `params[:tab]` is unsanitized
User.all.from(params[:tab])
User.all.from(params[:tab])
# BAD: executes `SELECT "users".* FROM (SELECT "users".* FROM "users") #{params[:sq]}
User.all.from(User.all, params[:sq])
end
Expand Down
Loading

0 comments on commit 8119a27

Please sign in to comment.