circle-ir 3.1.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/LICENSE +15 -0
- package/README.md +200 -0
- package/configs/sinks/code_injection.yaml +672 -0
- package/configs/sinks/command.yaml +917 -0
- package/configs/sinks/deserialization.yaml +105 -0
- package/configs/sinks/ldap.yaml +136 -0
- package/configs/sinks/nodejs.json +629 -0
- package/configs/sinks/path.yaml +715 -0
- package/configs/sinks/python.json +501 -0
- package/configs/sinks/rust.json +339 -0
- package/configs/sinks/sql.yaml +233 -0
- package/configs/sinks/ssrf.yaml +160 -0
- package/configs/sinks/xpath.yaml +121 -0
- package/configs/sinks/xss.yaml +727 -0
- package/configs/sources/db_sources.yaml +90 -0
- package/configs/sources/env_sources.yaml +94 -0
- package/configs/sources/express.json +197 -0
- package/configs/sources/file_sources.yaml +164 -0
- package/configs/sources/http_sources.yaml +379 -0
- package/configs/sources/io_sources.yaml +519 -0
- package/configs/sources/network_sources.yaml +99 -0
- package/configs/sources/python.json +230 -0
- package/configs/sources/rust.json +286 -0
- package/configs/sources/spring.yaml +70 -0
- package/dist/analysis/advisory-db.d.ts +86 -0
- package/dist/analysis/advisory-db.js +104 -0
- package/dist/analysis/advisory-db.js.map +1 -0
- package/dist/analysis/cargo-parser.d.ts +42 -0
- package/dist/analysis/cargo-parser.js +102 -0
- package/dist/analysis/cargo-parser.js.map +1 -0
- package/dist/analysis/config-loader.d.ts +37 -0
- package/dist/analysis/config-loader.js +1561 -0
- package/dist/analysis/config-loader.js.map +1 -0
- package/dist/analysis/constant-propagation/ast-utils.d.ts +25 -0
- package/dist/analysis/constant-propagation/ast-utils.js +34 -0
- package/dist/analysis/constant-propagation/ast-utils.js.map +1 -0
- package/dist/analysis/constant-propagation/evaluator.d.ts +32 -0
- package/dist/analysis/constant-propagation/evaluator.js +296 -0
- package/dist/analysis/constant-propagation/evaluator.js.map +1 -0
- package/dist/analysis/constant-propagation/index.d.ts +62 -0
- package/dist/analysis/constant-propagation/index.js +152 -0
- package/dist/analysis/constant-propagation/index.js.map +1 -0
- package/dist/analysis/constant-propagation/patterns.d.ts +8 -0
- package/dist/analysis/constant-propagation/patterns.js +126 -0
- package/dist/analysis/constant-propagation/patterns.js.map +1 -0
- package/dist/analysis/constant-propagation/propagator.d.ts +180 -0
- package/dist/analysis/constant-propagation/propagator.js +1985 -0
- package/dist/analysis/constant-propagation/propagator.js.map +1 -0
- package/dist/analysis/constant-propagation/types.d.ts +63 -0
- package/dist/analysis/constant-propagation/types.js +5 -0
- package/dist/analysis/constant-propagation/types.js.map +1 -0
- package/dist/analysis/constant-propagation.d.ts +9 -0
- package/dist/analysis/constant-propagation.js +18 -0
- package/dist/analysis/constant-propagation.js.map +1 -0
- package/dist/analysis/dependency-scanner.d.ts +79 -0
- package/dist/analysis/dependency-scanner.js +122 -0
- package/dist/analysis/dependency-scanner.js.map +1 -0
- package/dist/analysis/dfg-verifier.d.ts +116 -0
- package/dist/analysis/dfg-verifier.js +399 -0
- package/dist/analysis/dfg-verifier.js.map +1 -0
- package/dist/analysis/findings.d.ts +11 -0
- package/dist/analysis/findings.js +228 -0
- package/dist/analysis/findings.js.map +1 -0
- package/dist/analysis/index.d.ts +16 -0
- package/dist/analysis/index.js +18 -0
- package/dist/analysis/index.js.map +1 -0
- package/dist/analysis/interprocedural.d.ts +99 -0
- package/dist/analysis/interprocedural.js +526 -0
- package/dist/analysis/interprocedural.js.map +1 -0
- package/dist/analysis/path-finder.d.ts +133 -0
- package/dist/analysis/path-finder.js +354 -0
- package/dist/analysis/path-finder.js.map +1 -0
- package/dist/analysis/rules.d.ts +75 -0
- package/dist/analysis/rules.js +332 -0
- package/dist/analysis/rules.js.map +1 -0
- package/dist/analysis/semver.d.ts +27 -0
- package/dist/analysis/semver.js +127 -0
- package/dist/analysis/semver.js.map +1 -0
- package/dist/analysis/taint-matcher.d.ts +15 -0
- package/dist/analysis/taint-matcher.js +634 -0
- package/dist/analysis/taint-matcher.js.map +1 -0
- package/dist/analysis/taint-propagation.d.ts +67 -0
- package/dist/analysis/taint-propagation.js +298 -0
- package/dist/analysis/taint-propagation.js.map +1 -0
- package/dist/analysis/unresolved.d.ts +14 -0
- package/dist/analysis/unresolved.js +202 -0
- package/dist/analysis/unresolved.js.map +1 -0
- package/dist/analyzer.d.ts +43 -0
- package/dist/analyzer.js +1010 -0
- package/dist/analyzer.js.map +1 -0
- package/dist/browser/circle-ir.js +16576 -0
- package/dist/browser.d.ts +38 -0
- package/dist/browser.js +38 -0
- package/dist/browser.js.map +1 -0
- package/dist/core/circle-ir-core.cjs +13626 -0
- package/dist/core/circle-ir-core.d.ts +59 -0
- package/dist/core/circle-ir-core.js +13591 -0
- package/dist/core/extractors/calls.d.ts +13 -0
- package/dist/core/extractors/calls.js +1429 -0
- package/dist/core/extractors/calls.js.map +1 -0
- package/dist/core/extractors/cfg.d.ts +9 -0
- package/dist/core/extractors/cfg.js +519 -0
- package/dist/core/extractors/cfg.js.map +1 -0
- package/dist/core/extractors/dfg.d.ts +12 -0
- package/dist/core/extractors/dfg.js +1081 -0
- package/dist/core/extractors/dfg.js.map +1 -0
- package/dist/core/extractors/exports.d.ts +14 -0
- package/dist/core/extractors/exports.js +80 -0
- package/dist/core/extractors/exports.js.map +1 -0
- package/dist/core/extractors/imports.d.ts +9 -0
- package/dist/core/extractors/imports.js +739 -0
- package/dist/core/extractors/imports.js.map +1 -0
- package/dist/core/extractors/index.d.ts +10 -0
- package/dist/core/extractors/index.js +11 -0
- package/dist/core/extractors/index.js.map +1 -0
- package/dist/core/extractors/meta.d.ts +10 -0
- package/dist/core/extractors/meta.js +109 -0
- package/dist/core/extractors/meta.js.map +1 -0
- package/dist/core/extractors/types.d.ts +10 -0
- package/dist/core/extractors/types.js +1479 -0
- package/dist/core/extractors/types.js.map +1 -0
- package/dist/core/index.d.ts +5 -0
- package/dist/core/index.js +8 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/parser.d.ts +84 -0
- package/dist/core/parser.js +250 -0
- package/dist/core/parser.js.map +1 -0
- package/dist/core-lib.d.ts +59 -0
- package/dist/core-lib.js +62 -0
- package/dist/core-lib.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/languages/index.d.ts +11 -0
- package/dist/languages/index.js +14 -0
- package/dist/languages/index.js.map +1 -0
- package/dist/languages/plugins/base.d.ts +44 -0
- package/dist/languages/plugins/base.js +82 -0
- package/dist/languages/plugins/base.js.map +1 -0
- package/dist/languages/plugins/index.d.ts +14 -0
- package/dist/languages/plugins/index.js +25 -0
- package/dist/languages/plugins/index.js.map +1 -0
- package/dist/languages/plugins/java.d.ts +49 -0
- package/dist/languages/plugins/java.js +402 -0
- package/dist/languages/plugins/java.js.map +1 -0
- package/dist/languages/plugins/javascript.d.ts +48 -0
- package/dist/languages/plugins/javascript.js +445 -0
- package/dist/languages/plugins/javascript.js.map +1 -0
- package/dist/languages/plugins/python.d.ts +47 -0
- package/dist/languages/plugins/python.js +480 -0
- package/dist/languages/plugins/python.js.map +1 -0
- package/dist/languages/plugins/rust.d.ts +47 -0
- package/dist/languages/plugins/rust.js +405 -0
- package/dist/languages/plugins/rust.js.map +1 -0
- package/dist/languages/registry.d.ts +30 -0
- package/dist/languages/registry.js +80 -0
- package/dist/languages/registry.js.map +1 -0
- package/dist/languages/types.d.ts +184 -0
- package/dist/languages/types.js +8 -0
- package/dist/languages/types.js.map +1 -0
- package/dist/resolution/cross-file.d.ts +146 -0
- package/dist/resolution/cross-file.js +439 -0
- package/dist/resolution/cross-file.js.map +1 -0
- package/dist/resolution/index.d.ts +12 -0
- package/dist/resolution/index.js +10 -0
- package/dist/resolution/index.js.map +1 -0
- package/dist/resolution/symbol-table.d.ts +136 -0
- package/dist/resolution/symbol-table.js +336 -0
- package/dist/resolution/symbol-table.js.map +1 -0
- package/dist/resolution/type-hierarchy.d.ts +124 -0
- package/dist/resolution/type-hierarchy.js +515 -0
- package/dist/resolution/type-hierarchy.js.map +1 -0
- package/dist/types/config.d.ts +45 -0
- package/dist/types/config.js +5 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/index.d.ts +392 -0
- package/dist/types/index.js +7 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/logger.d.ts +85 -0
- package/dist/utils/logger.js +198 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/wasm/tree-sitter-java.wasm +0 -0
- package/dist/wasm/tree-sitter-javascript.wasm +0 -0
- package/dist/wasm/tree-sitter-python.wasm +0 -0
- package/dist/wasm/tree-sitter-rust.wasm +0 -0
- package/dist/wasm/web-tree-sitter.wasm +0 -0
- package/docs/SPEC.md +1021 -0
- package/examples/browser-example.html +610 -0
- package/examples/node-example.ts +215 -0
- package/package.json +107 -0
- package/wasm/tree-sitter-java.wasm +0 -0
- package/wasm/tree-sitter-javascript.wasm +0 -0
- package/wasm/tree-sitter-python.wasm +0 -0
- package/wasm/tree-sitter-rust.wasm +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"findings.js","sourceRoot":"","sources":["../../src/analysis/findings.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH,OAAO,EACL,iBAAiB,IAAI,YAAY,EACjC,cAAc,EACd,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,YAAY,CAAC;AAEpB;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAC9B,OAAsB,EACtB,KAAkB,EAClB,GAAQ,EACR,QAAgB;IAEhB,MAAM,QAAQ,GAAc,EAAE,CAAC;IAC/B,IAAI,SAAS,GAAG,CAAC,CAAC;IAElB,iDAAiD;IACjD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,qDAAqD;YACrD,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBAChD,SAAS;YACX,CAAC;YAED,qCAAqC;YACrC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;YAEpD,IAAI,UAAU,CAAC,UAAU,IAAI,wBAAwB,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC;gBACpE,MAAM,QAAQ,GAAG,YAAY,CAAC;oBAC5B,UAAU,EAAE,MAAM,CAAC,IAAI;oBACvB,QAAQ,EAAE,IAAI,CAAC,IAAI;oBACnB,UAAU,EAAE,UAAU,CAAC,UAAU;iBAClC,CAAC,CAAC;gBACH,MAAM,UAAU,GAAG,mBAAmB,CAAC,MAAM,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;gBAEjE,QAAQ,CAAC,IAAI,CAAC;oBACZ,EAAE,EAAE,OAAO,SAAS,EAAE,EAAE;oBACxB,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,GAAG,EAAE,IAAI,CAAC,GAAG;oBACb,QAAQ;oBACR,UAAU;oBACV,MAAM,EAAE;wBACN,IAAI,EAAE,QAAQ;wBACd,IAAI,EAAE,MAAM,CAAC,IAAI;wBACjB,IAAI,EAAE,MAAM,CAAC,QAAQ;qBACtB;oBACD,IAAI,EAAE;wBACJ,IAAI,EAAE,QAAQ;wBACd,IAAI,EAAE,IAAI,CAAC,IAAI;wBACf,IAAI,EAAE,IAAI,CAAC,QAAQ;qBACpB;oBACD,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;oBAC9D,WAAW,EAAE,UAAU,CAAC,UAAU,IAAI,UAAU,GAAG,GAAG;oBACtD,WAAW,EAAE,mBAAmB,CAAC,MAAM,EAAE,IAAI,EAAE,UAAU,CAAC;oBAC1D,WAAW,EAAE,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC;oBACtC,YAAY,EAAE;wBACZ,iBAAiB,EAAE,UAAU,CAAC,UAAU;wBACxC,YAAY,EAAE,KAAK;wBACnB,cAAc,EAAE,CAAC;qBAClB;iBACF,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,kCAAkC;IAClC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACrB,MAAM,aAAa,GAAG,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;QAClE,MAAM,YAAY,GAAG,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QAC3E,IAAI,YAAY,KAAK,CAAC;YAAE,OAAO,YAAY,CAAC;QAC5C,OAAO,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,UAAU,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;GAEG;AACH,SAAS,kBAAkB,CAAC,UAAkB,EAAE,QAAkB;IAChE,MAAM,mBAAmB,GAA+B;QACtD,UAAU,EAAE,CAAC,eAAe,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,CAAC;QACxH,SAAS,EAAE,CAAC,eAAe,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,KAAK,EAAE,KAAK,EAAE,gBAAgB,CAAC;QACpG,WAAW,EAAE,CAAC,eAAe,EAAE,KAAK,EAAE,MAAM,CAAC;QAC7C,WAAW,EAAE,CAAC,eAAe,EAAE,KAAK,CAAC;QACrC,SAAS,EAAE,CAAC,gBAAgB,EAAE,eAAe,EAAE,MAAM,CAAC;QACtD,UAAU,EAAE,CAAC,eAAe,EAAE,mBAAmB,EAAE,KAAK,EAAE,MAAM,CAAC;QACjE,QAAQ,EAAE,CAAC,mBAAmB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,KAAK,EAAE,gBAAgB,EAAE,KAAK,CAAC;QACpG,SAAS,EAAE,CAAC,mBAAmB,EAAE,gBAAgB,CAAC;QAClD,QAAQ,EAAE,CAAC,KAAK,EAAE,eAAe,CAAC,EAAE,yBAAyB;QAC7D,UAAU,EAAE,CAAC,iBAAiB,EAAE,KAAK,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,gBAAgB,CAAC;QAC/F,aAAa,EAAE,CAAC,eAAe,EAAE,mBAAmB,EAAE,KAAK,EAAE,MAAM,CAAC;QACpE,YAAY,EAAE,CAAC,eAAe,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE,sBAAsB;QAC7G,qBAAqB,EAAE,CAAC,eAAe,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,EAAE,gBAAgB,CAAC,EAAE,qBAAqB;QAC5K,YAAY,EAAE,CAAC,eAAe,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,KAAK,EAAE,gBAAgB,CAAC,EAAE,2BAA2B;KAC7H,CAAC;IAEF,MAAM,UAAU,GAAG,mBAAmB,CAAC,UAAU,CAAC,CAAC;IACnD,OAAO,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AAC5D,CAAC;AAQD;;GAEG;AACH,SAAS,aAAa,CAAC,MAAmB,EAAE,IAAe,EAAE,GAAQ;IACnE,MAAM,IAAI,GAAe,EAAE,CAAC;IAC5B,MAAM,SAAS,GAAa,EAAE,CAAC;IAE/B,wCAAwC;IACxC,MAAM,UAAU,GAAG,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CACrC,CAAC,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,GAAG,CAAC,CACvD,CAAC;IAEF,+BAA+B;IAC/B,MAAM,QAAQ,GAAG,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CACnC,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,GAAG,CAAC,CACnD,CAAC;IAEF,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrD,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;IACxD,CAAC;IAED,8BAA8B;IAC9B,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC;IAEhC,yDAAyD;IACzD,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,IAAI,GAAG,qBAAqB,CAAC,SAAS,CAAC,EAAE,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC;YAC9E,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACpB,uBAAuB;gBACvB,KAAK,MAAM,KAAK,IAAI,IAAI,EAAE,CAAC;oBACzB,MAAM,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC,CAAC;oBAC/C,IAAI,GAAG,EAAE,CAAC;wBACR,IAAI,CAAC,IAAI,CAAC;4BACR,IAAI,EAAE,EAAE,EAAE,2BAA2B;4BACrC,MAAM,EAAE,EAAE;4BACV,IAAI,EAAE,GAAG,CAAC,IAAI;4BACd,IAAI,EAAE,GAAG,GAAG,CAAC,QAAQ,QAAQ;4BAC7B,QAAQ,EAAE,GAAG,CAAC,QAAQ;yBACvB,CAAC,CAAC;wBACH,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;oBAC/B,CAAC;gBACH,CAAC;gBAED,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;YAC/C,CAAC;QACH,CAAC;IACH,CAAC;IAED,kDAAkD;IAClD,6DAA6D;IAC7D,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;QAC5C,4BAA4B;QAC5B,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC5D,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;QAExD,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;YAC3B,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;gBACpB,IAAI,CAAC,IAAI,CAAC;oBACR,IAAI,EAAE,EAAE;oBACR,MAAM,EAAE,EAAE;oBACV,IAAI,EAAE,MAAM,CAAC,IAAI;oBACjB,IAAI,EAAE,GAAG,CAAC,aAAa;oBACvB,QAAQ,EAAE,CAAC;iBACZ,CAAC,CAAC;gBACH,IAAI,CAAC,IAAI,CAAC;oBACR,IAAI,EAAE,EAAE;oBACR,MAAM,EAAE,EAAE;oBACV,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,IAAI,EAAE,QAAQ,CAAC,GAAG;oBAClB,QAAQ,EAAE,CAAC;iBACZ,CAAC,CAAC;gBACH,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBAClB,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;YAC/C,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;AACxD,CAAC;AAED;;GAEG;AACH,SAAS,qBAAqB,CAC5B,SAAiB,EACjB,OAAsB,EACtB,MAAkB,EAClB,GAAQ,EACR,UAAuB,IAAI,GAAG,EAAE,EAChC,OAAiB,EAAE;IAEnB,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,EAAE,CAAC;IAChC,IAAI,SAAS,KAAK,OAAO;QAAE,OAAO,CAAC,GAAG,IAAI,EAAE,SAAS,CAAC,CAAC;IACvD,IAAI,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;QAAE,OAAO,EAAE,CAAC;IAEtC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACvB,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAErB,uCAAuC;IACvC,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC;IAEpE,KAAK,MAAM,KAAK,IAAI,cAAc,EAAE,CAAC;QACnC,MAAM,MAAM,GAAG,qBAAqB,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;QAC7F,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtB,OAAO,MAAM,CAAC;QAChB,CAAC;IACH,CAAC;IAED,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;GAEG;AACH,SAAS,wBAAwB,CAAC,MAAmB,EAAE,IAAe;IACpE,8DAA8D;IAC9D,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;AACjD,CAAC;AAGD;;GAEG;AACH,SAAS,mBAAmB,CAAC,MAAmB,EAAE,IAAe,EAAE,UAAsB;IACvF,IAAI,UAAU,GAAG,GAAG,CAAC,CAAC,kBAAkB;IAExC,+BAA+B;IAC/B,IAAI,UAAU,CAAC,UAAU,EAAE,CAAC;QAC1B,UAAU,IAAI,GAAG,CAAC;IACpB,CAAC;IAED,0CAA0C;IAC1C,IAAI,UAAU,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/B,UAAU,IAAI,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,EAAE,GAAG,CAAC,CAAC;IAC7D,CAAC;IAED,6BAA6B;IAC7B,UAAU,GAAG,UAAU,GAAG,MAAM,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;IAE9D,kBAAkB;IAClB,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;IACnD,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;QAClB,UAAU,IAAI,GAAG,CAAC;IACpB,CAAC;SAAM,IAAI,QAAQ,IAAI,EAAE,EAAE,CAAC;QAC1B,UAAU,IAAI,IAAI,CAAC;IACrB,CAAC;IAED,OAAO,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;AACnC,CAAC;AAED;;GAEG;AACH,SAAS,mBAAmB,CAAC,MAAmB,EAAE,IAAe,EAAE,UAAsB;IACvF,MAAM,UAAU,GAAG,oBAAoB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACrD,MAAM,QAAQ,GAAG,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAE/C,IAAI,UAAU,CAAC,UAAU,IAAI,UAAU,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7D,MAAM,IAAI,GAAG,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC/C,OAAO,GAAG,UAAU,6BAA6B,IAAI,QAAQ,QAAQ,+BAA+B,CAAC;IACvG,CAAC;IAED,IAAI,UAAU,CAAC,UAAU,EAAE,CAAC;QAC1B,OAAO,GAAG,UAAU,aAAa,QAAQ,+BAA+B,CAAC;IAC3E,CAAC;IAED,OAAO,GAAG,UAAU,cAAc,QAAQ,oCAAoC,CAAC;AACjF,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analysis module index
|
|
3
|
+
*/
|
|
4
|
+
export { parseConfig, loadSourceConfigs, loadSinkConfigs, createTaintConfig, getDefaultConfig, DEFAULT_SOURCES, DEFAULT_SINKS, DEFAULT_SANITIZERS, } from './config-loader.js';
|
|
5
|
+
export { analyzeTaint, isInDangerousPosition, } from './taint-matcher.js';
|
|
6
|
+
export { detectUnresolved, } from './unresolved.js';
|
|
7
|
+
export { generateFindings, } from './findings.js';
|
|
8
|
+
export { propagateTaint, type TaintPropagationResult, type TaintedVariable, type TaintFlow, } from './taint-propagation.js';
|
|
9
|
+
export { analyzeInterprocedural, getInterproceduralSummary, findTaintBridges, getMethodTaintPaths, hasMethod, getMethod, isMethodTainted, type InterproceduralResult, type MethodNode, type CallEdge, } from './interprocedural.js';
|
|
10
|
+
export { analyzeConstantPropagation, isFalsePositive, isCorrelatedPredicateFP, ConstantPropagator, isKnown, createUnknown, createConstant, getNodeText, getNodeLine, type ConstantValue, type ConstantType, type ConstantPropagatorResult, type ConstantPropagationOptions, } from './constant-propagation.js';
|
|
11
|
+
export { PathFinder, findTaintPaths, formatTaintPath, type TaintHop, type TaintPath, type PathFinderResult, type PathFinderConfig, } from './path-finder.js';
|
|
12
|
+
export { DFGVerifier, verifyTaintFlow, formatVerificationResult, type VerificationResult, type VerificationPath, type VerificationStep, type VerifierConfig, } from './dfg-verifier.js';
|
|
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';
|
|
16
|
+
export { parseVersion, compareVersions, semverSatisfies, isVersionVulnerable, type ParsedVersion, } from './semver.js';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analysis module index
|
|
3
|
+
*/
|
|
4
|
+
export { parseConfig, loadSourceConfigs, loadSinkConfigs, createTaintConfig, getDefaultConfig, DEFAULT_SOURCES, DEFAULT_SINKS, DEFAULT_SANITIZERS, } from './config-loader.js';
|
|
5
|
+
export { analyzeTaint, isInDangerousPosition, } from './taint-matcher.js';
|
|
6
|
+
export { detectUnresolved, } from './unresolved.js';
|
|
7
|
+
export { generateFindings, } from './findings.js';
|
|
8
|
+
export { propagateTaint, } from './taint-propagation.js';
|
|
9
|
+
export { analyzeInterprocedural, getInterproceduralSummary, findTaintBridges, getMethodTaintPaths, hasMethod, getMethod, isMethodTainted, } from './interprocedural.js';
|
|
10
|
+
export { analyzeConstantPropagation, isFalsePositive, isCorrelatedPredicateFP, ConstantPropagator, isKnown, createUnknown, createConstant, getNodeText, getNodeLine, } from './constant-propagation.js';
|
|
11
|
+
export { PathFinder, findTaintPaths, formatTaintPath, } from './path-finder.js';
|
|
12
|
+
export { DFGVerifier, verifyTaintFlow, formatVerificationResult, } from './dfg-verifier.js';
|
|
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';
|
|
17
|
+
export { parseVersion, compareVersions, semverSatisfies, isVersionVulnerable, } from './semver.js';
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +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,EACZ,qBAAqB,GACtB,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,EACf,wBAAwB,GAKzB,MAAM,mBAAmB,CAAC;AAE3B,4BAA4B;AAC5B,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,kBAAkB,EAClB,qBAAqB,EACrB,iBAAiB,EACjB,mBAAmB,GAGpB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,cAAc,EACd,cAAc,EACd,kBAAkB,GAKnB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,aAAa,EACb,uBAAuB,EACvB,aAAa,EACb,gBAAgB,GAIjB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,YAAY,EACZ,eAAe,EACf,eAAe,EACf,mBAAmB,GAEpB,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inter-procedural Taint Analysis
|
|
3
|
+
*
|
|
4
|
+
* Tracks taint flow through method calls within the same file.
|
|
5
|
+
* - Propagates taint from arguments to parameters
|
|
6
|
+
* - Tracks taint through return values
|
|
7
|
+
* - Handles method call chains
|
|
8
|
+
*/
|
|
9
|
+
import type { CallInfo, TypeInfo, DFG, TaintSource, TaintSink, TaintSanitizer } from '../types/index.js';
|
|
10
|
+
/**
|
|
11
|
+
* Represents a method in the call graph.
|
|
12
|
+
*/
|
|
13
|
+
export interface MethodNode {
|
|
14
|
+
/** Simple method name */
|
|
15
|
+
name: string;
|
|
16
|
+
/** Fully qualified name: ClassName.methodName */
|
|
17
|
+
fqn: string;
|
|
18
|
+
/** Class/type this method belongs to */
|
|
19
|
+
className: string | null;
|
|
20
|
+
/** Package name if available */
|
|
21
|
+
packageName: string | null;
|
|
22
|
+
parameters: ParameterTaint[];
|
|
23
|
+
returnsTainted: boolean;
|
|
24
|
+
returnTaintType: string | null;
|
|
25
|
+
/** Which parameter positions flow to the return value (null = all potentially taint) */
|
|
26
|
+
returnTaintedFromParams: number[] | null;
|
|
27
|
+
startLine: number;
|
|
28
|
+
endLine: number;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Parameter taint information.
|
|
32
|
+
*/
|
|
33
|
+
export interface ParameterTaint {
|
|
34
|
+
name: string;
|
|
35
|
+
position: number;
|
|
36
|
+
isTainted: boolean;
|
|
37
|
+
taintType: string | null;
|
|
38
|
+
sourceLine: number | null;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* A call edge in the call graph.
|
|
42
|
+
*/
|
|
43
|
+
export interface CallEdge {
|
|
44
|
+
callerMethod: string;
|
|
45
|
+
calleeMethod: string;
|
|
46
|
+
callLine: number;
|
|
47
|
+
taintedArgs: number[];
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Result of inter-procedural analysis.
|
|
51
|
+
*/
|
|
52
|
+
export interface InterproceduralResult {
|
|
53
|
+
methodNodes: Map<string, MethodNode>;
|
|
54
|
+
callEdges: CallEdge[];
|
|
55
|
+
taintedMethods: Set<string>;
|
|
56
|
+
taintedReturns: Map<string, string>;
|
|
57
|
+
propagatedSinks: TaintSink[];
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Options for interprocedural analysis.
|
|
61
|
+
*/
|
|
62
|
+
export interface InterproceduralOptions {
|
|
63
|
+
/** Variables marked as tainted by constant propagation (e.g., collections with tainted elements) */
|
|
64
|
+
taintedVariables?: Set<string>;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Perform inter-procedural taint analysis.
|
|
68
|
+
*/
|
|
69
|
+
export declare function analyzeInterprocedural(types: TypeInfo[], calls: CallInfo[], dfg: DFG, sources: TaintSource[], sinks: TaintSink[], sanitizers: TaintSanitizer[], options?: InterproceduralOptions): InterproceduralResult;
|
|
70
|
+
/**
|
|
71
|
+
* Get summary of inter-procedural analysis.
|
|
72
|
+
*/
|
|
73
|
+
export declare function getInterproceduralSummary(result: InterproceduralResult): {
|
|
74
|
+
totalMethods: number;
|
|
75
|
+
taintedMethods: number;
|
|
76
|
+
callEdges: number;
|
|
77
|
+
methodsReturningTaint: number;
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* Check if a method exists in the interprocedural result.
|
|
81
|
+
* Accepts either simple name or FQN.
|
|
82
|
+
*/
|
|
83
|
+
export declare function hasMethod(result: InterproceduralResult, nameOrFqn: string): boolean;
|
|
84
|
+
/**
|
|
85
|
+
* Get a method node by simple name or FQN.
|
|
86
|
+
*/
|
|
87
|
+
export declare function getMethod(result: InterproceduralResult, nameOrFqn: string): MethodNode | undefined;
|
|
88
|
+
/**
|
|
89
|
+
* Check if a method is tainted (by simple name or FQN).
|
|
90
|
+
*/
|
|
91
|
+
export declare function isMethodTainted(result: InterproceduralResult, nameOrFqn: string): boolean;
|
|
92
|
+
/**
|
|
93
|
+
* Find methods that act as "taint bridges" - receiving taint and passing it on.
|
|
94
|
+
*/
|
|
95
|
+
export declare function findTaintBridges(result: InterproceduralResult): string[];
|
|
96
|
+
/**
|
|
97
|
+
* Get taint flow paths through methods.
|
|
98
|
+
*/
|
|
99
|
+
export declare function getMethodTaintPaths(result: InterproceduralResult, maxDepth?: number): string[][];
|
|
@@ -0,0 +1,526 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inter-procedural Taint Analysis
|
|
3
|
+
*
|
|
4
|
+
* Tracks taint flow through method calls within the same file.
|
|
5
|
+
* - Propagates taint from arguments to parameters
|
|
6
|
+
* - Tracks taint through return values
|
|
7
|
+
* - Handles method call chains
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Perform inter-procedural taint analysis.
|
|
11
|
+
*/
|
|
12
|
+
export function analyzeInterprocedural(types, calls, dfg, sources, sinks, sanitizers, options = {}) {
|
|
13
|
+
// Build method nodes from type information
|
|
14
|
+
const methodNodes = buildMethodNodes(types);
|
|
15
|
+
// Build call graph edges with receiver type resolution
|
|
16
|
+
const callEdges = buildCallEdges(calls, methodNodes, types);
|
|
17
|
+
// Identify initially tainted parameters (from sources)
|
|
18
|
+
const taintedMethods = new Set();
|
|
19
|
+
const taintedReturns = new Map();
|
|
20
|
+
// Mark methods containing sources as tainted (using FQN)
|
|
21
|
+
for (const source of sources) {
|
|
22
|
+
const methodInfo = findMethodAtLine(types, source.line);
|
|
23
|
+
if (methodInfo) {
|
|
24
|
+
const fqn = buildMethodFQN(methodInfo.packageName, methodInfo.className, methodInfo.methodName);
|
|
25
|
+
taintedMethods.add(fqn);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// Build taint map from DFG
|
|
29
|
+
const taintedDefIds = buildTaintedDefIds(dfg, sources);
|
|
30
|
+
// Get tainted variables from constant propagation (tracks collections with tainted elements)
|
|
31
|
+
const taintedVarsFromCP = options.taintedVariables ?? new Set();
|
|
32
|
+
// Analyze each call to propagate taint
|
|
33
|
+
const propagatedSinks = [];
|
|
34
|
+
// Track which method names are collection methods (should not create external escape sinks)
|
|
35
|
+
const collectionMethods = new Set([
|
|
36
|
+
'add', 'addLast', 'addFirst', 'addAll', 'put', 'putAll', 'set', 'push', 'offer',
|
|
37
|
+
'get', 'getLast', 'getFirst', 'peek', 'poll', 'pop', 'remove', 'removeFirst', 'removeLast',
|
|
38
|
+
'iterator', 'listIterator', 'next', 'hasNext', 'size', 'isEmpty', 'contains', 'containsKey',
|
|
39
|
+
'toString', 'valueOf', 'hashCode', 'equals', 'clone', 'clear',
|
|
40
|
+
]);
|
|
41
|
+
// Build set of sanitizer method names (methods that clean tainted data)
|
|
42
|
+
// Sanitizer methods may be in formats like "encode" or "URLEncoder.encode()"
|
|
43
|
+
const sanitizerMethods = new Set();
|
|
44
|
+
for (const san of sanitizers) {
|
|
45
|
+
sanitizerMethods.add(san.method);
|
|
46
|
+
// Also extract just the method name if formatted as "Class.method()"
|
|
47
|
+
const match = san.method.match(/\.(\w+)\(\)$/);
|
|
48
|
+
if (match) {
|
|
49
|
+
sanitizerMethods.add(match[1]);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
for (const call of calls) {
|
|
53
|
+
// Check if any arguments are tainted
|
|
54
|
+
const taintedArgPositions = [];
|
|
55
|
+
const taintedArgVars = [];
|
|
56
|
+
for (const arg of call.arguments) {
|
|
57
|
+
if (arg.variable) {
|
|
58
|
+
// Check 1: DFG-based taint tracking
|
|
59
|
+
const use = findUseAtLine(dfg, arg.variable, call.location.line);
|
|
60
|
+
const isTaintedByDFG = use && use.def_id !== null && taintedDefIds.has(use.def_id);
|
|
61
|
+
// Check 2: Constant propagation taint tracking (for collections with tainted elements)
|
|
62
|
+
const isTaintedByCP = taintedVarsFromCP.has(arg.variable);
|
|
63
|
+
if (isTaintedByDFG || isTaintedByCP) {
|
|
64
|
+
taintedArgPositions.push(arg.position);
|
|
65
|
+
taintedArgVars.push(arg.variable);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// Check if this is an internal method call (resolve using FQN or simple name)
|
|
70
|
+
const targetMethod = getMethodNode(methodNodes, call.method_name);
|
|
71
|
+
if (!targetMethod) {
|
|
72
|
+
// External method call - check if tainted data is escaping
|
|
73
|
+
// Skip collection methods (data manipulation) and sanitizer methods (data cleaning)
|
|
74
|
+
if (taintedArgPositions.length > 0 &&
|
|
75
|
+
!collectionMethods.has(call.method_name) &&
|
|
76
|
+
!sanitizerMethods.has(call.method_name)) {
|
|
77
|
+
// Create an "external_taint_escape" sink for this call
|
|
78
|
+
// This represents tainted data being passed to code we can't analyze
|
|
79
|
+
const sink = {
|
|
80
|
+
type: 'external_taint_escape',
|
|
81
|
+
cwe: 'CWE-668', // Exposure of Resource to Wrong Sphere
|
|
82
|
+
location: `Tainted data (${taintedArgVars.join(', ')}) passed to external method ${call.receiver ? call.receiver + '.' : ''}${call.method_name}()`,
|
|
83
|
+
line: call.location.line,
|
|
84
|
+
confidence: 0.7, // Lower confidence since we can't verify the external method is dangerous
|
|
85
|
+
method: call.method_name,
|
|
86
|
+
argPositions: taintedArgPositions,
|
|
87
|
+
};
|
|
88
|
+
// Only add if not already present
|
|
89
|
+
if (!propagatedSinks.some(s => s.line === sink.line && s.type === sink.type)) {
|
|
90
|
+
propagatedSinks.push(sink);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (taintedArgPositions.length > 0) {
|
|
96
|
+
// Mark corresponding parameters as tainted
|
|
97
|
+
for (const pos of taintedArgPositions) {
|
|
98
|
+
if (pos < targetMethod.parameters.length) {
|
|
99
|
+
targetMethod.parameters[pos].isTainted = true;
|
|
100
|
+
targetMethod.parameters[pos].sourceLine = call.location.line;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
taintedMethods.add(targetMethod.fqn);
|
|
104
|
+
// Check if target method has sinks
|
|
105
|
+
const methodSinks = sinks.filter(s => s.line >= targetMethod.startLine && s.line <= targetMethod.endLine);
|
|
106
|
+
// These sinks are now reachable via inter-procedural flow
|
|
107
|
+
for (const sink of methodSinks) {
|
|
108
|
+
// Check if not already in the list
|
|
109
|
+
if (!propagatedSinks.some(s => s.line === sink.line)) {
|
|
110
|
+
propagatedSinks.push({
|
|
111
|
+
...sink,
|
|
112
|
+
confidence: sink.confidence * 0.85, // Slightly lower confidence for inter-proc
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// Propagate taint through return values
|
|
119
|
+
propagateReturnTaint(types, dfg, taintedDefIds, taintedReturns, taintedMethods, methodNodes);
|
|
120
|
+
// Iteratively propagate taint through call chains
|
|
121
|
+
propagateThroughCallChains(callEdges, methodNodes, taintedMethods, taintedReturns, dfg, taintedDefIds);
|
|
122
|
+
return {
|
|
123
|
+
methodNodes: methodNodes.byFqn,
|
|
124
|
+
callEdges,
|
|
125
|
+
taintedMethods,
|
|
126
|
+
taintedReturns,
|
|
127
|
+
propagatedSinks,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Build a fully qualified name for a method.
|
|
132
|
+
* Format: [package.]ClassName.methodName
|
|
133
|
+
*/
|
|
134
|
+
function buildMethodFQN(packageName, className, methodName) {
|
|
135
|
+
if (packageName) {
|
|
136
|
+
return `${packageName}.${className}.${methodName}`;
|
|
137
|
+
}
|
|
138
|
+
return `${className}.${methodName}`;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Build method nodes from type information.
|
|
142
|
+
* Uses fully qualified names (FQN) as keys for precise method resolution.
|
|
143
|
+
*/
|
|
144
|
+
function buildMethodNodes(types) {
|
|
145
|
+
const byFqn = new Map();
|
|
146
|
+
const byName = new Map();
|
|
147
|
+
for (const type of types) {
|
|
148
|
+
for (const method of type.methods) {
|
|
149
|
+
const fqn = buildMethodFQN(type.package, type.name, method.name);
|
|
150
|
+
const node = {
|
|
151
|
+
name: method.name,
|
|
152
|
+
fqn,
|
|
153
|
+
className: type.name,
|
|
154
|
+
packageName: type.package,
|
|
155
|
+
parameters: method.parameters.map((p, i) => ({
|
|
156
|
+
name: p.name,
|
|
157
|
+
position: i,
|
|
158
|
+
isTainted: false,
|
|
159
|
+
taintType: null,
|
|
160
|
+
sourceLine: null,
|
|
161
|
+
})),
|
|
162
|
+
returnsTainted: false,
|
|
163
|
+
returnTaintType: null,
|
|
164
|
+
returnTaintedFromParams: null, // Will be computed during analysis
|
|
165
|
+
startLine: method.start_line,
|
|
166
|
+
endLine: method.end_line,
|
|
167
|
+
};
|
|
168
|
+
// Store with FQN as primary key
|
|
169
|
+
byFqn.set(fqn, node);
|
|
170
|
+
// Store with simple name for fallback (first occurrence wins)
|
|
171
|
+
if (!byName.has(method.name)) {
|
|
172
|
+
byName.set(method.name, node);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return { byFqn, byName };
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Get a method node by FQN or simple name.
|
|
180
|
+
*/
|
|
181
|
+
function getMethodNode(maps, key) {
|
|
182
|
+
return maps.byFqn.get(key) ?? maps.byName.get(key);
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Resolve a method call to its target node, considering receiver type.
|
|
186
|
+
* Returns the FQN of the resolved method, or null if not found.
|
|
187
|
+
*/
|
|
188
|
+
function resolveMethodCall(call, methodNodes, types) {
|
|
189
|
+
const methodName = call.method_name;
|
|
190
|
+
// If receiver type is known, try FQN resolution first
|
|
191
|
+
if (call.receiver_type) {
|
|
192
|
+
// Try exact FQN match
|
|
193
|
+
const fqn = `${call.receiver_type}.${methodName}`;
|
|
194
|
+
if (methodNodes.byFqn.has(fqn)) {
|
|
195
|
+
return fqn;
|
|
196
|
+
}
|
|
197
|
+
// Try with common package prefixes
|
|
198
|
+
for (const type of types) {
|
|
199
|
+
if (type.name === call.receiver_type && type.package) {
|
|
200
|
+
const fullFqn = `${type.package}.${type.name}.${methodName}`;
|
|
201
|
+
if (methodNodes.byFqn.has(fullFqn)) {
|
|
202
|
+
return fullFqn;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
// If receiver is known, try ClassName.methodName
|
|
208
|
+
if (call.receiver) {
|
|
209
|
+
// Receiver might be a variable - try to infer its type from types
|
|
210
|
+
for (const type of types) {
|
|
211
|
+
const fqn = type.package
|
|
212
|
+
? `${type.package}.${type.name}.${methodName}`
|
|
213
|
+
: `${type.name}.${methodName}`;
|
|
214
|
+
if (methodNodes.byFqn.has(fqn)) {
|
|
215
|
+
const node = methodNodes.byFqn.get(fqn);
|
|
216
|
+
// Check if this could be a match (same method name, right class)
|
|
217
|
+
if (node.name === methodName) {
|
|
218
|
+
return fqn;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
// Fallback: simple method name
|
|
224
|
+
if (methodNodes.byName.has(methodName)) {
|
|
225
|
+
const node = methodNodes.byName.get(methodName);
|
|
226
|
+
return node.fqn;
|
|
227
|
+
}
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Build call edges from call information.
|
|
232
|
+
* Uses receiver type information for precise method resolution.
|
|
233
|
+
*/
|
|
234
|
+
function buildCallEdges(calls, methodNodes, types) {
|
|
235
|
+
const edges = [];
|
|
236
|
+
for (const call of calls) {
|
|
237
|
+
// Resolve the call target using receiver type
|
|
238
|
+
const resolvedFqn = resolveMethodCall(call, methodNodes, types);
|
|
239
|
+
if (!resolvedFqn)
|
|
240
|
+
continue;
|
|
241
|
+
// Find the caller method
|
|
242
|
+
const callerMethod = call.in_method;
|
|
243
|
+
if (!callerMethod)
|
|
244
|
+
continue;
|
|
245
|
+
edges.push({
|
|
246
|
+
callerMethod,
|
|
247
|
+
calleeMethod: resolvedFqn,
|
|
248
|
+
callLine: call.location.line,
|
|
249
|
+
taintedArgs: [],
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
return edges;
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Build set of tainted definition IDs from sources.
|
|
256
|
+
*/
|
|
257
|
+
function buildTaintedDefIds(dfg, sources) {
|
|
258
|
+
const taintedDefIds = new Set();
|
|
259
|
+
// Find definitions on source lines
|
|
260
|
+
// Only mark defs on the EXACT source line as tainted
|
|
261
|
+
// (The previous +1 heuristic incorrectly marked unrelated defs as tainted)
|
|
262
|
+
for (const source of sources) {
|
|
263
|
+
for (const def of dfg.defs) {
|
|
264
|
+
if (def.line === source.line) {
|
|
265
|
+
taintedDefIds.add(def.id);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
// Propagate through chains
|
|
270
|
+
if (dfg.chains) {
|
|
271
|
+
let changed = true;
|
|
272
|
+
while (changed) {
|
|
273
|
+
changed = false;
|
|
274
|
+
for (const chain of dfg.chains) {
|
|
275
|
+
if (taintedDefIds.has(chain.from_def) && !taintedDefIds.has(chain.to_def)) {
|
|
276
|
+
taintedDefIds.add(chain.to_def);
|
|
277
|
+
changed = true;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
return taintedDefIds;
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Find a use at a specific line.
|
|
286
|
+
*/
|
|
287
|
+
function findUseAtLine(dfg, variable, line) {
|
|
288
|
+
for (const use of dfg.uses) {
|
|
289
|
+
if (use.variable === variable && use.line === line) {
|
|
290
|
+
return use;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return null;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Find the method containing a specific line.
|
|
297
|
+
* Returns method info along with class and package context.
|
|
298
|
+
*/
|
|
299
|
+
function findMethodAtLine(types, line) {
|
|
300
|
+
for (const type of types) {
|
|
301
|
+
for (const method of type.methods) {
|
|
302
|
+
if (line >= method.start_line && line <= method.end_line) {
|
|
303
|
+
return {
|
|
304
|
+
method,
|
|
305
|
+
methodName: method.name,
|
|
306
|
+
className: type.name,
|
|
307
|
+
packageName: type.package,
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
return null;
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Propagate taint through return values.
|
|
316
|
+
* Tracks which parameters flow to the return value for precise taint mapping.
|
|
317
|
+
*/
|
|
318
|
+
function propagateReturnTaint(types, dfg, taintedDefIds, taintedReturns, taintedMethods, methodNodes) {
|
|
319
|
+
// Find return statements that return tainted values
|
|
320
|
+
const returnDefs = dfg.defs.filter(d => d.kind === 'return');
|
|
321
|
+
for (const returnDef of returnDefs) {
|
|
322
|
+
// Find the method this return is in
|
|
323
|
+
const methodCtx = findMethodAtLine(types, returnDef.line);
|
|
324
|
+
if (!methodCtx)
|
|
325
|
+
continue;
|
|
326
|
+
const fqn = buildMethodFQN(methodCtx.packageName, methodCtx.className, methodCtx.methodName);
|
|
327
|
+
// Find uses on the same line (the returned value)
|
|
328
|
+
const usesOnLine = dfg.uses.filter(u => u.line === returnDef.line);
|
|
329
|
+
for (const use of usesOnLine) {
|
|
330
|
+
if (use.def_id !== null && taintedDefIds.has(use.def_id)) {
|
|
331
|
+
// This method returns a tainted value
|
|
332
|
+
taintedReturns.set(fqn, 'tainted');
|
|
333
|
+
taintedMethods.add(fqn);
|
|
334
|
+
// Track which parameter this return value came from
|
|
335
|
+
const methodNode = methodNodes.byFqn.get(fqn);
|
|
336
|
+
if (methodNode) {
|
|
337
|
+
// Check if the returned variable matches a parameter name
|
|
338
|
+
const paramIndex = methodNode.parameters.findIndex(p => p.name === use.variable);
|
|
339
|
+
if (paramIndex >= 0) {
|
|
340
|
+
// This return value comes from this parameter
|
|
341
|
+
if (methodNode.returnTaintedFromParams === null) {
|
|
342
|
+
methodNode.returnTaintedFromParams = [paramIndex];
|
|
343
|
+
}
|
|
344
|
+
else if (!methodNode.returnTaintedFromParams.includes(paramIndex)) {
|
|
345
|
+
methodNode.returnTaintedFromParams.push(paramIndex);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
break;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Propagate taint through call chains iteratively.
|
|
356
|
+
*/
|
|
357
|
+
function propagateThroughCallChains(callEdges, methodNodes, taintedMethods, taintedReturns, dfg, taintedDefIds) {
|
|
358
|
+
// Build reverse call graph (callee -> callers)
|
|
359
|
+
const callersOf = new Map();
|
|
360
|
+
for (const edge of callEdges) {
|
|
361
|
+
const existing = callersOf.get(edge.calleeMethod) ?? [];
|
|
362
|
+
existing.push(edge);
|
|
363
|
+
callersOf.set(edge.calleeMethod, existing);
|
|
364
|
+
}
|
|
365
|
+
// Iteratively propagate until fixed point
|
|
366
|
+
let changed = true;
|
|
367
|
+
let iterations = 0;
|
|
368
|
+
const maxIterations = 10; // Prevent infinite loops
|
|
369
|
+
while (changed && iterations < maxIterations) {
|
|
370
|
+
changed = false;
|
|
371
|
+
iterations++;
|
|
372
|
+
// For each method that returns tainted data
|
|
373
|
+
for (const [methodName, taintType] of taintedReturns) {
|
|
374
|
+
// Find all callers of this method
|
|
375
|
+
const callers = callersOf.get(methodName) ?? [];
|
|
376
|
+
for (const edge of callers) {
|
|
377
|
+
// The call site now produces tainted data
|
|
378
|
+
// Find definitions at the call line (the variable receiving the return value)
|
|
379
|
+
for (const def of dfg.defs) {
|
|
380
|
+
if (def.line === edge.callLine && !taintedDefIds.has(def.id)) {
|
|
381
|
+
taintedDefIds.add(def.id);
|
|
382
|
+
changed = true;
|
|
383
|
+
// Mark the caller method as tainted
|
|
384
|
+
if (!taintedMethods.has(edge.callerMethod)) {
|
|
385
|
+
taintedMethods.add(edge.callerMethod);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
// Propagate through chains again
|
|
392
|
+
if (dfg.chains) {
|
|
393
|
+
for (const chain of dfg.chains) {
|
|
394
|
+
if (taintedDefIds.has(chain.from_def) && !taintedDefIds.has(chain.to_def)) {
|
|
395
|
+
taintedDefIds.add(chain.to_def);
|
|
396
|
+
changed = true;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Get summary of inter-procedural analysis.
|
|
404
|
+
*/
|
|
405
|
+
export function getInterproceduralSummary(result) {
|
|
406
|
+
return {
|
|
407
|
+
totalMethods: result.methodNodes.size,
|
|
408
|
+
taintedMethods: result.taintedMethods.size,
|
|
409
|
+
callEdges: result.callEdges.length,
|
|
410
|
+
methodsReturningTaint: result.taintedReturns.size,
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Check if a method exists in the interprocedural result.
|
|
415
|
+
* Accepts either simple name or FQN.
|
|
416
|
+
*/
|
|
417
|
+
export function hasMethod(result, nameOrFqn) {
|
|
418
|
+
// Try exact match first (FQN)
|
|
419
|
+
if (result.methodNodes.has(nameOrFqn)) {
|
|
420
|
+
return true;
|
|
421
|
+
}
|
|
422
|
+
// Try matching by simple name
|
|
423
|
+
for (const [fqn, node] of result.methodNodes) {
|
|
424
|
+
if (node.name === nameOrFqn) {
|
|
425
|
+
return true;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
return false;
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Get a method node by simple name or FQN.
|
|
432
|
+
*/
|
|
433
|
+
export function getMethod(result, nameOrFqn) {
|
|
434
|
+
// Try exact match first (FQN)
|
|
435
|
+
if (result.methodNodes.has(nameOrFqn)) {
|
|
436
|
+
return result.methodNodes.get(nameOrFqn);
|
|
437
|
+
}
|
|
438
|
+
// Try matching by simple name
|
|
439
|
+
for (const [fqn, node] of result.methodNodes) {
|
|
440
|
+
if (node.name === nameOrFqn) {
|
|
441
|
+
return node;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
return undefined;
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Check if a method is tainted (by simple name or FQN).
|
|
448
|
+
*/
|
|
449
|
+
export function isMethodTainted(result, nameOrFqn) {
|
|
450
|
+
// Try exact match first (FQN)
|
|
451
|
+
if (result.taintedMethods.has(nameOrFqn)) {
|
|
452
|
+
return true;
|
|
453
|
+
}
|
|
454
|
+
// Try matching by simple name - check if any tainted method has this name
|
|
455
|
+
for (const fqn of result.taintedMethods) {
|
|
456
|
+
const node = result.methodNodes.get(fqn);
|
|
457
|
+
if (node && node.name === nameOrFqn) {
|
|
458
|
+
return true;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
return false;
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* Find methods that act as "taint bridges" - receiving taint and passing it on.
|
|
465
|
+
*/
|
|
466
|
+
export function findTaintBridges(result) {
|
|
467
|
+
const bridges = [];
|
|
468
|
+
for (const [name, node] of result.methodNodes) {
|
|
469
|
+
const hasTaintedParams = node.parameters.some(p => p.isTainted);
|
|
470
|
+
const returnsTainted = result.taintedReturns.has(name);
|
|
471
|
+
if (hasTaintedParams && returnsTainted) {
|
|
472
|
+
bridges.push(name);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
return bridges;
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Get taint flow paths through methods.
|
|
479
|
+
*/
|
|
480
|
+
export function getMethodTaintPaths(result, maxDepth = 5) {
|
|
481
|
+
const paths = [];
|
|
482
|
+
// Find entry points (methods with tainted parameters from external sources)
|
|
483
|
+
const entryMethods = Array.from(result.methodNodes.entries())
|
|
484
|
+
.filter(([_, node]) => node.parameters.some(p => p.isTainted && p.sourceLine !== null))
|
|
485
|
+
.map(([name]) => name);
|
|
486
|
+
// Build call graph adjacency
|
|
487
|
+
const callsTo = new Map();
|
|
488
|
+
for (const edge of result.callEdges) {
|
|
489
|
+
const existing = callsTo.get(edge.callerMethod) ?? [];
|
|
490
|
+
if (!existing.includes(edge.calleeMethod)) {
|
|
491
|
+
existing.push(edge.calleeMethod);
|
|
492
|
+
}
|
|
493
|
+
callsTo.set(edge.callerMethod, existing);
|
|
494
|
+
}
|
|
495
|
+
// DFS to find paths
|
|
496
|
+
function dfs(current, path, visited) {
|
|
497
|
+
if (path.length > maxDepth)
|
|
498
|
+
return;
|
|
499
|
+
if (visited.has(current))
|
|
500
|
+
return;
|
|
501
|
+
visited.add(current);
|
|
502
|
+
path.push(current);
|
|
503
|
+
// If this method returns taint and has callees, continue
|
|
504
|
+
const callees = callsTo.get(current) ?? [];
|
|
505
|
+
if (callees.length === 0 || !result.taintedMethods.has(current)) {
|
|
506
|
+
// End of path
|
|
507
|
+
if (path.length > 1) {
|
|
508
|
+
paths.push([...path]);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
else {
|
|
512
|
+
for (const callee of callees) {
|
|
513
|
+
if (result.taintedMethods.has(callee)) {
|
|
514
|
+
dfs(callee, path, visited);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
path.pop();
|
|
519
|
+
visited.delete(current);
|
|
520
|
+
}
|
|
521
|
+
for (const entry of entryMethods) {
|
|
522
|
+
dfs(entry, [], new Set());
|
|
523
|
+
}
|
|
524
|
+
return paths;
|
|
525
|
+
}
|
|
526
|
+
//# sourceMappingURL=interprocedural.js.map
|