@trust-assurance-protocol/owaspscan 1.0.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.
Files changed (221) hide show
  1. package/dist/analysis/ast-analyzer.d.ts +13 -0
  2. package/dist/analysis/ast-analyzer.d.ts.map +1 -0
  3. package/dist/analysis/ast-analyzer.js +58 -0
  4. package/dist/analysis/ast-analyzer.js.map +1 -0
  5. package/dist/analysis/llm-verifier.d.ts +17 -0
  6. package/dist/analysis/llm-verifier.d.ts.map +1 -0
  7. package/dist/analysis/llm-verifier.js +152 -0
  8. package/dist/analysis/llm-verifier.js.map +1 -0
  9. package/dist/analysis/result-cache.d.ts +20 -0
  10. package/dist/analysis/result-cache.d.ts.map +1 -0
  11. package/dist/analysis/result-cache.js +70 -0
  12. package/dist/analysis/result-cache.js.map +1 -0
  13. package/dist/analysis/sinks.d.ts +12 -0
  14. package/dist/analysis/sinks.d.ts.map +1 -0
  15. package/dist/analysis/sinks.js +142 -0
  16. package/dist/analysis/sinks.js.map +1 -0
  17. package/dist/analysis/sources.d.ts +8 -0
  18. package/dist/analysis/sources.d.ts.map +1 -0
  19. package/dist/analysis/sources.js +114 -0
  20. package/dist/analysis/sources.js.map +1 -0
  21. package/dist/analysis/taint-engine.d.ts +5 -0
  22. package/dist/analysis/taint-engine.d.ts.map +1 -0
  23. package/dist/analysis/taint-engine.js +187 -0
  24. package/dist/analysis/taint-engine.js.map +1 -0
  25. package/dist/cli/index.d.ts +3 -0
  26. package/dist/cli/index.d.ts.map +1 -0
  27. package/dist/cli/index.js +227 -0
  28. package/dist/cli/index.js.map +1 -0
  29. package/dist/config/loader.d.ts +10 -0
  30. package/dist/config/loader.d.ts.map +1 -0
  31. package/dist/config/loader.js +81 -0
  32. package/dist/config/loader.js.map +1 -0
  33. package/dist/config/schema.d.ts +23 -0
  34. package/dist/config/schema.d.ts.map +1 -0
  35. package/dist/config/schema.js +17 -0
  36. package/dist/config/schema.js.map +1 -0
  37. package/dist/mcp/server.d.ts +2 -0
  38. package/dist/mcp/server.d.ts.map +1 -0
  39. package/dist/mcp/server.js +250 -0
  40. package/dist/mcp/server.js.map +1 -0
  41. package/dist/parsers/ast-parser.d.ts +38 -0
  42. package/dist/parsers/ast-parser.d.ts.map +1 -0
  43. package/dist/parsers/ast-parser.js +88 -0
  44. package/dist/parsers/ast-parser.js.map +1 -0
  45. package/dist/parsers/ast-queries.d.ts +63 -0
  46. package/dist/parsers/ast-queries.d.ts.map +1 -0
  47. package/dist/parsers/ast-queries.js +580 -0
  48. package/dist/parsers/ast-queries.js.map +1 -0
  49. package/dist/reporter/console.d.ts +8 -0
  50. package/dist/reporter/console.d.ts.map +1 -0
  51. package/dist/reporter/console.js +143 -0
  52. package/dist/reporter/console.js.map +1 -0
  53. package/dist/reporter/json.d.ts +3 -0
  54. package/dist/reporter/json.d.ts.map +1 -0
  55. package/dist/reporter/json.js +7 -0
  56. package/dist/reporter/json.js.map +1 -0
  57. package/dist/reporter/llm.d.ts +3 -0
  58. package/dist/reporter/llm.d.ts.map +1 -0
  59. package/dist/reporter/llm.js +66 -0
  60. package/dist/reporter/llm.js.map +1 -0
  61. package/dist/reporter/sarif.d.ts +3 -0
  62. package/dist/reporter/sarif.d.ts.map +1 -0
  63. package/dist/reporter/sarif.js +110 -0
  64. package/dist/reporter/sarif.js.map +1 -0
  65. package/dist/rules/owasp-a01/idor.d.ts +3 -0
  66. package/dist/rules/owasp-a01/idor.d.ts.map +1 -0
  67. package/dist/rules/owasp-a01/idor.js +48 -0
  68. package/dist/rules/owasp-a01/idor.js.map +1 -0
  69. package/dist/rules/owasp-a01/missing-auth-middleware.d.ts +3 -0
  70. package/dist/rules/owasp-a01/missing-auth-middleware.d.ts.map +1 -0
  71. package/dist/rules/owasp-a01/missing-auth-middleware.js +41 -0
  72. package/dist/rules/owasp-a01/missing-auth-middleware.js.map +1 -0
  73. package/dist/rules/owasp-a01/path-traversal.d.ts +3 -0
  74. package/dist/rules/owasp-a01/path-traversal.d.ts.map +1 -0
  75. package/dist/rules/owasp-a01/path-traversal.js +73 -0
  76. package/dist/rules/owasp-a01/path-traversal.js.map +1 -0
  77. package/dist/rules/owasp-a02/hardcoded-secrets.d.ts +3 -0
  78. package/dist/rules/owasp-a02/hardcoded-secrets.d.ts.map +1 -0
  79. package/dist/rules/owasp-a02/hardcoded-secrets.js +97 -0
  80. package/dist/rules/owasp-a02/hardcoded-secrets.js.map +1 -0
  81. package/dist/rules/owasp-a02/insecure-tls.d.ts +3 -0
  82. package/dist/rules/owasp-a02/insecure-tls.d.ts.map +1 -0
  83. package/dist/rules/owasp-a02/insecure-tls.js +75 -0
  84. package/dist/rules/owasp-a02/insecure-tls.js.map +1 -0
  85. package/dist/rules/owasp-a02/weak-hash.d.ts +3 -0
  86. package/dist/rules/owasp-a02/weak-hash.d.ts.map +1 -0
  87. package/dist/rules/owasp-a02/weak-hash.js +73 -0
  88. package/dist/rules/owasp-a02/weak-hash.js.map +1 -0
  89. package/dist/rules/owasp-a02/weak-random.d.ts +3 -0
  90. package/dist/rules/owasp-a02/weak-random.d.ts.map +1 -0
  91. package/dist/rules/owasp-a02/weak-random.js +70 -0
  92. package/dist/rules/owasp-a02/weak-random.js.map +1 -0
  93. package/dist/rules/owasp-a03/command-injection.d.ts +3 -0
  94. package/dist/rules/owasp-a03/command-injection.d.ts.map +1 -0
  95. package/dist/rules/owasp-a03/command-injection.js +79 -0
  96. package/dist/rules/owasp-a03/command-injection.js.map +1 -0
  97. package/dist/rules/owasp-a03/ldap-injection.d.ts +3 -0
  98. package/dist/rules/owasp-a03/ldap-injection.d.ts.map +1 -0
  99. package/dist/rules/owasp-a03/ldap-injection.js +56 -0
  100. package/dist/rules/owasp-a03/ldap-injection.js.map +1 -0
  101. package/dist/rules/owasp-a03/nosql-injection.d.ts +3 -0
  102. package/dist/rules/owasp-a03/nosql-injection.d.ts.map +1 -0
  103. package/dist/rules/owasp-a03/nosql-injection.js +61 -0
  104. package/dist/rules/owasp-a03/nosql-injection.js.map +1 -0
  105. package/dist/rules/owasp-a03/sql-injection.d.ts +3 -0
  106. package/dist/rules/owasp-a03/sql-injection.d.ts.map +1 -0
  107. package/dist/rules/owasp-a03/sql-injection.js +88 -0
  108. package/dist/rules/owasp-a03/sql-injection.js.map +1 -0
  109. package/dist/rules/owasp-a03/template-injection.d.ts +3 -0
  110. package/dist/rules/owasp-a03/template-injection.d.ts.map +1 -0
  111. package/dist/rules/owasp-a03/template-injection.js +64 -0
  112. package/dist/rules/owasp-a03/template-injection.js.map +1 -0
  113. package/dist/rules/owasp-a03/xss.d.ts +3 -0
  114. package/dist/rules/owasp-a03/xss.d.ts.map +1 -0
  115. package/dist/rules/owasp-a03/xss.js +74 -0
  116. package/dist/rules/owasp-a03/xss.js.map +1 -0
  117. package/dist/rules/owasp-a04/mass-assignment.d.ts +3 -0
  118. package/dist/rules/owasp-a04/mass-assignment.d.ts.map +1 -0
  119. package/dist/rules/owasp-a04/mass-assignment.js +63 -0
  120. package/dist/rules/owasp-a04/mass-assignment.js.map +1 -0
  121. package/dist/rules/owasp-a04/missing-rate-limit.d.ts +3 -0
  122. package/dist/rules/owasp-a04/missing-rate-limit.d.ts.map +1 -0
  123. package/dist/rules/owasp-a04/missing-rate-limit.js +48 -0
  124. package/dist/rules/owasp-a04/missing-rate-limit.js.map +1 -0
  125. package/dist/rules/owasp-a05/cors-wildcard.d.ts +3 -0
  126. package/dist/rules/owasp-a05/cors-wildcard.d.ts.map +1 -0
  127. package/dist/rules/owasp-a05/cors-wildcard.js +79 -0
  128. package/dist/rules/owasp-a05/cors-wildcard.js.map +1 -0
  129. package/dist/rules/owasp-a05/debug-mode.d.ts +3 -0
  130. package/dist/rules/owasp-a05/debug-mode.d.ts.map +1 -0
  131. package/dist/rules/owasp-a05/debug-mode.js +73 -0
  132. package/dist/rules/owasp-a05/debug-mode.js.map +1 -0
  133. package/dist/rules/owasp-a05/default-credentials.d.ts +3 -0
  134. package/dist/rules/owasp-a05/default-credentials.d.ts.map +1 -0
  135. package/dist/rules/owasp-a05/default-credentials.js +52 -0
  136. package/dist/rules/owasp-a05/default-credentials.js.map +1 -0
  137. package/dist/rules/owasp-a05/error-disclosure.d.ts +3 -0
  138. package/dist/rules/owasp-a05/error-disclosure.d.ts.map +1 -0
  139. package/dist/rules/owasp-a05/error-disclosure.js +70 -0
  140. package/dist/rules/owasp-a05/error-disclosure.js.map +1 -0
  141. package/dist/rules/owasp-a06/outdated-packages.d.ts +3 -0
  142. package/dist/rules/owasp-a06/outdated-packages.d.ts.map +1 -0
  143. package/dist/rules/owasp-a06/outdated-packages.js +75 -0
  144. package/dist/rules/owasp-a06/outdated-packages.js.map +1 -0
  145. package/dist/rules/owasp-a07/insecure-cookies.d.ts +3 -0
  146. package/dist/rules/owasp-a07/insecure-cookies.d.ts.map +1 -0
  147. package/dist/rules/owasp-a07/insecure-cookies.js +64 -0
  148. package/dist/rules/owasp-a07/insecure-cookies.js.map +1 -0
  149. package/dist/rules/owasp-a07/jwt-none-alg.d.ts +3 -0
  150. package/dist/rules/owasp-a07/jwt-none-alg.d.ts.map +1 -0
  151. package/dist/rules/owasp-a07/jwt-none-alg.js +81 -0
  152. package/dist/rules/owasp-a07/jwt-none-alg.js.map +1 -0
  153. package/dist/rules/owasp-a07/no-password-hashing.d.ts +3 -0
  154. package/dist/rules/owasp-a07/no-password-hashing.d.ts.map +1 -0
  155. package/dist/rules/owasp-a07/no-password-hashing.js +70 -0
  156. package/dist/rules/owasp-a07/no-password-hashing.js.map +1 -0
  157. package/dist/rules/owasp-a07/weak-session.d.ts +3 -0
  158. package/dist/rules/owasp-a07/weak-session.d.ts.map +1 -0
  159. package/dist/rules/owasp-a07/weak-session.js +64 -0
  160. package/dist/rules/owasp-a07/weak-session.js.map +1 -0
  161. package/dist/rules/owasp-a08/unsafe-deserialization.d.ts +3 -0
  162. package/dist/rules/owasp-a08/unsafe-deserialization.d.ts.map +1 -0
  163. package/dist/rules/owasp-a08/unsafe-deserialization.js +78 -0
  164. package/dist/rules/owasp-a08/unsafe-deserialization.js.map +1 -0
  165. package/dist/rules/owasp-a08/unsafe-eval.d.ts +3 -0
  166. package/dist/rules/owasp-a08/unsafe-eval.d.ts.map +1 -0
  167. package/dist/rules/owasp-a08/unsafe-eval.js +73 -0
  168. package/dist/rules/owasp-a08/unsafe-eval.js.map +1 -0
  169. package/dist/rules/owasp-a09/log-sensitive-data.d.ts +3 -0
  170. package/dist/rules/owasp-a09/log-sensitive-data.d.ts.map +1 -0
  171. package/dist/rules/owasp-a09/log-sensitive-data.js +73 -0
  172. package/dist/rules/owasp-a09/log-sensitive-data.js.map +1 -0
  173. package/dist/rules/owasp-a09/missing-error-handling.d.ts +3 -0
  174. package/dist/rules/owasp-a09/missing-error-handling.d.ts.map +1 -0
  175. package/dist/rules/owasp-a09/missing-error-handling.js +84 -0
  176. package/dist/rules/owasp-a09/missing-error-handling.js.map +1 -0
  177. package/dist/rules/owasp-a10/open-redirect.d.ts +3 -0
  178. package/dist/rules/owasp-a10/open-redirect.d.ts.map +1 -0
  179. package/dist/rules/owasp-a10/open-redirect.js +67 -0
  180. package/dist/rules/owasp-a10/open-redirect.js.map +1 -0
  181. package/dist/rules/owasp-a10/unvalidated-fetch.d.ts +3 -0
  182. package/dist/rules/owasp-a10/unvalidated-fetch.d.ts.map +1 -0
  183. package/dist/rules/owasp-a10/unvalidated-fetch.js +85 -0
  184. package/dist/rules/owasp-a10/unvalidated-fetch.js.map +1 -0
  185. package/dist/rules/registry.d.ts +20 -0
  186. package/dist/rules/registry.d.ts.map +1 -0
  187. package/dist/rules/registry.js +142 -0
  188. package/dist/rules/registry.js.map +1 -0
  189. package/dist/scanner/engine.d.ts +21 -0
  190. package/dist/scanner/engine.d.ts.map +1 -0
  191. package/dist/scanner/engine.js +260 -0
  192. package/dist/scanner/engine.js.map +1 -0
  193. package/dist/scanner/file-walker.d.ts +7 -0
  194. package/dist/scanner/file-walker.d.ts.map +1 -0
  195. package/dist/scanner/file-walker.js +81 -0
  196. package/dist/scanner/file-walker.js.map +1 -0
  197. package/dist/scanner/language-detect.d.ts +5 -0
  198. package/dist/scanner/language-detect.d.ts.map +1 -0
  199. package/dist/scanner/language-detect.js +91 -0
  200. package/dist/scanner/language-detect.js.map +1 -0
  201. package/dist/scanner/sca-scanner.d.ts +38 -0
  202. package/dist/scanner/sca-scanner.d.ts.map +1 -0
  203. package/dist/scanner/sca-scanner.js +223 -0
  204. package/dist/scanner/sca-scanner.js.map +1 -0
  205. package/dist/types/index.d.ts +114 -0
  206. package/dist/types/index.d.ts.map +1 -0
  207. package/dist/types/index.js +25 -0
  208. package/dist/types/index.js.map +1 -0
  209. package/dist/utils/pattern-matcher.d.ts +4 -0
  210. package/dist/utils/pattern-matcher.d.ts.map +1 -0
  211. package/dist/utils/pattern-matcher.js +72 -0
  212. package/dist/utils/pattern-matcher.js.map +1 -0
  213. package/dist/utils/scoring.d.ts +8 -0
  214. package/dist/utils/scoring.d.ts.map +1 -0
  215. package/dist/utils/scoring.js +76 -0
  216. package/dist/utils/scoring.js.map +1 -0
  217. package/dist/utils/suppression.d.ts +3 -0
  218. package/dist/utils/suppression.d.ts.map +1 -0
  219. package/dist/utils/suppression.js +33 -0
  220. package/dist/utils/suppression.js.map +1 -0
  221. package/package.json +94 -0
@@ -0,0 +1,13 @@
1
+ import type { Finding, Rule } from '../types/index.js';
2
+ import type { TaintMap } from '../parsers/ast-queries.js';
3
+ export type { TaintMap };
4
+ type ASTLanguage = 'javascript' | 'typescript' | 'python';
5
+ /**
6
+ * Run AST-based analysis on source code.
7
+ * Returns Finding[] — empty array if AST parsing fails (graceful degradation).
8
+ *
9
+ * crossFileSources: optional function names from other scanned files that return
10
+ * tainted data (populated by the two-pass scanDirectory pre-pass).
11
+ */
12
+ export declare function analyzeAST(code: string, language: ASTLanguage, filePath: string, rules: Rule[], crossFileSources?: TaintMap): Finding[];
13
+ //# sourceMappingURL=ast-analyzer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ast-analyzer.d.ts","sourceRoot":"","sources":["../../src/analysis/ast-analyzer.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAGvD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAI1D,YAAY,EAAE,QAAQ,EAAE,CAAC;AAEzB,KAAK,WAAW,GAAG,YAAY,GAAG,YAAY,GAAG,QAAQ,CAAC;AAE1D;;;;;;GAMG;AACH,wBAAgB,UAAU,CACxB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,WAAW,EACrB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,IAAI,EAAE,EACb,gBAAgB,CAAC,EAAE,QAAQ,GAC1B,OAAO,EAAE,CAyCX"}
@@ -0,0 +1,58 @@
1
+ // ============================================================
2
+ // AST Analyzer — converts AST findings into Finding objects
3
+ //
4
+ // Integrates both direct detection and AST-based taint propagation.
5
+ // Runs before regex so that AST findings take priority.
6
+ // Falls back silently if tree-sitter is unavailable.
7
+ // ============================================================
8
+ import { parseCode } from '../parsers/ast-parser.js';
9
+ import { findVulnerableCalls } from '../parsers/ast-queries.js';
10
+ import { isSuppressed } from '../utils/suppression.js';
11
+ import { registry } from '../rules/registry.js';
12
+ /**
13
+ * Run AST-based analysis on source code.
14
+ * Returns Finding[] — empty array if AST parsing fails (graceful degradation).
15
+ *
16
+ * crossFileSources: optional function names from other scanned files that return
17
+ * tainted data (populated by the two-pass scanDirectory pre-pass).
18
+ */
19
+ export function analyzeAST(code, language, filePath, rules, crossFileSources) {
20
+ // Try to parse; if it fails (native module missing, parse error), return empty
21
+ const tree = parseCode(code, language);
22
+ if (!tree)
23
+ return [];
24
+ const activeRuleIds = new Set(rules.map((r) => r.id));
25
+ const lines = code.split('\n');
26
+ const findings = [];
27
+ const astFindings = findVulnerableCalls(tree.rootNode, language, lines, crossFileSources);
28
+ for (const af of astFindings) {
29
+ // Only emit if the rule is in the active set
30
+ if (!activeRuleIds.has(af.ruleId))
31
+ continue;
32
+ // Check suppression comments
33
+ if (isSuppressed(lines, af.line - 1, af.ruleId))
34
+ continue;
35
+ const rule = registry.getById(af.ruleId);
36
+ if (!rule)
37
+ continue;
38
+ findings.push({
39
+ ruleId: af.ruleId,
40
+ ruleName: rule.name,
41
+ owasp: af.owasp,
42
+ cwe: rule.cwe,
43
+ severity: af.severity,
44
+ filePath,
45
+ line: af.line,
46
+ column: af.column,
47
+ snippet: af.snippet,
48
+ message: `[AST] ${af.description}`,
49
+ fix: rule.fix,
50
+ references: rule.references,
51
+ confidence: af.suppressedByMiddleware ? 'LOW' : 'HIGH',
52
+ analysisMethod: 'ast',
53
+ taintPath: af.taintPath,
54
+ });
55
+ }
56
+ return findings;
57
+ }
58
+ //# sourceMappingURL=ast-analyzer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ast-analyzer.js","sourceRoot":"","sources":["../../src/analysis/ast-analyzer.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,4DAA4D;AAC5D,EAAE;AACF,oEAAoE;AACpE,wDAAwD;AACxD,qDAAqD;AACrD,+DAA+D;AAG/D,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAEhE,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAMhD;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CACxB,IAAY,EACZ,QAAqB,EACrB,QAAgB,EAChB,KAAa,EACb,gBAA2B;IAE3B,+EAA+E;IAC/E,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACvC,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IAErB,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACtD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC/B,MAAM,QAAQ,GAAc,EAAE,CAAC;IAE/B,MAAM,WAAW,GAAG,mBAAmB,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,gBAAgB,CAAC,CAAC;IAE1F,KAAK,MAAM,EAAE,IAAI,WAAW,EAAE,CAAC;QAC7B,6CAA6C;QAC7C,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC;YAAE,SAAS;QAE5C,6BAA6B;QAC7B,IAAI,YAAY,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC;YAAE,SAAS;QAE1D,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;QACzC,IAAI,CAAC,IAAI;YAAE,SAAS;QAEpB,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,EAAE,CAAC,MAAM;YACjB,QAAQ,EAAE,IAAI,CAAC,IAAI;YACnB,KAAK,EAAE,EAAE,CAAC,KAAK;YACf,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,QAAQ,EAAE,EAAE,CAAC,QAAQ;YACrB,QAAQ;YACR,IAAI,EAAE,EAAE,CAAC,IAAI;YACb,MAAM,EAAE,EAAE,CAAC,MAAM;YACjB,OAAO,EAAE,EAAE,CAAC,OAAO;YACnB,OAAO,EAAE,SAAS,EAAE,CAAC,WAAW,EAAE;YAClC,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,UAAU,EAAE,EAAE,CAAC,sBAAsB,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM;YACtD,cAAc,EAAE,KAAK;YACrB,SAAS,EAAE,EAAE,CAAC,SAAS;SACxB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,17 @@
1
+ import type { ScanResult } from '../types/index.js';
2
+ import type { FailOnLevel } from '../types/index.js';
3
+ export interface LLMVerifierOptions {
4
+ apiKey?: string;
5
+ maxCalls?: number;
6
+ projectRoot?: string;
7
+ }
8
+ /**
9
+ * Verify low-confidence (MEDIUM, regex-only) findings using Claude.
10
+ * Returns a new ScanResult with:
11
+ * - Confirmed findings: confidence upgraded, analysisMethod = 'llm'
12
+ * - Rejected findings: removed
13
+ * - HIGH-confidence findings: unchanged (not sent to LLM)
14
+ */
15
+ export declare function verifyFindings(result: ScanResult, sourceMap: Map<string, string[]>, // filePath → source lines
16
+ options?: LLMVerifierOptions, failOn?: FailOnLevel): Promise<ScanResult>;
17
+ //# sourceMappingURL=llm-verifier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-verifier.d.ts","sourceRoot":"","sources":["../../src/analysis/llm-verifier.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAW,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAG7D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAwED;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,UAAU,EAClB,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,0BAA0B;AAC5D,OAAO,GAAE,kBAAuB,EAChC,MAAM,GAAE,WAAqB,GAC5B,OAAO,CAAC,UAAU,CAAC,CAoFrB"}
@@ -0,0 +1,152 @@
1
+ // ============================================================
2
+ // LLM Verifier — uses Claude API to confirm/reject low-confidence findings
3
+ //
4
+ // When --ai-verify is set:
5
+ // 1. Finds all MEDIUM-confidence regex findings
6
+ // 2. Sends code context + rule description to Claude
7
+ // 3. On confirmation → upgrades confidence, sets analysisMethod='llm'
8
+ // 4. On rejection → removes the finding from results
9
+ //
10
+ // Requires ANTHROPIC_API_KEY env var.
11
+ // Results are cached in .owaspscan-cache.json (24hr TTL).
12
+ // ============================================================
13
+ import Anthropic from '@anthropic-ai/sdk';
14
+ import { ResultCache } from './result-cache.js';
15
+ import { buildScanResult } from '../utils/scoring.js';
16
+ function buildPrompt(finding, sourceLines) {
17
+ const startLine = Math.max(0, finding.line - 6);
18
+ const endLine = Math.min(sourceLines.length, finding.line + 5);
19
+ const context = sourceLines.slice(startLine, endLine)
20
+ .map((l, i) => `${startLine + i + 1}: ${l}`)
21
+ .join('\n');
22
+ return `You are a security code reviewer. Analyze this potential vulnerability finding:
23
+
24
+ RULE: ${finding.ruleName} (${finding.ruleId})
25
+ OWASP: ${finding.owasp} | ${finding.cwe}
26
+ SEVERITY: ${finding.severity}
27
+ DESCRIPTION: ${finding.message}
28
+
29
+ CODE CONTEXT (lines ${startLine + 1}-${endLine}):
30
+ \`\`\`
31
+ ${context}
32
+ \`\`\`
33
+
34
+ FLAGGED LINE ${finding.line}: ${finding.snippet}
35
+
36
+ Is this a real vulnerability? Consider:
37
+ 1. Is the flagged code actually reachable/dangerous?
38
+ 2. Is there sanitization, validation, or parameterization nearby?
39
+ 3. Could this be a false positive (e.g., test code, commented out, safe usage)?
40
+
41
+ Respond ONLY with valid JSON (no markdown, no explanation outside JSON):
42
+ {
43
+ "confirmed": <true|false>,
44
+ "confidence": "<HIGH|MEDIUM|LOW>",
45
+ "reason": "<one sentence explanation>",
46
+ "fix": "<optional: brief fix suggestion if confirmed>"
47
+ }`;
48
+ }
49
+ async function callClaude(client, prompt) {
50
+ try {
51
+ const message = await client.messages.create({
52
+ model: 'claude-sonnet-4-6',
53
+ max_tokens: 256,
54
+ messages: [{ role: 'user', content: prompt }],
55
+ });
56
+ const text = message.content
57
+ .filter((b) => b.type === 'text')
58
+ .map((b) => b.text)
59
+ .join('');
60
+ // Extract JSON from response (may have surrounding whitespace)
61
+ const jsonMatch = /\{[\s\S]*\}/.exec(text);
62
+ if (!jsonMatch)
63
+ return null;
64
+ const parsed = JSON.parse(jsonMatch[0]);
65
+ if (typeof parsed.confirmed !== 'boolean')
66
+ return null;
67
+ return parsed;
68
+ }
69
+ catch {
70
+ return null;
71
+ }
72
+ }
73
+ /**
74
+ * Verify low-confidence (MEDIUM, regex-only) findings using Claude.
75
+ * Returns a new ScanResult with:
76
+ * - Confirmed findings: confidence upgraded, analysisMethod = 'llm'
77
+ * - Rejected findings: removed
78
+ * - HIGH-confidence findings: unchanged (not sent to LLM)
79
+ */
80
+ export async function verifyFindings(result, sourceMap, // filePath → source lines
81
+ options = {}, failOn = 'never') {
82
+ const apiKey = options.apiKey ?? process.env['ANTHROPIC_API_KEY'];
83
+ if (!apiKey) {
84
+ process.stderr.write('Warning: --ai-verify requires ANTHROPIC_API_KEY environment variable\n');
85
+ return result;
86
+ }
87
+ const client = new Anthropic({ apiKey });
88
+ const cache = new ResultCache(options.projectRoot ?? process.cwd());
89
+ const maxCalls = options.maxCalls ?? 50;
90
+ let callCount = 0;
91
+ const updatedFiles = await Promise.all(result.files.map(async (fileResult) => {
92
+ const sourceLines = sourceMap.get(fileResult.filePath) ?? [];
93
+ const updatedFindings = [];
94
+ for (const finding of fileResult.findings) {
95
+ // Only verify MEDIUM-confidence regex findings
96
+ if (finding.confidence !== 'MEDIUM' || finding.analysisMethod !== 'regex') {
97
+ updatedFindings.push(finding);
98
+ continue;
99
+ }
100
+ // Check cache first
101
+ const cached = cache.get(finding.ruleId, finding.snippet);
102
+ if (cached) {
103
+ if (cached.confirmed) {
104
+ updatedFindings.push({
105
+ ...finding,
106
+ confidence: cached.confidence,
107
+ analysisMethod: 'llm',
108
+ message: `${finding.message} [AI-verified: ${cached.reason}]`,
109
+ });
110
+ }
111
+ // Rejected → don't add to updatedFindings
112
+ continue;
113
+ }
114
+ // Rate limit
115
+ if (callCount >= maxCalls) {
116
+ updatedFindings.push(finding); // Keep unverified
117
+ continue;
118
+ }
119
+ // Call Claude
120
+ const prompt = buildPrompt(finding, sourceLines);
121
+ const verifyResult = await callClaude(client, prompt);
122
+ callCount++;
123
+ if (!verifyResult) {
124
+ updatedFindings.push(finding); // Keep on API failure
125
+ continue;
126
+ }
127
+ // Cache the result
128
+ cache.set(finding.ruleId, finding.snippet, {
129
+ confirmed: verifyResult.confirmed,
130
+ confidence: verifyResult.confidence,
131
+ reason: verifyResult.reason,
132
+ fix: verifyResult.fix,
133
+ });
134
+ if (verifyResult.confirmed) {
135
+ updatedFindings.push({
136
+ ...finding,
137
+ confidence: verifyResult.confidence,
138
+ analysisMethod: 'llm',
139
+ message: `${finding.message} [AI-verified: ${verifyResult.reason}]`,
140
+ fix: verifyResult.fix ? `${verifyResult.fix}\n\n${finding.fix}` : finding.fix,
141
+ });
142
+ }
143
+ // Rejected → don't add
144
+ }
145
+ return { ...fileResult, findings: updatedFindings };
146
+ }));
147
+ if (callCount > 0) {
148
+ process.stderr.write(`AI verification: ${callCount} findings verified via Claude API\n`);
149
+ }
150
+ return buildScanResult(result.targetPath, updatedFiles, result.scanDurationMs, failOn);
151
+ }
152
+ //# sourceMappingURL=llm-verifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-verifier.js","sourceRoot":"","sources":["../../src/analysis/llm-verifier.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ export interface CacheEntry {
2
+ confirmed: boolean;
3
+ confidence: 'HIGH' | 'MEDIUM' | 'LOW';
4
+ reason: string;
5
+ fix?: string;
6
+ timestamp: number;
7
+ }
8
+ export declare class ResultCache {
9
+ private cacheFile;
10
+ private cache;
11
+ constructor(projectRoot: string);
12
+ private load;
13
+ private persist;
14
+ static hashKey(ruleId: string, snippet: string): string;
15
+ get(ruleId: string, snippet: string): CacheEntry | null;
16
+ set(ruleId: string, snippet: string, entry: Omit<CacheEntry, 'timestamp'>): void;
17
+ /** Remove expired entries and re-save */
18
+ prune(): void;
19
+ }
20
+ //# sourceMappingURL=result-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result-cache.d.ts","sourceRoot":"","sources":["../../src/analysis/result-cache.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAKD,qBAAa,WAAW;IACtB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,KAAK,CAA0B;gBAE3B,WAAW,EAAE,MAAM;IAK/B,OAAO,CAAC,IAAI;IAUZ,OAAO,CAAC,OAAO;IAYf,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM;IAIvD,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAYvD,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,GAAG,IAAI;IAMhF,yCAAyC;IACzC,KAAK,IAAI,IAAI;CAOd"}
@@ -0,0 +1,70 @@
1
+ // ============================================================
2
+ // Result Cache — hash-based caching for LLM verifier results
3
+ // Stored in .owaspscan-cache.json in the project root
4
+ // TTL: 24 hours per entry (re-verify if older)
5
+ // ============================================================
6
+ import fs from 'fs';
7
+ import path from 'path';
8
+ import crypto from 'crypto';
9
+ const CACHE_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours
10
+ const CACHE_FILENAME = '.owaspscan-cache.json';
11
+ export class ResultCache {
12
+ cacheFile;
13
+ cache;
14
+ constructor(projectRoot) {
15
+ this.cacheFile = path.join(projectRoot, CACHE_FILENAME);
16
+ this.cache = this.load();
17
+ }
18
+ load() {
19
+ try {
20
+ const raw = fs.readFileSync(this.cacheFile, 'utf8');
21
+ const obj = JSON.parse(raw);
22
+ return new Map(Object.entries(obj));
23
+ }
24
+ catch {
25
+ return new Map();
26
+ }
27
+ }
28
+ persist() {
29
+ try {
30
+ const obj = {};
31
+ for (const [k, v] of this.cache.entries()) {
32
+ obj[k] = v;
33
+ }
34
+ fs.writeFileSync(this.cacheFile, JSON.stringify(obj, null, 2), 'utf8');
35
+ }
36
+ catch {
37
+ // Non-fatal — cache write failure doesn't break scanning
38
+ }
39
+ }
40
+ static hashKey(ruleId, snippet) {
41
+ return crypto.createHash('sha256').update(`${ruleId}:${snippet}`).digest('hex').slice(0, 32);
42
+ }
43
+ get(ruleId, snippet) {
44
+ const key = ResultCache.hashKey(ruleId, snippet);
45
+ const entry = this.cache.get(key);
46
+ if (!entry)
47
+ return null;
48
+ // Expire after TTL
49
+ if (Date.now() - entry.timestamp > CACHE_TTL_MS) {
50
+ this.cache.delete(key);
51
+ return null;
52
+ }
53
+ return entry;
54
+ }
55
+ set(ruleId, snippet, entry) {
56
+ const key = ResultCache.hashKey(ruleId, snippet);
57
+ this.cache.set(key, { ...entry, timestamp: Date.now() });
58
+ this.persist();
59
+ }
60
+ /** Remove expired entries and re-save */
61
+ prune() {
62
+ const now = Date.now();
63
+ for (const [key, entry] of this.cache.entries()) {
64
+ if (now - entry.timestamp > CACHE_TTL_MS)
65
+ this.cache.delete(key);
66
+ }
67
+ this.persist();
68
+ }
69
+ }
70
+ //# sourceMappingURL=result-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result-cache.js","sourceRoot":"","sources":["../../src/analysis/result-cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { OWASPCategory, Severity } from '../types/index.js';
2
+ export interface SinkDef {
3
+ pattern: RegExp;
4
+ argPattern: RegExp;
5
+ ruleId: string;
6
+ owasp: OWASPCategory;
7
+ severity: Severity;
8
+ description: string;
9
+ languages: ('javascript' | 'typescript' | 'python')[];
10
+ }
11
+ export declare function getSinkPatterns(language: 'javascript' | 'typescript' | 'python'): SinkDef[];
12
+ //# sourceMappingURL=sinks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sinks.d.ts","sourceRoot":"","sources":["../../src/analysis/sinks.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAEjE,MAAM,WAAW,OAAO;IAGtB,OAAO,EAAE,MAAM,CAAC;IAEhB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,aAAa,CAAC;IACrB,QAAQ,EAAE,QAAQ,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,CAAC,YAAY,GAAG,YAAY,GAAG,QAAQ,CAAC,EAAE,CAAC;CACvD;AA0ID,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,YAAY,GAAG,YAAY,GAAG,QAAQ,GAC/C,OAAO,EAAE,CAGX"}
@@ -0,0 +1,142 @@
1
+ // ============================================================
2
+ // Taint Sinks — dangerous functions where tainted data causes harm
3
+ // ============================================================
4
+ const JS_SINKS = [
5
+ // SQL injection sinks
6
+ {
7
+ pattern: /\.(?:query|execute|raw|run)\s*\(/g,
8
+ argPattern: /\.(?:query|execute|raw|run)\s*\(([^)]{0,300})\)/,
9
+ ruleId: 'OWASP-A03-001',
10
+ owasp: 'A03:2021',
11
+ severity: 'CRITICAL',
12
+ description: 'Tainted variable passed to SQL query function',
13
+ languages: ['javascript', 'typescript'],
14
+ },
15
+ // NoSQL injection
16
+ {
17
+ pattern: /\$where\s*:/g,
18
+ argPattern: /\$where\s*:\s*([^,}\n]{0,200})/,
19
+ ruleId: 'OWASP-A03-003',
20
+ owasp: 'A03:2021',
21
+ severity: 'HIGH',
22
+ description: 'Tainted variable used in NoSQL $where clause',
23
+ languages: ['javascript', 'typescript'],
24
+ },
25
+ // Command injection sinks
26
+ {
27
+ pattern: /(?:exec|execSync|spawn|spawnSync|execFile|system)\s*\(/g,
28
+ argPattern: /(?:exec|execSync|spawn|spawnSync|execFile|system)\s*\(([^)]{0,300})\)/,
29
+ ruleId: 'OWASP-A03-002',
30
+ owasp: 'A03:2021',
31
+ severity: 'CRITICAL',
32
+ description: 'Tainted variable passed to shell execution function',
33
+ languages: ['javascript', 'typescript'],
34
+ },
35
+ // SSRF sinks
36
+ {
37
+ pattern: /(?:fetch|axios\.get|axios\.post|http\.get|https\.get|request\.get)\s*\(/g,
38
+ argPattern: /(?:fetch|axios\.get|axios\.post|http\.get|https\.get|request\.get)\s*\(([^)]{0,300})\)/,
39
+ ruleId: 'OWASP-A10-001',
40
+ owasp: 'A10:2021',
41
+ severity: 'HIGH',
42
+ description: 'Tainted variable used in HTTP fetch (potential SSRF)',
43
+ languages: ['javascript', 'typescript'],
44
+ },
45
+ // XSS sinks
46
+ {
47
+ pattern: /(?:innerHTML|outerHTML|document\.write)\s*[=+(]/g,
48
+ argPattern: /(?:innerHTML|outerHTML|document\.write)\s*[=+(]\s*([^;\n]{0,200})/,
49
+ ruleId: 'OWASP-A03-004',
50
+ owasp: 'A03:2021',
51
+ severity: 'HIGH',
52
+ description: 'Tainted variable rendered as HTML (XSS)',
53
+ languages: ['javascript', 'typescript'],
54
+ },
55
+ // eval / Function constructor
56
+ {
57
+ pattern: /(?:eval|new Function)\s*\(/g,
58
+ argPattern: /(?:eval|new Function)\s*\(([^)]{0,300})\)/,
59
+ ruleId: 'OWASP-A08-001',
60
+ owasp: 'A08:2021',
61
+ severity: 'CRITICAL',
62
+ description: 'Tainted variable passed to eval() (code injection)',
63
+ languages: ['javascript', 'typescript'],
64
+ },
65
+ // Path traversal (fs operations with user input)
66
+ {
67
+ pattern: /(?:readFile|writeFile|unlink|readdir|stat|open)(?:Sync)?\s*\(/g,
68
+ argPattern: /(?:readFile|writeFile|unlink|readdir|stat|open)(?:Sync)?\s*\(([^)]{0,300})\)/,
69
+ ruleId: 'OWASP-A01-002',
70
+ owasp: 'A01:2021',
71
+ severity: 'HIGH',
72
+ description: 'Tainted variable used as file path (path traversal)',
73
+ languages: ['javascript', 'typescript'],
74
+ },
75
+ ];
76
+ const PYTHON_SINKS = [
77
+ // SQL injection
78
+ {
79
+ pattern: /(?:execute|executemany|raw|cursor\.execute)\s*\(/g,
80
+ argPattern: /(?:execute|executemany|raw|cursor\.execute)\s*\(([^)]{0,300})\)/,
81
+ ruleId: 'OWASP-A03-001',
82
+ owasp: 'A03:2021',
83
+ severity: 'CRITICAL',
84
+ description: 'Tainted variable passed to SQL execute function',
85
+ languages: ['python'],
86
+ },
87
+ // Command injection
88
+ {
89
+ pattern: /(?:os\.system|subprocess\.(?:call|run|Popen|check_output)|commands\.getoutput)\s*\(/g,
90
+ argPattern: /(?:os\.system|subprocess\.(?:call|run|Popen|check_output)|commands\.getoutput)\s*\(([^)]{0,300})\)/,
91
+ ruleId: 'OWASP-A03-002',
92
+ owasp: 'A03:2021',
93
+ severity: 'CRITICAL',
94
+ description: 'Tainted variable passed to shell command (command injection)',
95
+ languages: ['python'],
96
+ },
97
+ // SSRF
98
+ {
99
+ pattern: /(?:requests\.(?:get|post|put|delete)|urllib\.request\.urlopen|urlopen)\s*\(/g,
100
+ argPattern: /(?:requests\.(?:get|post|put|delete)|urllib\.request\.urlopen|urlopen)\s*\(([^)]{0,300})\)/,
101
+ ruleId: 'OWASP-A10-001',
102
+ owasp: 'A10:2021',
103
+ severity: 'HIGH',
104
+ description: 'Tainted variable used in HTTP request (potential SSRF)',
105
+ languages: ['python'],
106
+ },
107
+ // eval / exec
108
+ {
109
+ pattern: /(?:^|\s)(?:eval|exec)\s*\(/gm,
110
+ argPattern: /(?:eval|exec)\s*\(([^)]{0,300})\)/,
111
+ ruleId: 'OWASP-A08-001',
112
+ owasp: 'A08:2021',
113
+ severity: 'CRITICAL',
114
+ description: 'Tainted variable passed to eval/exec (code injection)',
115
+ languages: ['python'],
116
+ },
117
+ // Template injection
118
+ {
119
+ pattern: /(?:render_template_string|Template)\s*\(/g,
120
+ argPattern: /(?:render_template_string|Template)\s*\(([^)]{0,300})\)/,
121
+ ruleId: 'OWASP-A03-005',
122
+ owasp: 'A03:2021',
123
+ severity: 'HIGH',
124
+ description: 'Tainted variable used in template (SSTI)',
125
+ languages: ['python'],
126
+ },
127
+ // Path traversal
128
+ {
129
+ pattern: /(?:open|os\.path\.join|pathlib\.Path)\s*\(/g,
130
+ argPattern: /(?:open|os\.path\.join|pathlib\.Path)\s*\(([^)]{0,300})\)/,
131
+ ruleId: 'OWASP-A01-002',
132
+ owasp: 'A01:2021',
133
+ severity: 'HIGH',
134
+ description: 'Tainted variable used as file path (path traversal)',
135
+ languages: ['python'],
136
+ },
137
+ ];
138
+ export function getSinkPatterns(language) {
139
+ const all = [...JS_SINKS, ...PYTHON_SINKS];
140
+ return all.filter((s) => s.languages.includes(language));
141
+ }
142
+ //# sourceMappingURL=sinks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sinks.js","sourceRoot":"","sources":["../../src/analysis/sinks.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,mEAAmE;AACnE,+DAA+D;AAiB/D,MAAM,QAAQ,GAAc;IAC1B,sBAAsB;IACtB;QACE,OAAO,EAAE,mCAAmC;QAC5C,UAAU,EAAE,iDAAiD;QAC7D,MAAM,EAAE,eAAe;QACvB,KAAK,EAAE,UAAU;QACjB,QAAQ,EAAE,UAAU;QACpB,WAAW,EAAE,+CAA+C;QAC5D,SAAS,EAAE,CAAC,YAAY,EAAE,YAAY,CAAC;KACxC;IACD,kBAAkB;IAClB;QACE,OAAO,EAAE,cAAc;QACvB,UAAU,EAAE,gCAAgC;QAC5C,MAAM,EAAE,eAAe;QACvB,KAAK,EAAE,UAAU;QACjB,QAAQ,EAAE,MAAM;QAChB,WAAW,EAAE,8CAA8C;QAC3D,SAAS,EAAE,CAAC,YAAY,EAAE,YAAY,CAAC;KACxC;IACD,0BAA0B;IAC1B;QACE,OAAO,EAAE,yDAAyD;QAClE,UAAU,EAAE,uEAAuE;QACnF,MAAM,EAAE,eAAe;QACvB,KAAK,EAAE,UAAU;QACjB,QAAQ,EAAE,UAAU;QACpB,WAAW,EAAE,qDAAqD;QAClE,SAAS,EAAE,CAAC,YAAY,EAAE,YAAY,CAAC;KACxC;IACD,aAAa;IACb;QACE,OAAO,EAAE,0EAA0E;QACnF,UAAU,EAAE,wFAAwF;QACpG,MAAM,EAAE,eAAe;QACvB,KAAK,EAAE,UAAU;QACjB,QAAQ,EAAE,MAAM;QAChB,WAAW,EAAE,sDAAsD;QACnE,SAAS,EAAE,CAAC,YAAY,EAAE,YAAY,CAAC;KACxC;IACD,YAAY;IACZ;QACE,OAAO,EAAE,kDAAkD;QAC3D,UAAU,EAAE,mEAAmE;QAC/E,MAAM,EAAE,eAAe;QACvB,KAAK,EAAE,UAAU;QACjB,QAAQ,EAAE,MAAM;QAChB,WAAW,EAAE,yCAAyC;QACtD,SAAS,EAAE,CAAC,YAAY,EAAE,YAAY,CAAC;KACxC;IACD,8BAA8B;IAC9B;QACE,OAAO,EAAE,6BAA6B;QACtC,UAAU,EAAE,2CAA2C;QACvD,MAAM,EAAE,eAAe;QACvB,KAAK,EAAE,UAAU;QACjB,QAAQ,EAAE,UAAU;QACpB,WAAW,EAAE,oDAAoD;QACjE,SAAS,EAAE,CAAC,YAAY,EAAE,YAAY,CAAC;KACxC;IACD,iDAAiD;IACjD;QACE,OAAO,EAAE,gEAAgE;QACzE,UAAU,EAAE,8EAA8E;QAC1F,MAAM,EAAE,eAAe;QACvB,KAAK,EAAE,UAAU;QACjB,QAAQ,EAAE,MAAM;QAChB,WAAW,EAAE,qDAAqD;QAClE,SAAS,EAAE,CAAC,YAAY,EAAE,YAAY,CAAC;KACxC;CACF,CAAC;AAEF,MAAM,YAAY,GAAc;IAC9B,gBAAgB;IAChB;QACE,OAAO,EAAE,mDAAmD;QAC5D,UAAU,EAAE,iEAAiE;QAC7E,MAAM,EAAE,eAAe;QACvB,KAAK,EAAE,UAAU;QACjB,QAAQ,EAAE,UAAU;QACpB,WAAW,EAAE,iDAAiD;QAC9D,SAAS,EAAE,CAAC,QAAQ,CAAC;KACtB;IACD,oBAAoB;IACpB;QACE,OAAO,EAAE,sFAAsF;QAC/F,UAAU,EAAE,oGAAoG;QAChH,MAAM,EAAE,eAAe;QACvB,KAAK,EAAE,UAAU;QACjB,QAAQ,EAAE,UAAU;QACpB,WAAW,EAAE,8DAA8D;QAC3E,SAAS,EAAE,CAAC,QAAQ,CAAC;KACtB;IACD,OAAO;IACP;QACE,OAAO,EAAE,8EAA8E;QACvF,UAAU,EAAE,4FAA4F;QACxG,MAAM,EAAE,eAAe;QACvB,KAAK,EAAE,UAAU;QACjB,QAAQ,EAAE,MAAM;QAChB,WAAW,EAAE,wDAAwD;QACrE,SAAS,EAAE,CAAC,QAAQ,CAAC;KACtB;IACD,cAAc;IACd;QACE,OAAO,EAAE,8BAA8B;QACvC,UAAU,EAAE,mCAAmC;QAC/C,MAAM,EAAE,eAAe;QACvB,KAAK,EAAE,UAAU;QACjB,QAAQ,EAAE,UAAU;QACpB,WAAW,EAAE,uDAAuD;QACpE,SAAS,EAAE,CAAC,QAAQ,CAAC;KACtB;IACD,qBAAqB;IACrB;QACE,OAAO,EAAE,2CAA2C;QACpD,UAAU,EAAE,yDAAyD;QACrE,MAAM,EAAE,eAAe;QACvB,KAAK,EAAE,UAAU;QACjB,QAAQ,EAAE,MAAM;QAChB,WAAW,EAAE,0CAA0C;QACvD,SAAS,EAAE,CAAC,QAAQ,CAAC;KACtB;IACD,iBAAiB;IACjB;QACE,OAAO,EAAE,6CAA6C;QACtD,UAAU,EAAE,2DAA2D;QACvE,MAAM,EAAE,eAAe;QACvB,KAAK,EAAE,UAAU;QACjB,QAAQ,EAAE,MAAM;QAChB,WAAW,EAAE,qDAAqD;QAClE,SAAS,EAAE,CAAC,QAAQ,CAAC;KACtB;CACF,CAAC;AAEF,MAAM,UAAU,eAAe,CAC7B,QAAgD;IAEhD,MAAM,GAAG,GAAG,CAAC,GAAG,QAAQ,EAAE,GAAG,YAAY,CAAC,CAAC;IAC3C,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC3D,CAAC"}
@@ -0,0 +1,8 @@
1
+ export interface SourceDef {
2
+ pattern: RegExp;
3
+ description: string;
4
+ languages: ('javascript' | 'typescript' | 'python')[];
5
+ }
6
+ export declare function getSourcePatterns(language: 'javascript' | 'typescript' | 'python'): SourceDef[];
7
+ export declare function extractTaintedVars(code: string, language: 'javascript' | 'typescript' | 'python'): Map<string, string>;
8
+ //# sourceMappingURL=sources.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sources.d.ts","sourceRoot":"","sources":["../../src/analysis/sources.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,SAAS;IAGxB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,CAAC,YAAY,GAAG,YAAY,GAAG,QAAQ,CAAC,EAAE,CAAC;CACvD;AAwFD,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,YAAY,GAAG,YAAY,GAAG,QAAQ,GAC/C,SAAS,EAAE,CAGb;AAGD,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,YAAY,GAAG,YAAY,GAAG,QAAQ,GAC/C,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAsBrB"}