@@ -376,9 +376,9 @@ module Pandas {
376376}
377377
378378module FileAndFormRemoteFlowSource {
379- class FastAPI extends DataFlow :: Node {
379+ class FastAPI extends RemoteFlowSource :: Range {
380380 FastAPI ( ) {
381- exists ( API:: Node fastApiParam |
381+ exists ( API:: Node fastApiParam , Expr fastApiUploadFile |
382382 fastApiParam =
383383 API:: moduleImport ( "fastapi" )
384384 .getMember ( "FastAPI" )
@@ -387,75 +387,72 @@ module FileAndFormRemoteFlowSource {
387387 .getReturn ( )
388388 .getParameter ( 0 )
389389 .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 ( )
396396 |
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
398400 exists ( For f , Attribute attr , DataFlow:: Node a , DataFlow:: Node b |
399401 fastApiParam .getAValueReachableFromSource ( ) .asExpr ( ) = f .getIter ( ) .getASubExpression * ( )
400402 |
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
409404 attr .getName ( ) = [ "filename" , "content_type" , "headers" , "file" , "read" ] and
410405 this .asExpr ( ) = attr
411406 )
412407 or
408+ // one Uploaded file as fastapi.UploadFile
413409 this =
414410 [
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 ( )
420417 ]
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 ( )
456418 ) and
457419 exists ( this .getLocation ( ) .getFile ( ) .getRelativePath ( ) )
458420 }
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" )
459456 }
460457}
461458
@@ -480,50 +477,6 @@ predicate isAdditionalTaintStepTextIOWrapper(DataFlow::Node nodeFrom, DataFlow::
480477 exists ( nodeTo .getLocation ( ) .getFile ( ) .getRelativePath ( ) )
481478}
482479
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-
527480module Bombs = TaintTracking:: Global< BombsConfig > ;
528481
529482import Bombs:: PathGraph
0 commit comments