@@ -8,6 +8,10 @@ module SQL {
8
8
/** A string-valued expression that is interpreted as a SQL command. */
9
9
abstract class SqlString extends Expr { }
10
10
11
+ private class SqlStringFromModel extends SqlString {
12
+ SqlStringFromModel ( ) { this = ModelOutput:: getASinkNode ( "sql-injection" ) .getARhs ( ) .asExpr ( ) }
13
+ }
14
+
11
15
/**
12
16
* An expression that sanitizes a string to make it safe to embed into
13
17
* a SQL command.
@@ -474,176 +478,65 @@ private module MsSql {
474
478
* Provides classes modeling the `sequelize` package.
475
479
*/
476
480
private module Sequelize {
477
- /** Gets an import of the `sequelize` module or one that re-exports it. */
478
- API:: Node sequelize ( ) { result = API:: moduleImport ( [ "sequelize" , "sequelize-typescript" ] ) }
479
-
480
- /** Gets an expression that creates an instance of the `Sequelize` class. */
481
- API:: Node instance ( ) {
482
- result = [ sequelize ( ) , sequelize ( ) .getMember ( "Sequelize" ) ] .getInstance ( )
483
- or
484
- result = API:: Node:: ofType ( [ "sequelize" , "sequelize-typescript" ] , [ "Sequelize" , "default" ] )
485
- }
486
-
487
- /** A call to `Sequelize.query`. */
488
- private class QueryCall extends DatabaseAccess , DataFlow:: MethodCallNode {
489
- QueryCall ( ) { this = instance ( ) .getMember ( "query" ) .getACall ( ) }
490
-
491
- override DataFlow:: Node getAQueryArgument ( ) {
492
- result = this .getArgument ( 0 )
493
- or
494
- result = this .getOptionArgument ( 0 , "query" )
481
+ class SequelizeModel extends ModelInput:: TypeModelCsv {
482
+ override predicate row ( string row ) {
483
+ // package1;type1;package2;type2;path
484
+ row =
485
+ [
486
+ "sequelize;;sequelize-typescript;;" , //
487
+ "sequelize;Sequelize;sequelize;default;" , //
488
+ "sequelize;Sequelize;sequelize;;Instance" ,
489
+ "sequelize;Sequelize;sequelize;;Member[Sequelize].Instance" ,
490
+ ]
495
491
}
496
492
}
497
493
498
- /** An expression that is passed to `Sequelize.query` method and hence interpreted as SQL. */
499
- class QueryString extends SQL:: SqlString {
500
- QueryString ( ) {
501
- this = any ( QueryCall qc ) .getAQueryArgument ( ) .asExpr ( )
502
- or
503
- this = sequelize ( ) .getMember ( [ "literal" , "asIs" ] ) .getParameter ( 0 ) .getARhs ( ) .asExpr ( )
494
+ class SequelizeSink extends ModelInput:: SinkModelCsv {
495
+ override predicate row ( string row ) {
496
+ row =
497
+ [
498
+ "sequelize;Sequelize;Member[query].Argument[0];sql-injection" ,
499
+ "sequelize;Sequelize;Member[query].Argument[0].Member[query];sql-injection" ,
500
+ "sequelize;;Member[literal,asIs].Argument[0];sql-injection" ,
501
+ "sequelize;;Argument[1];credentials[user name]" ,
502
+ "sequelize;;Argument[2];credentials[password]" ,
503
+ "sequelize;;Argument[0..].Member[username];credentials[user name]" ,
504
+ "sequelize;;Argument[0..].Member[password];credentials[password]"
505
+ ]
504
506
}
505
507
}
506
-
507
- /**
508
- * An expression that is passed as user name or password when creating an instance of the
509
- * `Sequelize` class.
510
- */
511
- class Credentials extends CredentialsExpr {
512
- string kind ;
513
-
514
- Credentials ( ) {
515
- exists ( NewExpr ne , string prop |
516
- ne = sequelize ( ) .getAnInstantiation ( ) .asExpr ( ) and
517
- (
518
- this = ne .getArgument ( 1 ) and prop = "username"
519
- or
520
- this = ne .getArgument ( 2 ) and prop = "password"
521
- or
522
- ne .hasOptionArgument ( ne .getNumArgument ( ) - 1 , prop , this )
523
- ) and
524
- (
525
- prop = "username" and kind = "user name"
526
- or
527
- prop = "password" and kind = prop
528
- )
529
- )
530
- }
531
-
532
- override string getCredentialsKind ( ) { result = kind }
533
- }
534
508
}
535
509
536
- /**
537
- * Provides classes modeling the Google Cloud Spanner library.
538
- */
539
- private module Spanner {
540
- /**
541
- * Gets a node that refers to the `Spanner` class
542
- */
543
- API:: Node spanner ( ) {
544
- // older versions
545
- result = API:: moduleImport ( "@google-cloud/spanner" )
546
- or
547
- // newer versions
548
- result = API:: moduleImport ( "@google-cloud/spanner" ) .getMember ( "Spanner" )
549
- }
550
-
551
- /**
552
- * Gets a node that refers to an instance of the `Database` class.
553
- */
554
- API:: Node database ( ) {
555
- result =
556
- spanner ( ) .getReturn ( ) .getMember ( "instance" ) .getReturn ( ) .getMember ( "database" ) .getReturn ( )
557
- or
558
- result = API:: Node:: ofType ( "@google-cloud/spanner" , "Database" )
559
- }
560
-
561
- /**
562
- * Gets a node that refers to an instance of the `v1.SpannerClient` class.
563
- */
564
- API:: Node v1SpannerClient ( ) {
565
- result = spanner ( ) .getMember ( "v1" ) .getMember ( "SpannerClient" ) .getInstance ( )
566
- or
567
- result = API:: Node:: ofType ( "@google-cloud/spanner" , "v1.SpannerClient" )
568
- }
569
-
570
- /**
571
- * Gets a node that refers to a transaction object.
572
- */
573
- API:: Node transaction ( ) {
574
- result =
575
- database ( )
576
- .getMember ( [ "runTransaction" , "runTransactionAsync" ] )
577
- .getParameter ( [ 0 , 1 ] )
578
- .getParameter ( 1 )
579
- or
580
- result = API:: Node:: ofType ( "@google-cloud/spanner" , "Transaction" )
581
- }
582
-
583
- /** Gets an API node referring to a `BatchTransaction` object. */
584
- API:: Node batchTransaction ( ) {
585
- result = database ( ) .getMember ( "batchTransaction" ) .getReturn ( )
586
- or
587
- result = database ( ) .getMember ( "createBatchTransaction" ) .getReturn ( ) .getPromised ( )
588
- or
589
- result = API:: Node:: ofType ( "@google-cloud/spanner" , "BatchTransaction" )
590
- }
591
-
592
- /**
593
- * A call to a Spanner method that executes a SQL query.
594
- */
595
- abstract class SqlExecution extends DatabaseAccess , DataFlow:: InvokeNode { }
596
-
597
- /**
598
- * A SQL execution that takes the input directly in the first argument or in the `sql` option.
599
- */
600
- class SqlExecutionDirect extends SqlExecution {
601
- SqlExecutionDirect ( ) {
602
- this = database ( ) .getMember ( [ "run" , "runPartitionedUpdate" , "runStream" ] ) .getACall ( )
603
- or
604
- this = transaction ( ) .getMember ( [ "run" , "runStream" , "runUpdate" ] ) .getACall ( )
605
- or
606
- this = batchTransaction ( ) .getMember ( "createQueryPartitions" ) .getACall ( )
607
- }
608
-
609
- override DataFlow:: Node getAQueryArgument ( ) {
610
- result = this .getArgument ( 0 )
611
- or
612
- result = this .getOptionArgument ( 0 , "sql" )
510
+ private module SpannerCsv {
511
+ class SpannerTypes extends ModelInput:: TypeModelCsv {
512
+ override predicate row ( string row ) {
513
+ // package1; type1; package2; type2; path
514
+ row =
515
+ [
516
+ "@google-cloud/spanner;;@google-cloud/spanner;;Member[Spanner]" ,
517
+ "@google-cloud/spanner;Database;@google-cloud/spanner;;ReturnValue.Member[instance].ReturnValue.Member[database].ReturnValue" ,
518
+ "@google-cloud/spanner;v1.SpannerClient;@google-cloud/spanner;;Member[v1].Member[SpannerClient].Instance" ,
519
+ "@google-cloud/spanner;Transaction;@google-cloud/spanner;Database;Member[runTransaction,runTransactionAsync].Argument[0..1].Parameter[1]" ,
520
+ "@google-cloud/spanner;BatchTransaction;@google-cloud/spanner;Database;Member[batchTransaction].ReturnValue" ,
521
+ "@google-cloud/spanner;BatchTransaction;@google-cloud/spanner;Database;Member[createBatchTransaction].ReturnValue.Awaited" ,
522
+ "@google-cloud/spanner;~SqlExecutorDirect;@google-cloud/spanner;Database;Member[run,runPartitionedUpdate,runStream]" ,
523
+ "@google-cloud/spanner;~SqlExecutorDirect;@google-cloud/spanner;Transaction;Member[run,runStream,runUpdate]" ,
524
+ "@google-cloud/spanner;~SqlExecutorDirect;@google-cloud/spanner;BatchTransaction;Member[createQueryPartitions]" ,
525
+ ]
613
526
}
614
527
}
615
528
616
- /**
617
- * A SQL execution that takes an array of SQL strings or { sql: string } objects.
618
- */
619
- class SqlExecutionBatch extends SqlExecution , API:: CallNode {
620
- SqlExecutionBatch ( ) { this = transaction ( ) .getMember ( "batchUpdate" ) .getACall ( ) }
621
-
622
- override DataFlow:: Node getAQueryArgument ( ) {
623
- // just use the whole array as the query argument, as arrays becomes tainted if one of the elements
624
- // are tainted
625
- result = this .getArgument ( 0 )
626
- or
627
- result = this .getParameter ( 0 ) .getUnknownMember ( ) .getMember ( "sql" ) .getARhs ( )
529
+ class SpannerSinks extends ModelInput:: SinkModelCsv {
530
+ override predicate row ( string row ) {
531
+ // package; type; path; kind
532
+ row =
533
+ [
534
+ "@google-cloud/spanner;~SqlExecutorDirect;Argument[0];sql-injection" ,
535
+ "@google-cloud/spanner;~SqlExecutorDirect;Argument[0].Member[sql];sql-injection" ,
536
+ "@google-cloud/spanner;Transaction;Member[batchUpdate].Argument[0];sql-injection" ,
537
+ "@google-cloud/spanner;Transaction;Member[batchUpdate].Argument[0].ArrayElement.Member[sql];sql-injection" ,
538
+ "@google-cloud/spanner;v1.SpannerClient;Member[executeSql,executeStreamingSql].Argument[0].Member[sql];sql-injection" ,
539
+ ]
628
540
}
629
541
}
630
-
631
- /**
632
- * A SQL execution that only takes the input in the `sql` option, and do not accept query strings
633
- * directly.
634
- */
635
- class SqlExecutionWithOption extends SqlExecution {
636
- SqlExecutionWithOption ( ) {
637
- this = v1SpannerClient ( ) .getMember ( [ "executeSql" , "executeStreamingSql" ] ) .getACall ( )
638
- }
639
-
640
- override DataFlow:: Node getAQueryArgument ( ) { result = this .getOptionArgument ( 0 , "sql" ) }
641
- }
642
-
643
- /**
644
- * An expression that is interpreted as a SQL string.
645
- */
646
- class QueryString extends SQL:: SqlString {
647
- QueryString ( ) { this = any ( SqlExecution se ) .getAQueryArgument ( ) .asExpr ( ) }
648
- }
649
542
}
0 commit comments