diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll index fe0899d4763..d8b04bebfab 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll @@ -327,7 +327,12 @@ private module Cached { FlowSummaryImpl::Private::Steps::summaryThroughStepValue(nodeFrom, nodeTo, _) } - /** This is the local flow predicate that is used in type tracking. */ + /** + * This is the local flow predicate that is used in type tracking. + * + * This needs to exclude `localFlowSsaParamInput` due to a performance trick + * in type tracking, where such steps are treated as call steps. + */ cached predicate localFlowStepTypeTracker(Node nodeFrom, Node nodeTo) { LocalFlow::localFlowStepCommon(nodeFrom, nodeTo) diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll index 8af1d31e303..16740ce33fe 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll @@ -326,9 +326,11 @@ private module Cached { source = sink and source instanceof LocalSourceNode or - exists(Node mid | - hasLocalSource(mid, source) and + exists(Node mid | hasLocalSource(mid, source) | localFlowStepTypeTracker(mid, sink) + or + // Explicitly include the SSA param input step as type-tracking omits this step. + LocalFlow::localFlowSsaParamInput(mid, sink) ) }