circle-ir 3.1.1 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/configs/sinks/code_injection.yaml +136 -0
- package/configs/sinks/command.yaml +109 -0
- package/configs/sinks/path.yaml +113 -0
- package/configs/sources/http_sources.yaml +151 -0
- package/dist/analysis/index.d.ts +2 -5
- package/dist/analysis/index.js +2 -6
- package/dist/analysis/index.js.map +1 -1
- package/dist/analysis/taint-matcher.js +37 -1
- package/dist/analysis/taint-matcher.js.map +1 -1
- package/dist/analyzer.js +64 -1
- package/dist/analyzer.js.map +1 -1
- package/dist/browser/circle-ir.js +97 -95
- package/dist/core/circle-ir-core.cjs +17 -1
- package/dist/core/circle-ir-core.js +17 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/utils/logger.d.ts +28 -40
- package/dist/utils/logger.js +64 -137
- package/dist/utils/logger.js.map +1 -1
- package/package.json +3 -5
- package/dist/analysis/advisory-db.d.ts +0 -86
- package/dist/analysis/advisory-db.js +0 -104
- package/dist/analysis/advisory-db.js.map +0 -1
- package/dist/analysis/cargo-parser.d.ts +0 -42
- package/dist/analysis/cargo-parser.js +0 -102
- package/dist/analysis/cargo-parser.js.map +0 -1
- package/dist/analysis/dependency-scanner.d.ts +0 -79
- package/dist/analysis/dependency-scanner.js +0 -122
- package/dist/analysis/dependency-scanner.js.map +0 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ A high-performance Static Application Security Testing (SAST) library for detect
|
|
|
6
6
|
|
|
7
7
|
- **Taint Analysis**: Track data flow from sources (user input) to sinks (dangerous operations)
|
|
8
8
|
- **Multi-language Support**: Java, JavaScript/TypeScript, Python, Rust
|
|
9
|
-
- **High Accuracy**: 100% on OWASP Benchmark, 100% on Juliet Test Suite,
|
|
9
|
+
- **High Accuracy**: 100% on OWASP Benchmark, 100% on Juliet Test Suite, 97.7% TPR on SecuriBench Micro
|
|
10
10
|
- **Universal**: Works in Node.js, browsers, and Cloudflare Workers
|
|
11
11
|
- **Zero External Dependencies**: Core analysis runs without network calls or external services
|
|
12
12
|
- **Browser Compatible**: Tree-sitter WASM for universal parsing
|
|
@@ -187,7 +187,7 @@ sources:
|
|
|
187
187
|
|-----------|-------|---------|
|
|
188
188
|
| **OWASP Benchmark** | +100% | TPR 100%, FPR 0% (1415 test cases) |
|
|
189
189
|
| **Juliet Test Suite** | +100% | 156/156 test cases, 9 CWEs |
|
|
190
|
-
| **SecuriBench Micro** |
|
|
190
|
+
| **SecuriBench Micro** | 97.7% TPR | 105/108 vulns detected, 6.7% FPR |
|
|
191
191
|
| **CWE-Bench-Java** | 65.5% | 509/777 real-world CVEs |
|
|
192
192
|
|
|
193
193
|
## Documentation
|
|
@@ -621,6 +621,142 @@
|
|
|
621
621
|
"severity": "critical",
|
|
622
622
|
"arg_positions": [0],
|
|
623
623
|
"note": "Groovy class compilation from string"
|
|
624
|
+
},
|
|
625
|
+
{
|
|
626
|
+
"method": "interpolate",
|
|
627
|
+
"class": "StringSubstitutor",
|
|
628
|
+
"type": "code_injection",
|
|
629
|
+
"cwe": "CWE-094",
|
|
630
|
+
"severity": "critical",
|
|
631
|
+
"arg_positions": [0],
|
|
632
|
+
"note": "Apache Commons Text interpolation - CVE-2022-42889 (script:, dns:, url: lookups)"
|
|
633
|
+
},
|
|
634
|
+
{
|
|
635
|
+
"method": "replace",
|
|
636
|
+
"class": "StringSubstitutor",
|
|
637
|
+
"type": "code_injection",
|
|
638
|
+
"cwe": "CWE-094",
|
|
639
|
+
"severity": "critical",
|
|
640
|
+
"arg_positions": [0],
|
|
641
|
+
"note": "Apache Commons Text substitution with lookup"
|
|
642
|
+
},
|
|
643
|
+
{
|
|
644
|
+
"method": "interpolate",
|
|
645
|
+
"class": "StringLookupFactory",
|
|
646
|
+
"type": "code_injection",
|
|
647
|
+
"cwe": "CWE-094",
|
|
648
|
+
"severity": "critical",
|
|
649
|
+
"arg_positions": [0],
|
|
650
|
+
"note": "Apache Commons Text lookup interpolation"
|
|
651
|
+
},
|
|
652
|
+
{
|
|
653
|
+
"method": "getConnection",
|
|
654
|
+
"class": "DriverManager",
|
|
655
|
+
"type": "code_injection",
|
|
656
|
+
"cwe": "CWE-094",
|
|
657
|
+
"severity": "high",
|
|
658
|
+
"arg_positions": [0],
|
|
659
|
+
"note": "JDBC URL injection - can trigger JNDI/RCE via malicious JDBC URLs"
|
|
660
|
+
},
|
|
661
|
+
{
|
|
662
|
+
"method": "createConnection",
|
|
663
|
+
"type": "code_injection",
|
|
664
|
+
"cwe": "CWE-094",
|
|
665
|
+
"severity": "high",
|
|
666
|
+
"arg_positions": [0],
|
|
667
|
+
"note": "Database connection creation with attacker-controlled URL"
|
|
668
|
+
},
|
|
669
|
+
{
|
|
670
|
+
"method": "invoke",
|
|
671
|
+
"class": "RpcInvocation",
|
|
672
|
+
"type": "code_injection",
|
|
673
|
+
"cwe": "CWE-094",
|
|
674
|
+
"severity": "critical",
|
|
675
|
+
"note": "Dubbo RPC invocation - may execute arbitrary code"
|
|
676
|
+
},
|
|
677
|
+
{
|
|
678
|
+
"method": "decode",
|
|
679
|
+
"class": "DecodeableRpcInvocation",
|
|
680
|
+
"type": "code_injection",
|
|
681
|
+
"cwe": "CWE-094",
|
|
682
|
+
"severity": "critical",
|
|
683
|
+
"note": "Dubbo RPC deserialization"
|
|
684
|
+
},
|
|
685
|
+
{
|
|
686
|
+
"method": "refer",
|
|
687
|
+
"class": "RegistryProtocol",
|
|
688
|
+
"type": "code_injection",
|
|
689
|
+
"cwe": "CWE-094",
|
|
690
|
+
"severity": "high",
|
|
691
|
+
"note": "Dubbo registry protocol reference"
|
|
692
|
+
},
|
|
693
|
+
{
|
|
694
|
+
"method": "executeScript",
|
|
695
|
+
"class": "ScriptingComponentHelper",
|
|
696
|
+
"type": "code_injection",
|
|
697
|
+
"cwe": "CWE-094",
|
|
698
|
+
"severity": "critical",
|
|
699
|
+
"arg_positions": [0],
|
|
700
|
+
"note": "Apache NiFi script execution"
|
|
701
|
+
},
|
|
702
|
+
{
|
|
703
|
+
"method": "onTrigger",
|
|
704
|
+
"class": "ExecuteScript",
|
|
705
|
+
"type": "code_injection",
|
|
706
|
+
"cwe": "CWE-094",
|
|
707
|
+
"severity": "critical",
|
|
708
|
+
"note": "Apache NiFi ExecuteScript processor"
|
|
709
|
+
},
|
|
710
|
+
{
|
|
711
|
+
"method": "parse",
|
|
712
|
+
"class": "CronDefinition",
|
|
713
|
+
"type": "code_injection",
|
|
714
|
+
"cwe": "CWE-094",
|
|
715
|
+
"severity": "high",
|
|
716
|
+
"arg_positions": [0],
|
|
717
|
+
"note": "Cron expression parsing - potential injection"
|
|
718
|
+
},
|
|
719
|
+
{
|
|
720
|
+
"method": "parse",
|
|
721
|
+
"class": "CronParser",
|
|
722
|
+
"type": "code_injection",
|
|
723
|
+
"cwe": "CWE-094",
|
|
724
|
+
"severity": "high",
|
|
725
|
+
"arg_positions": [0],
|
|
726
|
+
"note": "Cron expression parsing"
|
|
727
|
+
},
|
|
728
|
+
{
|
|
729
|
+
"method": "check",
|
|
730
|
+
"class": "PermitAllPermissionEvaluator",
|
|
731
|
+
"type": "code_injection",
|
|
732
|
+
"cwe": "CWE-094",
|
|
733
|
+
"severity": "high",
|
|
734
|
+
"note": "Spring Security expression evaluation bypass"
|
|
735
|
+
},
|
|
736
|
+
{
|
|
737
|
+
"method": "evaluate",
|
|
738
|
+
"class": "SpelExpressionParser",
|
|
739
|
+
"type": "code_injection",
|
|
740
|
+
"cwe": "CWE-094",
|
|
741
|
+
"severity": "critical",
|
|
742
|
+
"arg_positions": [0],
|
|
743
|
+
"note": "SpEL direct evaluation"
|
|
744
|
+
},
|
|
745
|
+
{
|
|
746
|
+
"method": "setPropertyValues",
|
|
747
|
+
"class": "DataBinder",
|
|
748
|
+
"type": "code_injection",
|
|
749
|
+
"cwe": "CWE-094",
|
|
750
|
+
"severity": "high",
|
|
751
|
+
"note": "Spring DataBinder property binding - Spring4Shell"
|
|
752
|
+
},
|
|
753
|
+
{
|
|
754
|
+
"method": "bind",
|
|
755
|
+
"class": "DataBinder",
|
|
756
|
+
"type": "code_injection",
|
|
757
|
+
"cwe": "CWE-094",
|
|
758
|
+
"severity": "high",
|
|
759
|
+
"note": "Spring DataBinder bind - Spring4Shell"
|
|
624
760
|
}
|
|
625
761
|
],
|
|
626
762
|
"sanitizers": [
|
|
@@ -869,6 +869,115 @@
|
|
|
869
869
|
"severity": "critical",
|
|
870
870
|
"arg_positions": [0],
|
|
871
871
|
"note": "Shell command execution"
|
|
872
|
+
},
|
|
873
|
+
{
|
|
874
|
+
"method": "cmds",
|
|
875
|
+
"class": "ProcStarter",
|
|
876
|
+
"type": "command_injection",
|
|
877
|
+
"cwe": "CWE-078",
|
|
878
|
+
"severity": "critical",
|
|
879
|
+
"arg_positions": [0],
|
|
880
|
+
"note": "Jenkins Launcher.ProcStarter command list"
|
|
881
|
+
},
|
|
882
|
+
{
|
|
883
|
+
"method": "launch",
|
|
884
|
+
"class": "Launcher",
|
|
885
|
+
"type": "command_injection",
|
|
886
|
+
"cwe": "CWE-078",
|
|
887
|
+
"severity": "critical",
|
|
888
|
+
"note": "Jenkins Launcher.launch() - process execution"
|
|
889
|
+
},
|
|
890
|
+
{
|
|
891
|
+
"method": "launch",
|
|
892
|
+
"class": "ProcStarter",
|
|
893
|
+
"type": "command_injection",
|
|
894
|
+
"cwe": "CWE-078",
|
|
895
|
+
"severity": "critical",
|
|
896
|
+
"note": "Jenkins ProcStarter.launch() - process execution"
|
|
897
|
+
},
|
|
898
|
+
{
|
|
899
|
+
"method": "start",
|
|
900
|
+
"class": "ProcStarter",
|
|
901
|
+
"type": "command_injection",
|
|
902
|
+
"cwe": "CWE-078",
|
|
903
|
+
"severity": "critical",
|
|
904
|
+
"note": "Jenkins ProcStarter.start() - process execution"
|
|
905
|
+
},
|
|
906
|
+
{
|
|
907
|
+
"method": "launchChannel",
|
|
908
|
+
"class": "Launcher",
|
|
909
|
+
"type": "command_injection",
|
|
910
|
+
"cwe": "CWE-078",
|
|
911
|
+
"severity": "critical",
|
|
912
|
+
"arg_positions": [0],
|
|
913
|
+
"note": "Jenkins Launcher channel creation with command"
|
|
914
|
+
},
|
|
915
|
+
{
|
|
916
|
+
"method": "subcommand",
|
|
917
|
+
"type": "command_injection",
|
|
918
|
+
"cwe": "CWE-078",
|
|
919
|
+
"severity": "high",
|
|
920
|
+
"arg_positions": [0],
|
|
921
|
+
"note": "Git CLI subcommand construction"
|
|
922
|
+
},
|
|
923
|
+
{
|
|
924
|
+
"method": "launchCommandIn",
|
|
925
|
+
"type": "command_injection",
|
|
926
|
+
"cwe": "CWE-078",
|
|
927
|
+
"severity": "critical",
|
|
928
|
+
"arg_positions": [0],
|
|
929
|
+
"note": "Jenkins Git plugin command launch"
|
|
930
|
+
},
|
|
931
|
+
{
|
|
932
|
+
"method": "fetch",
|
|
933
|
+
"class": "CliGitAPIImpl",
|
|
934
|
+
"type": "command_injection",
|
|
935
|
+
"cwe": "CWE-078",
|
|
936
|
+
"severity": "high",
|
|
937
|
+
"note": "Jenkins Git plugin fetch - may inject via refspec"
|
|
938
|
+
},
|
|
939
|
+
{
|
|
940
|
+
"method": "checkout",
|
|
941
|
+
"class": "CliGitAPIImpl",
|
|
942
|
+
"type": "command_injection",
|
|
943
|
+
"cwe": "CWE-078",
|
|
944
|
+
"severity": "high",
|
|
945
|
+
"note": "Jenkins Git plugin checkout - may inject via branch name"
|
|
946
|
+
},
|
|
947
|
+
{
|
|
948
|
+
"method": "submoduleUpdate",
|
|
949
|
+
"class": "CliGitAPIImpl",
|
|
950
|
+
"type": "command_injection",
|
|
951
|
+
"cwe": "CWE-078",
|
|
952
|
+
"severity": "high",
|
|
953
|
+
"note": "Jenkins Git plugin submodule update - CVE injection vector"
|
|
954
|
+
},
|
|
955
|
+
{
|
|
956
|
+
"method": "interpolate",
|
|
957
|
+
"class": "StringSubstitutor",
|
|
958
|
+
"type": "command_injection",
|
|
959
|
+
"cwe": "CWE-078",
|
|
960
|
+
"severity": "critical",
|
|
961
|
+
"arg_positions": [0],
|
|
962
|
+
"note": "Apache Commons Text string interpolation - CVE-2022-42889"
|
|
963
|
+
},
|
|
964
|
+
{
|
|
965
|
+
"method": "replace",
|
|
966
|
+
"class": "StringSubstitutor",
|
|
967
|
+
"type": "command_injection",
|
|
968
|
+
"cwe": "CWE-078",
|
|
969
|
+
"severity": "critical",
|
|
970
|
+
"arg_positions": [0],
|
|
971
|
+
"note": "Apache Commons Text string substitution"
|
|
972
|
+
},
|
|
973
|
+
{
|
|
974
|
+
"method": "getConnection",
|
|
975
|
+
"class": "DriverManager",
|
|
976
|
+
"type": "command_injection",
|
|
977
|
+
"cwe": "CWE-078",
|
|
978
|
+
"severity": "high",
|
|
979
|
+
"arg_positions": [0],
|
|
980
|
+
"note": "JDBC connection with attacker-controlled URL can lead to RCE"
|
|
872
981
|
}
|
|
873
982
|
],
|
|
874
983
|
"sanitizers": [
|
package/configs/sinks/path.yaml
CHANGED
|
@@ -684,6 +684,119 @@
|
|
|
684
684
|
"cwe": "CWE-022",
|
|
685
685
|
"severity": "high",
|
|
686
686
|
"note": "Jenkins FilePath recursive delete"
|
|
687
|
+
},
|
|
688
|
+
{
|
|
689
|
+
"method": "createRelative",
|
|
690
|
+
"class": "Resource",
|
|
691
|
+
"type": "path_traversal",
|
|
692
|
+
"cwe": "CWE-022",
|
|
693
|
+
"severity": "high",
|
|
694
|
+
"arg_positions": [0],
|
|
695
|
+
"note": "Spring Resource.createRelative() - path traversal via relative path"
|
|
696
|
+
},
|
|
697
|
+
{
|
|
698
|
+
"method": "createRelative",
|
|
699
|
+
"type": "path_traversal",
|
|
700
|
+
"cwe": "CWE-022",
|
|
701
|
+
"severity": "high",
|
|
702
|
+
"arg_positions": [0],
|
|
703
|
+
"note": "Resource createRelative without class qualifier"
|
|
704
|
+
},
|
|
705
|
+
{
|
|
706
|
+
"method": "sendFile",
|
|
707
|
+
"type": "path_traversal",
|
|
708
|
+
"cwe": "CWE-022",
|
|
709
|
+
"severity": "high",
|
|
710
|
+
"arg_positions": [0],
|
|
711
|
+
"note": "Vert.x/HTTP file sending - path traversal"
|
|
712
|
+
},
|
|
713
|
+
{
|
|
714
|
+
"method": "sendStatic",
|
|
715
|
+
"type": "path_traversal",
|
|
716
|
+
"cwe": "CWE-022",
|
|
717
|
+
"severity": "high",
|
|
718
|
+
"arg_positions": [0],
|
|
719
|
+
"note": "Static file serving - path traversal"
|
|
720
|
+
},
|
|
721
|
+
{
|
|
722
|
+
"method": "handle",
|
|
723
|
+
"class": "StaticHandler",
|
|
724
|
+
"type": "path_traversal",
|
|
725
|
+
"cwe": "CWE-022",
|
|
726
|
+
"severity": "high",
|
|
727
|
+
"note": "Vert.x static file handler"
|
|
728
|
+
},
|
|
729
|
+
{
|
|
730
|
+
"method": "handle",
|
|
731
|
+
"class": "StaticHandlerImpl",
|
|
732
|
+
"type": "path_traversal",
|
|
733
|
+
"cwe": "CWE-022",
|
|
734
|
+
"severity": "high",
|
|
735
|
+
"note": "Vert.x static file handler implementation"
|
|
736
|
+
},
|
|
737
|
+
{
|
|
738
|
+
"method": "getFile",
|
|
739
|
+
"type": "path_traversal",
|
|
740
|
+
"cwe": "CWE-022",
|
|
741
|
+
"severity": "high",
|
|
742
|
+
"arg_positions": [0],
|
|
743
|
+
"note": "Generic getFile with user input"
|
|
744
|
+
},
|
|
745
|
+
{
|
|
746
|
+
"method": "extractEntry",
|
|
747
|
+
"type": "path_traversal",
|
|
748
|
+
"cwe": "CWE-022",
|
|
749
|
+
"severity": "high",
|
|
750
|
+
"arg_positions": [0],
|
|
751
|
+
"note": "Archive entry extraction - zip slip"
|
|
752
|
+
},
|
|
753
|
+
{
|
|
754
|
+
"method": "extractAll",
|
|
755
|
+
"type": "path_traversal",
|
|
756
|
+
"cwe": "CWE-022",
|
|
757
|
+
"severity": "high",
|
|
758
|
+
"arg_positions": [0],
|
|
759
|
+
"note": "Archive extraction - zip slip"
|
|
760
|
+
},
|
|
761
|
+
{
|
|
762
|
+
"method": "unzip",
|
|
763
|
+
"type": "path_traversal",
|
|
764
|
+
"cwe": "CWE-022",
|
|
765
|
+
"severity": "high",
|
|
766
|
+
"arg_positions": [0],
|
|
767
|
+
"note": "Unzip operation - zip slip"
|
|
768
|
+
},
|
|
769
|
+
{
|
|
770
|
+
"method": "getPath",
|
|
771
|
+
"class": "ZipEntry",
|
|
772
|
+
"type": "path_traversal",
|
|
773
|
+
"cwe": "CWE-022",
|
|
774
|
+
"severity": "high",
|
|
775
|
+
"note": "Zip entry path - may contain ../"
|
|
776
|
+
},
|
|
777
|
+
{
|
|
778
|
+
"method": "getName",
|
|
779
|
+
"class": "ZipEntry",
|
|
780
|
+
"type": "path_traversal",
|
|
781
|
+
"cwe": "CWE-022",
|
|
782
|
+
"severity": "high",
|
|
783
|
+
"note": "Zip entry name - may contain ../"
|
|
784
|
+
},
|
|
785
|
+
{
|
|
786
|
+
"method": "getEnvironment",
|
|
787
|
+
"class": "ConfigServicePropertySourceLocator",
|
|
788
|
+
"type": "path_traversal",
|
|
789
|
+
"cwe": "CWE-022",
|
|
790
|
+
"severity": "high",
|
|
791
|
+
"note": "Spring Cloud Config path traversal"
|
|
792
|
+
},
|
|
793
|
+
{
|
|
794
|
+
"method": "findOne",
|
|
795
|
+
"class": "GenericResourceRepository",
|
|
796
|
+
"type": "path_traversal",
|
|
797
|
+
"cwe": "CWE-022",
|
|
798
|
+
"severity": "high",
|
|
799
|
+
"note": "Spring Cloud Config resource repository"
|
|
687
800
|
}
|
|
688
801
|
],
|
|
689
802
|
"sanitizers": [
|
|
@@ -374,6 +374,157 @@
|
|
|
374
374
|
"severity": "high",
|
|
375
375
|
"return_tainted": true,
|
|
376
376
|
"note": "Model object getter - may contain HTTP request data"
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
"method": "getParameter",
|
|
380
|
+
"class": "StaplerRequest",
|
|
381
|
+
"type": "http_param",
|
|
382
|
+
"severity": "high",
|
|
383
|
+
"return_tainted": true,
|
|
384
|
+
"note": "Jenkins StaplerRequest parameter - attacker-controlled"
|
|
385
|
+
},
|
|
386
|
+
{
|
|
387
|
+
"method": "getSubmittedForm",
|
|
388
|
+
"class": "StaplerRequest",
|
|
389
|
+
"type": "http_body",
|
|
390
|
+
"severity": "high",
|
|
391
|
+
"return_tainted": true,
|
|
392
|
+
"note": "Jenkins StaplerRequest form submission"
|
|
393
|
+
},
|
|
394
|
+
{
|
|
395
|
+
"method": "bindJSON",
|
|
396
|
+
"class": "StaplerRequest",
|
|
397
|
+
"type": "http_body",
|
|
398
|
+
"severity": "high",
|
|
399
|
+
"return_tainted": true,
|
|
400
|
+
"note": "Jenkins StaplerRequest JSON binding"
|
|
401
|
+
},
|
|
402
|
+
{
|
|
403
|
+
"method": "getRequestURI",
|
|
404
|
+
"class": "StaplerRequest",
|
|
405
|
+
"type": "http_path",
|
|
406
|
+
"severity": "high",
|
|
407
|
+
"return_tainted": true,
|
|
408
|
+
"note": "Jenkins StaplerRequest URI"
|
|
409
|
+
},
|
|
410
|
+
{
|
|
411
|
+
"method": "getRestOfPath",
|
|
412
|
+
"class": "StaplerRequest",
|
|
413
|
+
"type": "http_path",
|
|
414
|
+
"severity": "high",
|
|
415
|
+
"return_tainted": true,
|
|
416
|
+
"note": "Jenkins StaplerRequest rest of path"
|
|
417
|
+
},
|
|
418
|
+
{
|
|
419
|
+
"method": "getPathParameter",
|
|
420
|
+
"class": "HandlerRequest",
|
|
421
|
+
"type": "http_param",
|
|
422
|
+
"severity": "high",
|
|
423
|
+
"return_tainted": true,
|
|
424
|
+
"note": "Apache Flink HandlerRequest path parameter"
|
|
425
|
+
},
|
|
426
|
+
{
|
|
427
|
+
"method": "getQueryParameter",
|
|
428
|
+
"class": "HandlerRequest",
|
|
429
|
+
"type": "http_param",
|
|
430
|
+
"severity": "high",
|
|
431
|
+
"return_tainted": true,
|
|
432
|
+
"note": "Apache Flink HandlerRequest query parameter"
|
|
433
|
+
},
|
|
434
|
+
{
|
|
435
|
+
"method": "getRequestBody",
|
|
436
|
+
"class": "HandlerRequest",
|
|
437
|
+
"type": "http_body",
|
|
438
|
+
"severity": "high",
|
|
439
|
+
"return_tainted": true,
|
|
440
|
+
"note": "Apache Flink HandlerRequest body"
|
|
441
|
+
},
|
|
442
|
+
{
|
|
443
|
+
"method": "path",
|
|
444
|
+
"class": "HttpServerRequest",
|
|
445
|
+
"type": "http_path",
|
|
446
|
+
"severity": "high",
|
|
447
|
+
"return_tainted": true,
|
|
448
|
+
"note": "Vert.x HTTP request path"
|
|
449
|
+
},
|
|
450
|
+
{
|
|
451
|
+
"method": "getParam",
|
|
452
|
+
"class": "HttpServerRequest",
|
|
453
|
+
"type": "http_param",
|
|
454
|
+
"severity": "high",
|
|
455
|
+
"return_tainted": true,
|
|
456
|
+
"note": "Vert.x HTTP request parameter"
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
"method": "getHeader",
|
|
460
|
+
"class": "HttpServerRequest",
|
|
461
|
+
"type": "http_header",
|
|
462
|
+
"severity": "high",
|
|
463
|
+
"return_tainted": true,
|
|
464
|
+
"note": "Vert.x HTTP request header"
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
"method": "request",
|
|
468
|
+
"class": "RoutingContext",
|
|
469
|
+
"type": "http_param",
|
|
470
|
+
"severity": "high",
|
|
471
|
+
"return_tainted": true,
|
|
472
|
+
"note": "Vert.x RoutingContext request access"
|
|
473
|
+
},
|
|
474
|
+
{
|
|
475
|
+
"method": "pathParam",
|
|
476
|
+
"class": "RoutingContext",
|
|
477
|
+
"type": "http_path",
|
|
478
|
+
"severity": "high",
|
|
479
|
+
"return_tainted": true,
|
|
480
|
+
"note": "Vert.x RoutingContext path parameter"
|
|
481
|
+
},
|
|
482
|
+
{
|
|
483
|
+
"method": "queryParam",
|
|
484
|
+
"class": "RoutingContext",
|
|
485
|
+
"type": "http_param",
|
|
486
|
+
"severity": "high",
|
|
487
|
+
"return_tainted": true,
|
|
488
|
+
"note": "Vert.x RoutingContext query parameter"
|
|
489
|
+
},
|
|
490
|
+
{
|
|
491
|
+
"method": "getBodyAsString",
|
|
492
|
+
"class": "RoutingContext",
|
|
493
|
+
"type": "http_body",
|
|
494
|
+
"severity": "high",
|
|
495
|
+
"return_tainted": true,
|
|
496
|
+
"note": "Vert.x RoutingContext body"
|
|
497
|
+
},
|
|
498
|
+
{
|
|
499
|
+
"method": "normalisedPath",
|
|
500
|
+
"class": "RoutingContext",
|
|
501
|
+
"type": "http_path",
|
|
502
|
+
"severity": "high",
|
|
503
|
+
"return_tainted": true,
|
|
504
|
+
"note": "Vert.x RoutingContext normalized path"
|
|
505
|
+
},
|
|
506
|
+
{
|
|
507
|
+
"method": "getRemoteEnvironment",
|
|
508
|
+
"type": "http_param",
|
|
509
|
+
"severity": "high",
|
|
510
|
+
"return_tainted": true,
|
|
511
|
+
"note": "Spring Cloud Config remote environment fetch"
|
|
512
|
+
},
|
|
513
|
+
{
|
|
514
|
+
"method": "getHeader",
|
|
515
|
+
"class": "ServerWebExchange",
|
|
516
|
+
"type": "http_header",
|
|
517
|
+
"severity": "high",
|
|
518
|
+
"return_tainted": true,
|
|
519
|
+
"note": "Spring WebFlux exchange header"
|
|
520
|
+
},
|
|
521
|
+
{
|
|
522
|
+
"method": "getExchange",
|
|
523
|
+
"class": "GatewayFilter",
|
|
524
|
+
"type": "http_param",
|
|
525
|
+
"severity": "high",
|
|
526
|
+
"return_tainted": true,
|
|
527
|
+
"note": "Spring Cloud Gateway exchange"
|
|
377
528
|
}
|
|
378
529
|
]
|
|
379
530
|
}
|
package/dist/analysis/index.d.ts
CHANGED
|
@@ -2,15 +2,12 @@
|
|
|
2
2
|
* Analysis module index
|
|
3
3
|
*/
|
|
4
4
|
export { parseConfig, loadSourceConfigs, loadSinkConfigs, createTaintConfig, getDefaultConfig, DEFAULT_SOURCES, DEFAULT_SINKS, DEFAULT_SANITIZERS, } from './config-loader.js';
|
|
5
|
-
export { analyzeTaint,
|
|
5
|
+
export { analyzeTaint, } from './taint-matcher.js';
|
|
6
6
|
export { detectUnresolved, } from './unresolved.js';
|
|
7
7
|
export { generateFindings, } from './findings.js';
|
|
8
8
|
export { propagateTaint, type TaintPropagationResult, type TaintedVariable, type TaintFlow, } from './taint-propagation.js';
|
|
9
9
|
export { analyzeInterprocedural, getInterproceduralSummary, findTaintBridges, getMethodTaintPaths, hasMethod, getMethod, isMethodTainted, type InterproceduralResult, type MethodNode, type CallEdge, } from './interprocedural.js';
|
|
10
10
|
export { analyzeConstantPropagation, isFalsePositive, isCorrelatedPredicateFP, ConstantPropagator, isKnown, createUnknown, createConstant, getNodeText, getNodeLine, type ConstantValue, type ConstantType, type ConstantPropagatorResult, type ConstantPropagationOptions, } from './constant-propagation.js';
|
|
11
11
|
export { PathFinder, findTaintPaths, formatTaintPath, type TaintHop, type TaintPath, type PathFinderResult, type PathFinderConfig, } from './path-finder.js';
|
|
12
|
-
export { DFGVerifier, verifyTaintFlow,
|
|
13
|
-
export { loadBundledAdvisories, parseAdvisoryJson, categoryToSeverity, getAdvisoriesForCrate, findAdvisoryByCve, getVulnerableCrates, type AdvisoryVulnerability, type AdvisoryDatabase, } from './advisory-db.js';
|
|
14
|
-
export { parseCargoLock, parseCargoToml, filterRegistryDeps, type CargoLock, type CargoLockDependency, type CargoToml, type CargoTomlDependency, } from './cargo-parser.js';
|
|
15
|
-
export { scanCargoLock, checkCrateVulnerability, formatFinding, formatScanReport, type DependencyFinding, type ScanOptions, type ScanResult, } from './dependency-scanner.js';
|
|
12
|
+
export { DFGVerifier, verifyTaintFlow, type VerificationResult, type VerificationPath, type VerificationStep, type VerifierConfig, } from './dfg-verifier.js';
|
|
16
13
|
export { parseVersion, compareVersions, semverSatisfies, isVersionVulnerable, type ParsedVersion, } from './semver.js';
|
package/dist/analysis/index.js
CHANGED
|
@@ -2,17 +2,13 @@
|
|
|
2
2
|
* Analysis module index
|
|
3
3
|
*/
|
|
4
4
|
export { parseConfig, loadSourceConfigs, loadSinkConfigs, createTaintConfig, getDefaultConfig, DEFAULT_SOURCES, DEFAULT_SINKS, DEFAULT_SANITIZERS, } from './config-loader.js';
|
|
5
|
-
export { analyzeTaint,
|
|
5
|
+
export { analyzeTaint, } from './taint-matcher.js';
|
|
6
6
|
export { detectUnresolved, } from './unresolved.js';
|
|
7
7
|
export { generateFindings, } from './findings.js';
|
|
8
8
|
export { propagateTaint, } from './taint-propagation.js';
|
|
9
9
|
export { analyzeInterprocedural, getInterproceduralSummary, findTaintBridges, getMethodTaintPaths, hasMethod, getMethod, isMethodTainted, } from './interprocedural.js';
|
|
10
10
|
export { analyzeConstantPropagation, isFalsePositive, isCorrelatedPredicateFP, ConstantPropagator, isKnown, createUnknown, createConstant, getNodeText, getNodeLine, } from './constant-propagation.js';
|
|
11
11
|
export { PathFinder, findTaintPaths, formatTaintPath, } from './path-finder.js';
|
|
12
|
-
export { DFGVerifier, verifyTaintFlow,
|
|
13
|
-
// RustSec Advisory Database
|
|
14
|
-
export { loadBundledAdvisories, parseAdvisoryJson, categoryToSeverity, getAdvisoriesForCrate, findAdvisoryByCve, getVulnerableCrates, } from './advisory-db.js';
|
|
15
|
-
export { parseCargoLock, parseCargoToml, filterRegistryDeps, } from './cargo-parser.js';
|
|
16
|
-
export { scanCargoLock, checkCrateVulnerability, formatFinding, formatScanReport, } from './dependency-scanner.js';
|
|
12
|
+
export { DFGVerifier, verifyTaintFlow, } from './dfg-verifier.js';
|
|
17
13
|
export { parseVersion, compareVersions, semverSatisfies, isVersionVulnerable, } from './semver.js';
|
|
18
14
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/analysis/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,kBAAkB,GACnB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,YAAY,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/analysis/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,kBAAkB,GACnB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,YAAY,GACb,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,gBAAgB,GACjB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,gBAAgB,GACjB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,cAAc,GAIf,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,sBAAsB,EACtB,yBAAyB,EACzB,gBAAgB,EAChB,mBAAmB,EACnB,SAAS,EACT,SAAS,EACT,eAAe,GAIhB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,0BAA0B,EAC1B,eAAe,EACf,uBAAuB,EACvB,kBAAkB,EAClB,OAAO,EACP,aAAa,EACb,cAAc,EACd,WAAW,EACX,WAAW,GAKZ,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EACL,UAAU,EACV,cAAc,EACd,eAAe,GAKhB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,WAAW,EACX,eAAe,GAKhB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,YAAY,EACZ,eAAe,EACf,eAAe,EACf,mBAAmB,GAEpB,MAAM,aAAa,CAAC"}
|
|
@@ -62,7 +62,7 @@ function findSources(calls, types, patterns) {
|
|
|
62
62
|
if (method.modifiers.includes('private'))
|
|
63
63
|
continue;
|
|
64
64
|
// Skip standard methods that are unlikely to receive tainted data
|
|
65
|
-
const skipMethods = ['toString', 'hashCode', 'equals', 'compareTo'
|
|
65
|
+
const skipMethods = ['toString', 'hashCode', 'equals', 'compareTo'];
|
|
66
66
|
if (skipMethods.includes(method.name))
|
|
67
67
|
continue;
|
|
68
68
|
for (const param of method.parameters) {
|
|
@@ -179,6 +179,38 @@ function isInterproceduralTaintableType(typeName) {
|
|
|
179
179
|
}
|
|
180
180
|
return false;
|
|
181
181
|
}
|
|
182
|
+
/**
|
|
183
|
+
* Check if a SQL query call uses parameterized query pattern.
|
|
184
|
+
* Parameterized queries (e.g., db.query("SELECT ? ...", [param])) are safe
|
|
185
|
+
* because user input is passed as bound parameters, not concatenated into the query.
|
|
186
|
+
*
|
|
187
|
+
* Recognized patterns:
|
|
188
|
+
* - db.query(sql, [params], callback) — Node.js mysql/pg
|
|
189
|
+
* - db.query(sql, [params]) — Node.js mysql2
|
|
190
|
+
* - knex.raw(sql, [params]) — Knex.js
|
|
191
|
+
*/
|
|
192
|
+
function isParameterizedQueryCall(call, pattern) {
|
|
193
|
+
// Only applies to SQL injection sinks
|
|
194
|
+
if (pattern.type !== 'sql_injection')
|
|
195
|
+
return false;
|
|
196
|
+
// Parameterized queries have at least 2 arguments:
|
|
197
|
+
// arg[0] = query string (with ? or $N placeholders)
|
|
198
|
+
// arg[1] = params array
|
|
199
|
+
if (call.arguments.length < 2)
|
|
200
|
+
return false;
|
|
201
|
+
// Check if the second argument looks like a params array
|
|
202
|
+
const secondArg = call.arguments.find(a => a.position === 1);
|
|
203
|
+
if (!secondArg)
|
|
204
|
+
return false;
|
|
205
|
+
// Check for array literal: [id], [id, name], etc.
|
|
206
|
+
if (secondArg.expression) {
|
|
207
|
+
const expr = secondArg.expression.trim();
|
|
208
|
+
if (expr.startsWith('[')) {
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
182
214
|
/**
|
|
183
215
|
* Find taint sinks in method calls.
|
|
184
216
|
* Deduplicates sinks at the same location+line+cwe, keeping highest confidence.
|
|
@@ -189,6 +221,10 @@ function findSinks(calls, patterns) {
|
|
|
189
221
|
for (const call of calls) {
|
|
190
222
|
for (const pattern of patterns) {
|
|
191
223
|
if (matchesSinkPattern(call, pattern)) {
|
|
224
|
+
// Skip parameterized queries (safe pattern for SQL injection)
|
|
225
|
+
if (isParameterizedQueryCall(call, pattern)) {
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
192
228
|
const location = formatCallLocation(call);
|
|
193
229
|
const key = `${location}:${call.location.line}:${pattern.cwe}`;
|
|
194
230
|
const confidence = calculateSinkConfidence(call, pattern);
|