@@ -376,9 +376,9 @@ module Pandas {
376
376
}
377
377
378
378
module FileAndFormRemoteFlowSource {
379
- class FastAPI extends DataFlow :: Node {
379
+ class FastAPI extends RemoteFlowSource :: Range {
380
380
FastAPI ( ) {
381
- exists ( API:: Node fastApiParam |
381
+ exists ( API:: Node fastApiParam , Expr fastApiUploadFile |
382
382
fastApiParam =
383
383
API:: moduleImport ( "fastapi" )
384
384
.getMember ( "FastAPI" )
@@ -387,75 +387,72 @@ module FileAndFormRemoteFlowSource {
387
387
.getReturn ( )
388
388
.getParameter ( 0 )
389
389
.getKeywordParameter ( _) and
390
- API :: moduleImport ( "fastapi" )
391
- . getMember ( "UploadFile ")
392
- . getASubclass * ( )
393
- . getAValueReachableFromSource ( )
394
- . asExpr ( ) =
395
- fastApiParam . asSource ( ) . asExpr ( ) . ( Parameter ) . getAnnotation ( ) . getASubExpression * ( )
390
+ fastApiUploadFile =
391
+ API :: moduleImport ( "fastapi ")
392
+ . getMember ( "UploadFile" )
393
+ . getASubclass * ( )
394
+ . getAValueReachableFromSource ( )
395
+ . asExpr ( )
396
396
|
397
- // in the case of List of files
397
+ fastApiUploadFile =
398
+ fastApiParam .asSource ( ) .asExpr ( ) .( Parameter ) .getAnnotation ( ) .getASubExpression * ( ) and
399
+ // Multiple Uploaded files as list of fastapi.UploadFile
398
400
exists ( For f , Attribute attr , DataFlow:: Node a , DataFlow:: Node b |
399
401
fastApiParam .getAValueReachableFromSource ( ) .asExpr ( ) = f .getIter ( ) .getASubExpression * ( )
400
402
|
401
- // file.file in following
402
- // def upload(files: List[UploadFile] = File(...)):
403
- // for file in files:
404
- // **file.file**
405
- // thanks Arthur Baars for helping me in following
406
- TaintTracking:: localTaint ( a , b ) and
407
- a .asExpr ( ) = f .getIter ( ) and
408
- b .asExpr ( ) = attr .getObject ( ) and
403
+ TaintTracking:: localExprTaint ( f .getIter ( ) , attr .getObject ( ) ) and
409
404
attr .getName ( ) = [ "filename" , "content_type" , "headers" , "file" , "read" ] and
410
405
this .asExpr ( ) = attr
411
406
)
412
407
or
408
+ // one Uploaded file as fastapi.UploadFile
413
409
this =
414
410
[
415
- fastApiParam .asSource ( ) ,
416
- fastApiParam .getMember ( [ "filename" , "content_type" , "headers" , "file" ] ) .asSource ( ) ,
417
- fastApiParam .getMember ( "read" ) .getReturn ( ) .asSource ( ) ,
418
- // file-like object, I'm trying to not do additional work here by using already existing file-like objs if it is possible
419
- // fastApiParam.getMember("file").getAMember().asSource(),
411
+ fastApiParam .getMember ( [ "filename" , "content_type" , "headers" ] ) .asSource ( ) ,
412
+ fastApiParam
413
+ .getMember ( "file" )
414
+ .getMember ( [ "readlines" , "readline" , "read" ] )
415
+ .getReturn ( )
416
+ .asSource ( ) , fastApiParam .getMember ( "read" ) .getReturn ( ) .asSource ( )
420
417
]
421
- )
422
- or
423
- exists ( API:: Node fastApiParam |
424
- fastApiParam =
425
- API:: moduleImport ( "fastapi" )
426
- .getMember ( "FastAPI" )
427
- .getReturn ( )
428
- .getMember ( "post" )
429
- .getReturn ( )
430
- .getParameter ( 0 )
431
- .getKeywordParameter ( _) and
432
- API:: moduleImport ( "fastapi" )
433
- .getMember ( "File" )
434
- .getASubclass * ( )
435
- .getAValueReachableFromSource ( )
436
- .asExpr ( ) =
437
- fastApiParam .asSource ( ) .asExpr ( ) .( Parameter ) .getAnnotation ( ) .getASubExpression * ( )
438
- |
439
- // in the case of List of files
440
- exists ( For f , Attribute attr , DataFlow:: Node a , DataFlow:: Node b |
441
- fastApiParam .getAValueReachableFromSource ( ) .asExpr ( ) = f .getIter ( ) .getASubExpression * ( )
442
- |
443
- // file.file in following
444
- // def upload(files: List[UploadFile] = File(...)):
445
- // for file in files:
446
- // **file.file**
447
- // thanks Arthur Baars for helping me in following
448
- TaintTracking:: localTaint ( a , b ) and
449
- a .asExpr ( ) = f .getIter ( ) and
450
- b .asExpr ( ) = attr .getObject ( ) and
451
- attr .getName ( ) = "file" and
452
- this .asExpr ( ) = attr
453
- )
454
- or
455
- this = fastApiParam .asSource ( )
456
418
) and
457
419
exists ( this .getLocation ( ) .getFile ( ) .getRelativePath ( ) )
458
420
}
421
+
422
+ override string getSourceType ( ) { result = "HTTP FORM" }
423
+ }
424
+ }
425
+
426
+ module BombsConfig implements DataFlow:: ConfigSig {
427
+ predicate isSource ( DataFlow:: Node source ) {
428
+ source instanceof RemoteFlowSource and
429
+ // or
430
+ // source instanceof FileAndFormRemoteFlowSource::FastAPI
431
+ exists ( source .getLocation ( ) .getFile ( ) .getRelativePath ( ) ) and
432
+ not source .getLocation ( ) .getFile ( ) .getRelativePath ( ) .matches ( "venv" )
433
+ }
434
+
435
+ predicate isSink ( DataFlow:: Node sink ) {
436
+ (
437
+ sink =
438
+ [
439
+ ZipFile:: isSink ( ) , Gzip:: isSink ( ) , Lzma:: isSink ( ) , Bz2:: isSink ( ) , TarFile:: isSink ( ) ,
440
+ Shutil:: isSink ( ) , Pandas:: isSink ( )
441
+ ] or
442
+ any ( )
443
+ ) and
444
+ exists ( sink .getLocation ( ) .getFile ( ) .getRelativePath ( ) ) and
445
+ not sink .getLocation ( ) .getFile ( ) .getRelativePath ( ) .matches ( "venv" )
446
+ }
447
+
448
+ predicate isAdditionalFlowStep ( DataFlow:: Node nodeFrom , DataFlow:: Node nodeTo ) {
449
+ (
450
+ isAdditionalTaintStepTextIOWrapper ( nodeFrom , nodeTo ) or
451
+ ZipFile:: isAdditionalTaintStep ( nodeFrom , nodeTo ) or
452
+ TarFile:: isAdditionalTaintStep ( nodeFrom , nodeTo )
453
+ ) and
454
+ exists ( nodeTo .getLocation ( ) .getFile ( ) .getRelativePath ( ) ) and
455
+ not nodeTo .getLocation ( ) .getFile ( ) .getRelativePath ( ) .matches ( "venv" )
459
456
}
460
457
}
461
458
@@ -480,50 +477,6 @@ predicate isAdditionalTaintStepTextIOWrapper(DataFlow::Node nodeFrom, DataFlow::
480
477
exists ( nodeTo .getLocation ( ) .getFile ( ) .getRelativePath ( ) )
481
478
}
482
479
483
- module BombsConfig implements DataFlow:: ConfigSig {
484
- // borrowed from UnsafeUnpackQuery.qll
485
- predicate isSource ( DataFlow:: Node source ) {
486
- source instanceof RemoteFlowSource
487
- or
488
- exists ( MethodCallNode args |
489
- args = source .( AttrRead ) .getObject ( ) .getALocalSource ( ) and
490
- args =
491
- [
492
- API:: moduleImport ( "argparse" )
493
- .getMember ( "ArgumentParser" )
494
- .getReturn ( )
495
- .getMember ( "parse_args" )
496
- .getACall ( ) , API:: moduleImport ( "os" ) .getMember ( "getenv" ) .getACall ( ) ,
497
- API:: moduleImport ( "os" ) .getMember ( "environ" ) .getMember ( "get" ) .getACall ( )
498
- ]
499
- )
500
- or
501
- source instanceof FileAndFormRemoteFlowSource:: FastAPI
502
- or
503
- source = TarFile:: tarfileInstance ( ) .getACall ( )
504
- or
505
- source = ZipFile:: zipFileClass ( ) .getACall ( )
506
- }
507
-
508
- predicate isSink ( DataFlow:: Node sink ) {
509
- sink =
510
- [
511
- ZipFile:: isSink ( ) , Gzip:: isSink ( ) , Lzma:: isSink ( ) , Bz2:: isSink ( ) , TarFile:: isSink ( ) ,
512
- Shutil:: isSink ( ) , Pandas:: isSink ( )
513
- ] and
514
- exists ( sink .getLocation ( ) .getFile ( ) .getRelativePath ( ) )
515
- }
516
-
517
- predicate isAdditionalFlowStep ( DataFlow:: Node nodeFrom , DataFlow:: Node nodeTo ) {
518
- (
519
- isAdditionalTaintStepTextIOWrapper ( nodeFrom , nodeTo ) or
520
- ZipFile:: isAdditionalTaintStep ( nodeFrom , nodeTo ) or
521
- TarFile:: isAdditionalTaintStep ( nodeFrom , nodeTo )
522
- ) and
523
- exists ( nodeTo .getLocation ( ) .getFile ( ) .getRelativePath ( ) )
524
- }
525
- }
526
-
527
480
module Bombs = TaintTracking:: Global< BombsConfig > ;
528
481
529
482
import Bombs:: PathGraph
0 commit comments