diff --git a/ql/lib/codeql/ruby/security/UnsafeDeserializationCustomizations.qll b/ql/lib/codeql/ruby/security/UnsafeDeserializationCustomizations.qll index 875081caa48..84e61bd1ece 100644 --- a/ql/lib/codeql/ruby/security/UnsafeDeserializationCustomizations.qll +++ b/ql/lib/codeql/ruby/security/UnsafeDeserializationCustomizations.qll @@ -25,6 +25,13 @@ module UnsafeDeserialization { */ abstract class Sanitizer extends DataFlow::Node { } + /** + * Additional taint steps for "unsafe deserialization" vulnerabilities. + */ + predicate isAdditionalTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) { + base64DecodeTaintStep(fromNode, toNode) + } + /** A source of remote user input, considered as a flow source for unsafe deserialization. */ class RemoteFlowSourceAsSource extends Source { RemoteFlowSourceAsSource() { this instanceof RemoteFlowSource } @@ -59,4 +66,18 @@ module UnsafeDeserialization { this = API::getTopLevelMember("JSON").getAMethodCall(["load", "restore"]).getArgument(0) } } + + /** + * `Base64.decode64` propagates taint from its argument to its return value. + */ + predicate base64DecodeTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) { + exists(DataFlow::CallNode callNode | + callNode = + API::getTopLevelMember("Base64") + .getAMethodCall(["decode64", "strict_decode64", "urlsafe_decode64"]) + | + fromNode = callNode.getArgument(0) and + toNode = callNode + ) + } } diff --git a/ql/lib/codeql/ruby/security/UnsafeDeserializationQuery.qll b/ql/lib/codeql/ruby/security/UnsafeDeserializationQuery.qll index f8d19ab76f4..d08b73da936 100644 --- a/ql/lib/codeql/ruby/security/UnsafeDeserializationQuery.qll +++ b/ql/lib/codeql/ruby/security/UnsafeDeserializationQuery.qll @@ -27,4 +27,8 @@ class Configuration extends TaintTracking::Configuration { super.isSanitizer(node) or node instanceof UnsafeDeserialization::Sanitizer } + + override predicate isAdditionalTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) { + UnsafeDeserialization::isAdditionalTaintStep(fromNode, toNode) + } }