diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Mysql2.qll b/ruby/ql/lib/codeql/ruby/frameworks/Mysql2.qll index c1c74813b75..1b7c1cde61e 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Mysql2.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Mysql2.qll @@ -48,4 +48,26 @@ module Mysql2 { override DataFlow::Node getSql() { result = query } } + + /** + * A call to `Mysql2::Client.escape`, considered as a sanitizer for SQL statements. + */ + private class Mysql2EscapeSanitization extends SqlSanitization::Range { + Mysql2EscapeSanitization() { + this = API::getTopLevelMember("Mysql2").getMember("Client").getAMethodCall("escape") + } + } + + /** + * Flow summary for `Mysql2::Client.escape()`. + */ + private class EscapeSummary extends SummarizedCallable { + EscapeSummary() { this = "Mysql2::Client.escape()" } + + override MethodCall getACall() { result = any(Mysql2EscapeSanitization c).asExpr().getExpr() } + + override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + input = "Argument[0]" and output = "ReturnValue" and preservesValue = false + } + } } diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Sqlite3.qll b/ruby/ql/lib/codeql/ruby/frameworks/Sqlite3.qll index e051a847993..8a07e211a21 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Sqlite3.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Sqlite3.qll @@ -77,4 +77,26 @@ module Sqlite3 { override DataFlow::Node getSql() { result = this.getArgument(0) } } -} + + /** + * A call to `SQLite3::Database.quote`, considered as a sanitizer for SQL statements. + */ + private class SQLite3QuoteSanitization extends SqlSanitization { + SQLite3QuoteSanitization() { + this = API::getTopLevelMember("SQLite3").getMember("Database").getAMethodCall("quote") + } + } + + /** + * Flow summary for `SQLite3::Database.quote()`. + */ + private class QuoteSummary extends SummarizedCallable { + QuoteSummary() { this = "SQLite3::Database.quote()" } + + override MethodCall getACall() { result = any(SQLite3QuoteSanitization c).asExpr().getExpr() } + + override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + input = "Argument[0]" and output = "ReturnValue" and preservesValue = false + } + } +} \ No newline at end of file diff --git a/ruby/ql/lib/codeql/ruby/security/SqlInjectionCustomizations.qll b/ruby/ql/lib/codeql/ruby/security/SqlInjectionCustomizations.qll index e1e1b630d9d..48358fe1d6b 100644 --- a/ruby/ql/lib/codeql/ruby/security/SqlInjectionCustomizations.qll +++ b/ruby/ql/lib/codeql/ruby/security/SqlInjectionCustomizations.qll @@ -52,23 +52,8 @@ module SqlInjection { * sanitizer-guard. */ class StringConstArrayInclusionCallAsSanitizer extends Sanitizer, - StringConstArrayInclusionCallBarrier { } + StringConstArrayInclusionCallBarrier + { } - /** - * A call to `Mysql2::Client.escape`, considered as a sanitizer. - */ - private class Mysql2EscapeSanitization extends Sanitizer { - Mysql2EscapeSanitization() { - this = API::getTopLevelMember("Mysql2").getMember("Client").getAMethodCall("escape") - } - } - - /** - * A call to `SQLite3::Database.quote`, considered as a sanitizer. - */ - private class SQLite3EscapeSanitization extends Sanitizer { - SQLite3EscapeSanitization() { - this = API::getTopLevelMember("SQLite3").getMember("Database").getAMethodCall("quote") - } - } + private class SqlSanitizationAsSanitizer extends Sanitizer, SqlSanitization { } }