Skip to content

Ruby: ActiveRecord - refine conditions argument as an SQLi sink #16185

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
May 22, 2024

Conversation

alexrford
Copy link
Contributor

See https://guides.rubyonrails.org/v2.3/active_record_querying.html#conditions

We previously assumed a string argument - but array arguments are only vulnerable if the first element is tainted.

@alexrford alexrford added no-change-note-required This PR does not need a change note Ruby labels Apr 11, 2024
@alexrford alexrford force-pushed the rb/conditions-arr0 branch from 4d848b8 to 91bca4a Compare April 12, 2024 14:32
@alexrford alexrford marked this pull request as ready for review April 12, 2024 14:34
@alexrford alexrford requested a review from a team as a code owner April 12, 2024 14:34
sink = sn.(DataFlow::ArrayLiteralNode).getElement(0)
or
sn.(DataFlow::LiteralNode).asLiteralAstNode() instanceof StringlikeLiteral and
sink = sn
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this find cases like this?

conds = "name=#{name}"
find(:first, conditions: conds)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does (added a test case), although it marks the string as the sink rather than the conds argument in the find call as the sink which is not ideal.

In this particular case we could say call.getKeywordArgument("conditions") = sink instead, but there's a weird edge case for something like:

if some_condition
  conds = ["name = ?", name] # safe path
else
  conds = "name = #{name}" # dangerous path
end
find(:first, conditions: conds)

where the safe path would be flagged up because the SQLi query itself doesn't have the extra context of why the conditions argument is vulnerable.

I think it's possible for this logic to move into the query itself, but I worry that it could get quite complex. For example, there could be some sinks where a tainted array in general is vulnerable vs. cases like conditions where only arrays where the first element is tainted is vulnerable. I suspect we would have to introduce flow states to track this context, and then add information to each sink to note what kinds of values are potentially dangerous.

Copy link
Contributor

@joefarebrother joefarebrother left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good 👍

@alexrford alexrford merged commit 8119a27 into github:main May 22, 2024
@alexrford alexrford deleted the rb/conditions-arr0 branch May 22, 2024 11:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
no-change-note-required This PR does not need a change note Ruby
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants