44
55private import ruby
66private import codeql.ruby.DataFlow
7+ private import codeql.ruby.DataFlow2
78private import codeql.ruby.CFG
89private import codeql.ruby.Concepts
910private import codeql.ruby.Frameworks
1011private import codeql.ruby.frameworks.ActionController
1112private import codeql.ruby.frameworks.ActionView
13+ private import codeql.ruby.frameworks.ActiveRecord
1214private import codeql.ruby.dataflow.RemoteFlowSources
1315private import codeql.ruby.dataflow.BarrierGuards
1416private import codeql.ruby.dataflow.internal.DataFlowDispatch
@@ -122,9 +124,9 @@ private module Shared {
122124 }
123125
124126 /**
125- * An additional step that is taint-preserving in the context of reflected XSS.
127+ * An additional step that is preserves dataflow in the context of reflected XSS.
126128 */
127- predicate isAdditionalXSSTaintStep ( DataFlow:: Node node1 , DataFlow:: Node node2 ) {
129+ predicate isAdditionalXSSFlowStep ( DataFlow:: Node node1 , DataFlow:: Node node2 ) {
128130 // node1 is a `locals` argument to a render call...
129131 exists ( RenderCall call , Pair kvPair , string hashKey |
130132 call .getLocals ( ) .getAKeyValuePair ( ) = kvPair and
@@ -229,19 +231,38 @@ module ReflectedXSS {
229231 }
230232
231233 // Consider all arbitrary XSS taint steps to be reflected XSS taint steps
232- predicate isAdditionalXSSTaintStep = Shared:: isAdditionalXSSTaintStep / 2 ;
234+ predicate isAdditionalXSSTaintStep = Shared:: isAdditionalXSSFlowStep / 2 ;
233235
234236 /**
235237 * A source of remote user input, considered as a flow source.
236238 */
237239 class RemoteFlowSourceAsSource extends Source , RemoteFlowSource { }
238240}
239241
240- /**
241- * Provides default sources, sinks and sanitizers for detecting
242- * "stored server-side cross-site scripting" vulnerabilities, as well as
243- * extension points for adding your own.
244- */
242+ private module OrmTracking {
243+ /**
244+ * A data flow configuration to track flow from finder calls to field accesses.
245+ */
246+ class Configuration extends DataFlow2:: Configuration {
247+ Configuration ( ) { this = "OrmTracking" }
248+
249+ // TODO: abstract to ORMFinderCall concept
250+ override predicate isSource ( DataFlow2:: Node source ) {
251+ source instanceof ActiveRecordModelInstantiation
252+ }
253+
254+ // Select any call node and narrow down later
255+ override predicate isSink ( DataFlow2:: Node sink ) { sink instanceof DataFlow2:: CallNode }
256+
257+ override predicate isAdditionalFlowStep ( DataFlow2:: Node node1 , DataFlow2:: Node node2 ) {
258+ Shared:: isAdditionalXSSFlowStep ( node1 , node2 )
259+ or
260+ // Propagate flow through arbitrary method calls
261+ node2 .( DataFlow2:: CallNode ) .getReceiver ( ) = node1
262+ }
263+ }
264+ }
265+
245266module StoredXSS {
246267 /** A data flow source for stored XSS vulnerabilities. */
247268 abstract class Source extends Shared:: Source { }
@@ -268,11 +289,19 @@ module StoredXSS {
268289 }
269290 }
270291
271- // Consider all arbitrary XSS taint steps to be stored XSS taint steps
272- predicate isAdditionalXSSTaintStep = Shared:: isAdditionalXSSTaintStep / 2 ;
292+ predicate isAdditionalXSSTaintStep = Shared:: isAdditionalXSSFlowStep / 2 ;
293+
294+ private class ActiveRecordModelFieldAccessAsSource extends Source {
295+ ActiveRecordModelFieldAccessAsSource ( ) {
296+ exists ( OrmTracking:: Configuration subConfig , DataFlow2:: Node subSrc |
297+ subConfig .hasFlow ( subSrc , this ) and
298+ activeRecordMethodMayAccessField ( subSrc .( ActiveRecordModelInstantiation ) .getClass ( ) ,
299+ this .asExpr ( ) .getExpr ( ) )
300+ )
301+ }
302+ }
273303
274304 /** A file read, considered as a flow source for stored XSS. */
275- class FileSystemReadAccessAsSource extends Source instanceof FileSystemReadAccess { }
305+ private class FileSystemReadAccessAsSource extends Source instanceof FileSystemReadAccess { }
276306 // TODO: Consider `FileNameSource` flowing to script tag `src` attributes and similar
277- // TODO: ORM database reads as sources
278307}
0 commit comments