@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,114 @@
1
+ // ============================================================
2
+ // Taint Sources — definitions of where user-controlled input enters
3
+ // ============================================================
4
+ // JavaScript / TypeScript taint sources
5
+ const JS_SOURCES = [
6
+ // req.query.*, req.body.*, req.params.*
7
+ {
8
+ pattern: /(?:const|let|var)\s+(\w+)\s*=\s*req(?:uest)?\.(?:query|body|params)\b/g,
9
+ description: 'HTTP request query/body/params',
10
+ languages: ['javascript', 'typescript'],
11
+ },
12
+ // Destructured: const { id } = req.query
13
+ {
14
+ pattern: /(?:const|let|var)\s*\{([^}]+)\}\s*=\s*req(?:uest)?\.(?:query|body|params)\b/g,
15
+ description: 'Destructured HTTP request input',
16
+ languages: ['javascript', 'typescript'],
17
+ },
18
+ // req.query directly used (no assignment)
19
+ {
20
+ pattern: /(?:const|let|var)\s+(\w+)\s*=\s*req(?:uest)?\.(?:query|body|params)\.(\w+)/g,
21
+ description: 'HTTP request field',
22
+ languages: ['javascript', 'typescript'],
23
+ },
24
+ // process.argv
25
+ {
26
+ pattern: /(?:const|let|var)\s+(\w+)\s*=\s*process\.argv\b/g,
27
+ description: 'CLI argument input',
28
+ languages: ['javascript', 'typescript'],
29
+ },
30
+ // readFileSync / readFile with user-controlled path
31
+ {
32
+ pattern: /(?:const|let|var)\s+(\w+)\s*=\s*(?:fs\.)?readFileSync\s*\(/g,
33
+ description: 'File read result',
34
+ languages: ['javascript', 'typescript'],
35
+ },
36
+ // event.target.value (browser DOM)
37
+ {
38
+ pattern: /(?:const|let|var)\s+(\w+)\s*=\s*(?:event|e)\.target\.value\b/g,
39
+ description: 'DOM input value',
40
+ languages: ['javascript', 'typescript'],
41
+ },
42
+ // localStorage / sessionStorage
43
+ {
44
+ pattern: /(?:const|let|var)\s+(\w+)\s*=\s*(?:localStorage|sessionStorage)\.getItem\s*\(/g,
45
+ description: 'Browser storage value',
46
+ languages: ['javascript', 'typescript'],
47
+ },
48
+ // URLSearchParams
49
+ {
50
+ pattern: /(?:const|let|var)\s+(\w+)\s*=\s*(?:new URLSearchParams|searchParams\.get)\s*\(/g,
51
+ description: 'URL search param',
52
+ languages: ['javascript', 'typescript'],
53
+ },
54
+ ];
55
+ // Python taint sources
56
+ const PYTHON_SOURCES = [
57
+ // Flask: request.args.get, request.form.get, request.json
58
+ {
59
+ pattern: /(\w+)\s*=\s*request\.(?:args|form|json|values|data|files)(?:\.get\s*\(|\[)/g,
60
+ description: 'Flask HTTP request input',
61
+ languages: ['python'],
62
+ },
63
+ // Django: request.GET, request.POST, request.body
64
+ {
65
+ pattern: /(\w+)\s*=\s*request\.(?:GET|POST|body|data)\s*(?:\.get\s*\(|\[)/g,
66
+ description: 'Django HTTP request input',
67
+ languages: ['python'],
68
+ },
69
+ // input() function
70
+ {
71
+ pattern: /(\w+)\s*=\s*input\s*\(/g,
72
+ description: 'User terminal input',
73
+ languages: ['python'],
74
+ },
75
+ // sys.argv
76
+ {
77
+ pattern: /(\w+)\s*=\s*sys\.argv\b/g,
78
+ description: 'CLI argument input',
79
+ languages: ['python'],
80
+ },
81
+ // FastAPI / path param
82
+ {
83
+ pattern: /async\s+def\s+\w+\s*\([^)]*(\w+)\s*:/g,
84
+ description: 'FastAPI route parameter',
85
+ languages: ['python'],
86
+ },
87
+ ];
88
+ export function getSourcePatterns(language) {
89
+ const all = [...JS_SOURCES, ...PYTHON_SOURCES];
90
+ return all.filter((s) => s.languages.includes(language));
91
+ }
92
+ // Extract tainted variable names from a block of code
93
+ export function extractTaintedVars(code, language) {
94
+ const tainted = new Map(); // varName → source description
95
+ const sources = getSourcePatterns(language);
96
+ for (const source of sources) {
97
+ // Reset lastIndex for global regexes
98
+ source.pattern.lastIndex = 0;
99
+ let match;
100
+ while ((match = source.pattern.exec(code)) !== null) {
101
+ // For destructured: capture group 1 might be "id, name" — split and add all
102
+ const captured = match[1] ?? '';
103
+ const varNames = captured.split(',').map((v) => v.trim().split(':')[0].trim());
104
+ for (const v of varNames) {
105
+ if (v && /^\w+$/.test(v)) {
106
+ tainted.set(v, source.description);
107
+ }
108
+ }
109
+ }
110
+ source.pattern.lastIndex = 0;
111
+ }
112
+ return tainted;
113
+ }
114
+ //# sourceMappingURL=sources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sources.js","sourceRoot":"","sources":["../../src/analysis/sources.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { Finding, Rule } from '../types/index.js';
2
+ type TaintLanguage = 'javascript' | 'typescript' | 'python';
3
+ export declare function analyzeTaint(code: string, language: TaintLanguage, filePath: string, rules: Rule[]): Finding[];
4
+ export {};
5
+ //# sourceMappingURL=taint-engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"taint-engine.d.ts","sourceRoot":"","sources":["../../src/analysis/taint-engine.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAMvD,KAAK,aAAa,GAAG,YAAY,GAAG,YAAY,GAAG,QAAQ,CAAC;AAgI5D,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,aAAa,EACvB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,IAAI,EAAE,GACZ,OAAO,EAAE,CA6EX"}
@@ -0,0 +1,187 @@
1
+ // ============================================================
2
+ // Taint Engine — intra-procedural data flow / taint analysis
3
+ //
4
+ // Strategy:
5
+ // 1. Extract taint sources (variables assigned from user input)
6
+ // 2. Propagate taint through assignment chains within the same scope
7
+ // 3. Detect tainted variables reaching dangerous sinks
8
+ //
9
+ // Limitation: intra-procedural only (single file / function scope).
10
+ // Inter-procedural taint (across function calls) is not tracked.
11
+ // ============================================================
12
+ import { extractTaintedVars } from './sources.js';
13
+ import { getSinkPatterns } from './sinks.js';
14
+ import { isSuppressed } from '../utils/suppression.js';
15
+ import { registry } from '../rules/registry.js';
16
+ // Propagate taint through assignment statements.
17
+ // e.g. if userId is tainted and we see: const q = userId + " extra",
18
+ // then q becomes tainted too.
19
+ function propagateTaint(code, tainted, language) {
20
+ const lines = code.split('\n');
21
+ let changed = true;
22
+ // Keep iterating until no new variables become tainted (fixed-point)
23
+ let iterations = 0;
24
+ while (changed && iterations < 10) {
25
+ changed = false;
26
+ iterations++;
27
+ for (const line of lines) {
28
+ const trimmed = line.trim();
29
+ // Skip comment lines
30
+ if (trimmed.startsWith('//') ||
31
+ trimmed.startsWith('#') ||
32
+ trimmed.startsWith('*') ||
33
+ trimmed.startsWith('/*')) {
34
+ continue;
35
+ }
36
+ // JavaScript/TypeScript assignment: const/let/var varName = ... taintedVar ...
37
+ if (language === 'javascript' || language === 'typescript') {
38
+ const assignMatch = /(?:const|let|var)\s+(\w+)\s*=\s*(.+)/.exec(trimmed);
39
+ if (assignMatch) {
40
+ const newVar = assignMatch[1];
41
+ const rhs = assignMatch[2];
42
+ if (!tainted.has(newVar)) {
43
+ for (const [taintedVar] of tainted) {
44
+ // Check if the tainted variable appears in the RHS
45
+ if (new RegExp(`\\b${taintedVar}\\b`).test(rhs)) {
46
+ tainted.set(newVar, `derived from ${taintedVar}`);
47
+ changed = true;
48
+ break;
49
+ }
50
+ }
51
+ }
52
+ }
53
+ // Simple reassignment: varName = ... taintedVar ...
54
+ const reassignMatch = /^(\w+)\s*=\s*(.+)/.exec(trimmed);
55
+ if (reassignMatch && !['if', 'while', 'for', 'return', 'const', 'let', 'var'].includes(reassignMatch[1])) {
56
+ const newVar = reassignMatch[1];
57
+ const rhs = reassignMatch[2];
58
+ if (!tainted.has(newVar)) {
59
+ for (const [taintedVar] of tainted) {
60
+ if (new RegExp(`\\b${taintedVar}\\b`).test(rhs)) {
61
+ tainted.set(newVar, `derived from ${taintedVar}`);
62
+ changed = true;
63
+ break;
64
+ }
65
+ }
66
+ }
67
+ }
68
+ // Template literal assignment: const q = `... ${taintedVar} ...`
69
+ const templateMatch = /(?:const|let|var)\s+(\w+)\s*=\s*`([^`]*)`;?/.exec(trimmed);
70
+ if (templateMatch) {
71
+ const newVar = templateMatch[1];
72
+ const template = templateMatch[2];
73
+ if (!tainted.has(newVar)) {
74
+ for (const [taintedVar] of tainted) {
75
+ if (template.includes(`\${${taintedVar}}`)) {
76
+ tainted.set(newVar, `derived from ${taintedVar} (template)`);
77
+ changed = true;
78
+ break;
79
+ }
80
+ }
81
+ }
82
+ }
83
+ }
84
+ // Python assignment: varName = ... taintedVar ...
85
+ if (language === 'python') {
86
+ const assignMatch = /^(\w+)\s*=\s*(.+)/.exec(trimmed);
87
+ if (assignMatch && !['if', 'while', 'for', 'return', 'def', 'class', 'import'].includes(assignMatch[1])) {
88
+ const newVar = assignMatch[1];
89
+ const rhs = assignMatch[2];
90
+ if (!tainted.has(newVar)) {
91
+ for (const [taintedVar] of tainted) {
92
+ if (new RegExp(`\\b${taintedVar}\\b`).test(rhs)) {
93
+ tainted.set(newVar, `derived from ${taintedVar}`);
94
+ changed = true;
95
+ break;
96
+ }
97
+ }
98
+ }
99
+ }
100
+ }
101
+ }
102
+ }
103
+ }
104
+ // Check if a sink's argument string contains a tainted variable
105
+ function sinkArgContainsTainted(argStr, tainted) {
106
+ for (const [taintedVar] of tainted) {
107
+ if (new RegExp(`\\b${taintedVar}\\b`).test(argStr)) {
108
+ return taintedVar;
109
+ }
110
+ }
111
+ return null;
112
+ }
113
+ // Get line number (1-based) for a character offset in source
114
+ function getLineNumber(source, offset) {
115
+ return source.slice(0, offset).split('\n').length;
116
+ }
117
+ // Get line content at a given 1-based line number
118
+ function getLineContent(lines, lineNum) {
119
+ return lines[lineNum - 1] ?? '';
120
+ }
121
+ export function analyzeTaint(code, language, filePath, rules) {
122
+ const findings = [];
123
+ // Build the set of rule IDs we're scanning for
124
+ const activeRuleIds = new Set(rules.map((r) => r.id));
125
+ // Step 1: Extract initial taint sources
126
+ const tainted = extractTaintedVars(code, language);
127
+ // Step 2: Propagate taint through assignments
128
+ propagateTaint(code, tainted, language);
129
+ if (tainted.size === 0) {
130
+ return findings; // Nothing tainted — no need to check sinks
131
+ }
132
+ // Step 3: Check sinks
133
+ const sinks = getSinkPatterns(language);
134
+ const lines = code.split('\n');
135
+ for (const sink of sinks) {
136
+ // Skip sinks whose rule isn't in the active rule set
137
+ if (!activeRuleIds.has(sink.ruleId))
138
+ continue;
139
+ // Find the rule definition
140
+ const rule = registry.getById(sink.ruleId);
141
+ if (!rule)
142
+ continue;
143
+ // Reset lastIndex
144
+ sink.pattern.lastIndex = 0;
145
+ let match;
146
+ while ((match = sink.pattern.exec(code)) !== null) {
147
+ const offset = match.index;
148
+ const lineNum = getLineNumber(code, offset);
149
+ // Check suppression
150
+ if (isSuppressed(lines, lineNum - 1, sink.ruleId))
151
+ continue;
152
+ // Extract the argument to the sink call
153
+ const lineContent = getLineContent(lines, lineNum);
154
+ const argMatch = sink.argPattern.exec(lineContent);
155
+ const argStr = argMatch ? argMatch[1] ?? '' : lineContent;
156
+ // Check if the arg contains a tainted variable
157
+ const taintedVar = sinkArgContainsTainted(argStr, tainted);
158
+ if (taintedVar !== null) {
159
+ const sourceDesc = tainted.get(taintedVar) ?? 'user input';
160
+ const taintPath = [
161
+ `Source: '${taintedVar}' from ${sourceDesc}`,
162
+ `Sink: line ${lineNum} — ${sink.description}`,
163
+ ];
164
+ findings.push({
165
+ ruleId: sink.ruleId,
166
+ ruleName: rule.name,
167
+ owasp: sink.owasp,
168
+ cwe: rule.cwe,
169
+ severity: sink.severity,
170
+ filePath,
171
+ line: lineNum,
172
+ column: 1,
173
+ snippet: lineContent.trim(),
174
+ message: `[TAINT] ${sink.description} — variable '${taintedVar}' originates from ${sourceDesc}`,
175
+ fix: rule.fix,
176
+ references: rule.references,
177
+ confidence: 'HIGH',
178
+ analysisMethod: 'taint',
179
+ taintPath,
180
+ });
181
+ }
182
+ }
183
+ sink.pattern.lastIndex = 0;
184
+ }
185
+ return findings;
186
+ }
187
+ //# sourceMappingURL=taint-engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"taint-engine.js","sourceRoot":"","sources":["../../src/analysis/taint-engine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,227 @@
1
+ #!/usr/bin/env node
2
+ // ============================================================
3
+ // OWASPScan CLI — Professional OWASP Security Auditor
4
+ // ============================================================
5
+ import { Command } from 'commander';
6
+ import path from 'path';
7
+ import process from 'process';
8
+ import { scanDirectory, scanCode, registry } from '../scanner/engine.js';
9
+ import { reportConsole } from '../reporter/console.js';
10
+ import { reportJson } from '../reporter/json.js';
11
+ import { reportSarif } from '../reporter/sarif.js';
12
+ import { reportLlm } from '../reporter/llm.js';
13
+ import { filterScanResultByConfidence } from '../utils/scoring.js';
14
+ import { loadConfig } from '../config/loader.js';
15
+ import { verifyFindings } from '../analysis/llm-verifier.js';
16
+ import { readFileSafe } from '../scanner/file-walker.js';
17
+ const VERSION = '1.0.0';
18
+ const program = new Command();
19
+ program
20
+ .name('owaspscan')
21
+ .description('OWASPScan — Security code auditor covering OWASP Top 10 + LLM Top 10.\n' +
22
+ 'Detects security vulnerabilities in AI-generated and human-written code.')
23
+ .version(VERSION, '-v, --version');
24
+ // ─── Scan command (default) ───────────────────────────────────────────────
25
+ program
26
+ .command('scan [target]', { isDefault: true })
27
+ .description('Scan a file or directory for security vulnerabilities')
28
+ .option('-r, --rules <categories>', 'Comma-separated OWASP categories to check (e.g. A01,A03,LLM01)')
29
+ .option('-f, --format <format>', 'Output format: console, json, sarif, llm')
30
+ .option('--fail-on <severity>', 'Exit code 1 if findings at this severity or above: critical, high, medium, low, never')
31
+ .option('--no-recursive', 'Do not scan subdirectories recursively')
32
+ .option('--exclude <patterns>', 'Comma-separated glob patterns to exclude')
33
+ .option('--verbose', 'Show fix suggestions and references for each finding')
34
+ .option('--no-color', 'Disable colored output', false)
35
+ .option('--max-findings <n>', 'Stop scanning after N findings', parseInt)
36
+ .option('--min-confidence <level>', 'Minimum confidence level to report: HIGH, MEDIUM, LOW')
37
+ .option('--sca', 'Run SCA dependency scanning against OSV CVE database')
38
+ .option('--ai-verify', 'Use Claude AI to verify low-confidence findings (requires ANTHROPIC_API_KEY)')
39
+ .option('--ai-verify-limit <n>', 'Max Claude API calls per scan (default: 50)', parseInt)
40
+ .option('--config <path>', 'Path to owaspscan.config.json (auto-discovered if not set)')
41
+ .option('--mcp', 'Start as MCP server instead of scanning')
42
+ .action(async (target, options) => {
43
+ // MCP server mode
44
+ if (options.mcp) {
45
+ await import('../mcp/server.js');
46
+ return;
47
+ }
48
+ const targetPath = target ? path.resolve(target) : process.cwd();
49
+ // Load config file, then override with explicitly-set CLI flags only
50
+ // Undefined CLI options fall back to config file, which falls back to defaults
51
+ const cfg = loadConfig({
52
+ rules: options.rules ? options.rules.split(',').map((r) => r.trim()).filter(Boolean) : undefined,
53
+ exclude: options.exclude ? options.exclude.split(',').map((e) => e.trim()).filter(Boolean) : undefined,
54
+ failOn: options.failOn,
55
+ format: options.format,
56
+ verbose: options.verbose,
57
+ minConfidence: options.minConfidence
58
+ ? options.minConfidence.toUpperCase()
59
+ : undefined,
60
+ sca: options.sca,
61
+ aiVerify: options.aiVerify,
62
+ aiVerifyLimit: options.aiVerifyLimit,
63
+ }, options.config, path.dirname(targetPath));
64
+ const format = cfg.format;
65
+ const failOn = cfg.failOn;
66
+ const rules = cfg.rules.length > 0 ? cfg.rules : undefined;
67
+ const exclude = cfg.exclude.length > 0 ? cfg.exclude : undefined;
68
+ const noColor = !options.color;
69
+ const minConfidence = cfg.minConfidence;
70
+ if (!['HIGH', 'MEDIUM', 'LOW'].includes(minConfidence)) {
71
+ process.stderr.write(`Invalid minConfidence: ${minConfidence}. Must be: HIGH, MEDIUM, LOW\n`);
72
+ process.exit(1);
73
+ }
74
+ // Validate format
75
+ if (!['console', 'json', 'sarif', 'llm'].includes(format)) {
76
+ process.stderr.write(`Invalid format: ${format}. Must be: console, json, sarif, llm\n`);
77
+ process.exit(1);
78
+ }
79
+ // Validate failOn
80
+ if (!['critical', 'high', 'medium', 'low', 'never'].includes(failOn)) {
81
+ process.stderr.write(`Invalid --fail-on value: ${failOn}. Must be: critical, high, medium, low, never\n`);
82
+ process.exit(1);
83
+ }
84
+ if (format === 'console' && !noColor) {
85
+ const totalRules = registry.size();
86
+ const coreCount = registry.coreRuleCount;
87
+ const proCount = totalRules - coreCount;
88
+ const rulesLabel = proCount > 0
89
+ ? `${coreCount} (core) + ${proCount} (pro) = ${totalRules} total`
90
+ : `${coreCount} rules (core)`;
91
+ process.stdout.write(`\nOWASPScan v${VERSION} — Scanning ${targetPath}\n`);
92
+ process.stdout.write(`Rules: ${rules?.join(', ') ?? rulesLabel} | Format: ${format} | Fail-on: ${failOn}\n`);
93
+ }
94
+ let progressInterval;
95
+ let lastProgress = '';
96
+ if (format === 'console') {
97
+ progressInterval = setInterval(() => {
98
+ if (lastProgress) {
99
+ process.stderr.write(`\r Scanning: ${lastProgress.slice(-60)} `);
100
+ }
101
+ }, 200);
102
+ }
103
+ try {
104
+ const result = await scanDirectory(targetPath, {
105
+ rules,
106
+ exclude,
107
+ recursive: options.recursive,
108
+ failOn,
109
+ verbose: cfg.verbose,
110
+ maxFindings: options.maxFindings,
111
+ sca: cfg.sca,
112
+ }, (_current, _total, filePath) => {
113
+ lastProgress = filePath;
114
+ });
115
+ if (progressInterval) {
116
+ clearInterval(progressInterval);
117
+ process.stderr.write('\r' + ' '.repeat(80) + '\r');
118
+ }
119
+ // AI verification (opt-in): verify MEDIUM-confidence regex findings via Claude
120
+ let verifiedResult = result;
121
+ if (cfg.aiVerify || options.aiVerify) {
122
+ const sourceMap = new Map();
123
+ for (const fileResult of result.files) {
124
+ const content = readFileSafe(fileResult.filePath);
125
+ if (content)
126
+ sourceMap.set(fileResult.filePath, content.split('\n'));
127
+ }
128
+ verifiedResult = await verifyFindings(result, sourceMap, {
129
+ maxCalls: options.aiVerifyLimit ?? cfg.aiVerifyLimit,
130
+ projectRoot: targetPath,
131
+ }, failOn);
132
+ }
133
+ // Apply confidence filter if requested
134
+ const filteredResult = minConfidence !== 'LOW'
135
+ ? filterScanResultByConfidence(verifiedResult, minConfidence, failOn)
136
+ : verifiedResult;
137
+ switch (format) {
138
+ case 'json':
139
+ process.stdout.write(reportJson(filteredResult) + '\n');
140
+ break;
141
+ case 'sarif':
142
+ process.stdout.write(reportSarif(filteredResult) + '\n');
143
+ break;
144
+ case 'llm':
145
+ process.stdout.write(reportLlm(filteredResult) + '\n');
146
+ break;
147
+ case 'console':
148
+ default:
149
+ reportConsole(filteredResult, {
150
+ verbose: cfg.verbose,
151
+ noColor,
152
+ showFix: cfg.verbose,
153
+ });
154
+ break;
155
+ }
156
+ // Exit code based on fail-on threshold
157
+ if (!filteredResult.passed) {
158
+ process.exit(1);
159
+ }
160
+ }
161
+ catch (err) {
162
+ if (progressInterval)
163
+ clearInterval(progressInterval);
164
+ process.stderr.write(`Error: ${String(err)}\n`);
165
+ process.exit(2);
166
+ }
167
+ });
168
+ // ─── Rules command — list all available rules ─────────────────────────────
169
+ program
170
+ .command('rules')
171
+ .description('List all available security rules')
172
+ .option('--category <category>', 'Filter by OWASP category (e.g. A01, LLM01, EXTRA)')
173
+ .option('--severity <severity>', 'Filter by severity (CRITICAL, HIGH, MEDIUM, LOW, INFO)')
174
+ .option('--json', 'Output as JSON')
175
+ .action((options) => {
176
+ let rules = registry.getAll();
177
+ if (options.category) {
178
+ rules = registry.filterByCategories([options.category]);
179
+ }
180
+ if (options.severity) {
181
+ const sevOrder = { CRITICAL: 5, HIGH: 4, MEDIUM: 3, LOW: 2, INFO: 1 };
182
+ const minSev = sevOrder[options.severity.toUpperCase()] ?? 0;
183
+ rules = rules.filter((r) => (sevOrder[r.severity] ?? 0) >= minSev);
184
+ }
185
+ if (options.json) {
186
+ process.stdout.write(JSON.stringify(rules, null, 2) + '\n');
187
+ return;
188
+ }
189
+ process.stdout.write(`\nOWASPScan — ${rules.length} security rules\n\n`);
190
+ for (const rule of rules) {
191
+ process.stdout.write(` [${rule.severity.padEnd(8)}] ${rule.id.padEnd(20)} ${rule.owasp.padEnd(12)} ${rule.name}\n`);
192
+ }
193
+ process.stdout.write('\n');
194
+ });
195
+ // ─── Check command — scan a code snippet from stdin ───────────────────────
196
+ program
197
+ .command('check')
198
+ .description('Scan code from stdin (pipe code into owaspscan check --lang typescript)')
199
+ .requiredOption('--lang <language>', 'Language of the code (javascript, typescript, python, java, go, php, ruby)')
200
+ .option('--format <format>', 'Output format', 'console')
201
+ .option('--no-color', 'Disable color output')
202
+ .action(async (options) => {
203
+ const chunks = [];
204
+ for await (const chunk of process.stdin) {
205
+ chunks.push(chunk);
206
+ }
207
+ const code = Buffer.concat(chunks).toString('utf8');
208
+ if (!code.trim()) {
209
+ process.stderr.write('No code received on stdin.\n');
210
+ process.exit(1);
211
+ }
212
+ const result = await scanCode(code, options.lang, '<stdin>');
213
+ switch (options.format) {
214
+ case 'json':
215
+ process.stdout.write(reportJson(result) + '\n');
216
+ break;
217
+ case 'llm':
218
+ process.stdout.write(reportLlm(result) + '\n');
219
+ break;
220
+ default:
221
+ reportConsole(result, { verbose: true, noColor: !options.color, showFix: true });
222
+ }
223
+ if (!result.passed)
224
+ process.exit(1);
225
+ });
226
+ program.parse(process.argv);
227
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AACA,+DAA+D;AAC/D,sDAAsD;AACtD,+DAA+D;AAE/D,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACzE,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,4BAA4B,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAGzD,MAAM,OAAO,GAAG,OAAO,CAAC;AAExB,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,WAAW,CAAC;KACjB,WAAW,CACV,yEAAyE;IACzE,0EAA0E,CAC3E;KACA,OAAO,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;AAErC,6EAA6E;AAC7E,OAAO;KACJ,OAAO,CAAC,eAAe,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;KAC7C,WAAW,CAAC,uDAAuD,CAAC;KACpE,MAAM,CAAC,0BAA0B,EAAE,gEAAgE,CAAC;KACpG,MAAM,CAAC,uBAAuB,EAAE,0CAA0C,CAAC;KAC3E,MAAM,CAAC,sBAAsB,EAAE,uFAAuF,CAAC;KACvH,MAAM,CAAC,gBAAgB,EAAE,wCAAwC,CAAC;KAClE,MAAM,CAAC,sBAAsB,EAAE,0CAA0C,CAAC;KAC1E,MAAM,CAAC,WAAW,EAAE,sDAAsD,CAAC;KAC3E,MAAM,CAAC,YAAY,EAAE,wBAAwB,EAAE,KAAK,CAAC;KACrD,MAAM,CAAC,oBAAoB,EAAE,gCAAgC,EAAE,QAAQ,CAAC;KACxE,MAAM,CAAC,0BAA0B,EAAE,uDAAuD,CAAC;KAC3F,MAAM,CAAC,OAAO,EAAE,sDAAsD,CAAC;KACvE,MAAM,CAAC,aAAa,EAAE,8EAA8E,CAAC;KACrG,MAAM,CAAC,uBAAuB,EAAE,6CAA6C,EAAE,QAAQ,CAAC;KACxF,MAAM,CAAC,iBAAiB,EAAE,4DAA4D,CAAC;KACvF,MAAM,CAAC,OAAO,EAAE,yCAAyC,CAAC;KAC1D,MAAM,CAAC,KAAK,EAAE,MAA0B,EAAE,OAe1C,EAAE,EAAE;IACH,kBAAkB;IAClB,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QAChB,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;QACjC,OAAO;IACT,CAAC;IAED,MAAM,UAAU,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;IAEjE,qEAAqE;IACrE,+EAA+E;IAC/E,MAAM,GAAG,GAAG,UAAU,CACpB;QACE,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS;QAChG,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS;QACtG,MAAM,EAAE,OAAO,CAAC,MAAiC;QACjD,MAAM,EAAE,OAAO,CAAC,MAAkC;QAClD,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,aAAa,EAAE,OAAO,CAAC,aAAa;YAClC,CAAC,CAAE,OAAO,CAAC,aAAa,CAAC,WAAW,EAAiB;YACrD,CAAC,CAAC,SAAS;QACb,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,aAAa,EAAE,OAAO,CAAC,aAAa;KACrC,EACD,OAAO,CAAC,MAAM,EACd,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CACzB,CAAC;IAEF,MAAM,MAAM,GAAG,GAAG,CAAC,MAAsB,CAAC;IAC1C,MAAM,MAAM,GAAG,GAAG,CAAC,MAAqB,CAAC;IACzC,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;IAC3D,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;IACjE,MAAM,OAAO,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC;IAC/B,MAAM,aAAa,GAAG,GAAG,CAAC,aAAa,CAAC;IAExC,IAAI,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;QACvD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,0BAA0B,aAAa,gCAAgC,CAAC,CAAC;QAC9F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,kBAAkB;IAClB,IAAI,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,mBAAmB,MAAM,wCAAwC,CAAC,CAAC;QACxF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,kBAAkB;IAClB,IAAI,CAAC,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACrE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,4BAA4B,MAAM,iDAAiD,CAAC,CAAC;QAC1G,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,MAAM,KAAK,SAAS,IAAI,CAAC,OAAO,EAAE,CAAC;QACrC,MAAM,UAAU,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnC,MAAM,SAAS,GAAG,QAAQ,CAAC,aAAa,CAAC;QACzC,MAAM,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;QACxC,MAAM,UAAU,GAAG,QAAQ,GAAG,CAAC;YAC7B,CAAC,CAAC,GAAG,SAAS,aAAa,QAAQ,YAAY,UAAU,QAAQ;YACjE,CAAC,CAAC,GAAG,SAAS,eAAe,CAAC;QAChC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gBAAgB,OAAO,eAAe,UAAU,IAAI,CAAC,CAAC;QAC3E,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,UAAU,cAAc,MAAM,eAAe,MAAM,IAAI,CAAC,CAAC;IAC/G,CAAC;IAED,IAAI,gBAA4C,CAAC;IACjD,IAAI,YAAY,GAAG,EAAE,CAAC;IAEtB,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,gBAAgB,GAAG,WAAW,CAAC,GAAG,EAAE;YAClC,IAAI,YAAY,EAAE,CAAC;gBACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;YACrE,CAAC;QACH,CAAC,EAAE,GAAG,CAAC,CAAC;IACV,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,UAAU,EAAE;YAC7C,KAAK;YACL,OAAO;YACP,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,MAAM;YACN,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,GAAG,EAAE,GAAG,CAAC,GAAG;SACb,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE;YAChC,YAAY,GAAG,QAAQ,CAAC;QAC1B,CAAC,CAAC,CAAC;QAEH,IAAI,gBAAgB,EAAE,CAAC;YACrB,aAAa,CAAC,gBAAgB,CAAC,CAAC;YAChC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;QACrD,CAAC;QAED,+EAA+E;QAC/E,IAAI,cAAc,GAAG,MAAM,CAAC;QAC5B,IAAI,GAAG,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACrC,MAAM,SAAS,GAAG,IAAI,GAAG,EAAoB,CAAC;YAC9C,KAAK,MAAM,UAAU,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;gBACtC,MAAM,OAAO,GAAG,YAAY,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;gBAClD,IAAI,OAAO;oBAAE,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;YACvE,CAAC;YACD,cAAc,GAAG,MAAM,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE;gBACvD,QAAQ,EAAE,OAAO,CAAC,aAAa,IAAI,GAAG,CAAC,aAAa;gBACpD,WAAW,EAAE,UAAU;aACxB,EAAE,MAAM,CAAC,CAAC;QACb,CAAC;QAED,uCAAuC;QACvC,MAAM,cAAc,GAAG,aAAa,KAAK,KAAK;YAC5C,CAAC,CAAC,4BAA4B,CAAC,cAAc,EAAE,aAAa,EAAE,MAAM,CAAC;YACrE,CAAC,CAAC,cAAc,CAAC;QAEnB,QAAQ,MAAM,EAAE,CAAC;YACf,KAAK,MAAM;gBACT,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,cAAc,CAAC,GAAG,IAAI,CAAC,CAAC;gBACxD,MAAM;YACR,KAAK,OAAO;gBACV,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,cAAc,CAAC,GAAG,IAAI,CAAC,CAAC;gBACzD,MAAM;YACR,KAAK,KAAK;gBACR,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,GAAG,IAAI,CAAC,CAAC;gBACvD,MAAM;YACR,KAAK,SAAS,CAAC;YACf;gBACE,aAAa,CAAC,cAAc,EAAE;oBAC5B,OAAO,EAAE,GAAG,CAAC,OAAO;oBACpB,OAAO;oBACP,OAAO,EAAE,GAAG,CAAC,OAAO;iBACrB,CAAC,CAAC;gBACH,MAAM;QACV,CAAC;QAED,uCAAuC;QACvC,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,CAAC;YAC3B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,gBAAgB;YAAE,aAAa,CAAC,gBAAgB,CAAC,CAAC;QACtD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAChD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,6EAA6E;AAC7E,OAAO;KACJ,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,mCAAmC,CAAC;KAChD,MAAM,CAAC,uBAAuB,EAAE,mDAAmD,CAAC;KACpF,MAAM,CAAC,uBAAuB,EAAE,wDAAwD,CAAC;KACzF,MAAM,CAAC,QAAQ,EAAE,gBAAgB,CAAC;KAClC,MAAM,CAAC,CAAC,OAAiE,EAAE,EAAE;IAC5E,IAAI,KAAK,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;IAE9B,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACrB,KAAK,GAAG,QAAQ,CAAC,kBAAkB,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC1D,CAAC;IAED,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACrB,MAAM,QAAQ,GAA2B,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QAC9F,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,IAAI,CAAC,CAAC;QAC7D,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC;IACrE,CAAC;IAED,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QAC5D,OAAO;IACT,CAAC;IAED,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,KAAK,CAAC,MAAM,qBAAqB,CAAC,CAAC;IACzE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC;IACvH,CAAC;IACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AAC7B,CAAC,CAAC,CAAC;AAEL,6EAA6E;AAC7E,OAAO;KACJ,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,yEAAyE,CAAC;KACtF,cAAc,CAAC,mBAAmB,EAAE,4EAA4E,CAAC;KACjH,MAAM,CAAC,mBAAmB,EAAE,eAAe,EAAE,SAAS,CAAC;KACvD,MAAM,CAAC,YAAY,EAAE,sBAAsB,CAAC;KAC5C,MAAM,CAAC,KAAK,EAAE,OAAyD,EAAE,EAAE;IAC1E,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QACxC,MAAM,CAAC,IAAI,CAAC,KAAe,CAAC,CAAC;IAC/B,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAEpD,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;QACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;QACrD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,IAAyB,EAAE,SAAS,CAAC,CAAC;IAElF,QAAQ,OAAO,CAAC,MAAM,EAAE,CAAC;QACvB,KAAK,MAAM;YACT,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;YAChD,MAAM;QACR,KAAK,KAAK;YACR,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;YAC/C,MAAM;QACR;YACE,aAAa,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IACrF,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,MAAM;QAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACtC,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { OWASPScanConfig } from './schema.js';
2
+ /**
3
+ * Load the effective config by merging: defaults < config file < CLI overrides.
4
+ *
5
+ * @param cliOverrides Partial config from CLI flags (undefined fields are ignored)
6
+ * @param explicitConfigPath Path from --config flag (overrides auto-discovery)
7
+ * @param searchDir Directory to start config file search from (default: cwd)
8
+ */
9
+ export declare function loadConfig(cliOverrides?: Partial<OWASPScanConfig>, explicitConfigPath?: string, searchDir?: string): Required<OWASPScanConfig>;
10
+ //# sourceMappingURL=loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAkCnD;;;;;;GAMG;AACH,wBAAgB,UAAU,CACxB,YAAY,GAAE,OAAO,CAAC,eAAe,CAAM,EAC3C,kBAAkB,CAAC,EAAE,MAAM,EAC3B,SAAS,GAAE,MAAsB,GAChC,QAAQ,CAAC,eAAe,CAAC,CAoC3B"}