@oculum/scanner 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 (281) hide show
  1. package/dist/formatters/cli-terminal.d.ts +27 -0
  2. package/dist/formatters/cli-terminal.d.ts.map +1 -0
  3. package/dist/formatters/cli-terminal.js +412 -0
  4. package/dist/formatters/cli-terminal.js.map +1 -0
  5. package/dist/formatters/github-comment.d.ts +41 -0
  6. package/dist/formatters/github-comment.d.ts.map +1 -0
  7. package/dist/formatters/github-comment.js +306 -0
  8. package/dist/formatters/github-comment.js.map +1 -0
  9. package/dist/formatters/grouping.d.ts +52 -0
  10. package/dist/formatters/grouping.d.ts.map +1 -0
  11. package/dist/formatters/grouping.js +152 -0
  12. package/dist/formatters/grouping.js.map +1 -0
  13. package/dist/formatters/index.d.ts +9 -0
  14. package/dist/formatters/index.d.ts.map +1 -0
  15. package/dist/formatters/index.js +35 -0
  16. package/dist/formatters/index.js.map +1 -0
  17. package/dist/formatters/vscode-diagnostic.d.ts +103 -0
  18. package/dist/formatters/vscode-diagnostic.d.ts.map +1 -0
  19. package/dist/formatters/vscode-diagnostic.js +151 -0
  20. package/dist/formatters/vscode-diagnostic.js.map +1 -0
  21. package/dist/index.d.ts +52 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +648 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/layer1/comments.d.ts +8 -0
  26. package/dist/layer1/comments.d.ts.map +1 -0
  27. package/dist/layer1/comments.js +203 -0
  28. package/dist/layer1/comments.js.map +1 -0
  29. package/dist/layer1/config-audit.d.ts +8 -0
  30. package/dist/layer1/config-audit.d.ts.map +1 -0
  31. package/dist/layer1/config-audit.js +252 -0
  32. package/dist/layer1/config-audit.js.map +1 -0
  33. package/dist/layer1/entropy.d.ts +8 -0
  34. package/dist/layer1/entropy.d.ts.map +1 -0
  35. package/dist/layer1/entropy.js +500 -0
  36. package/dist/layer1/entropy.js.map +1 -0
  37. package/dist/layer1/file-flags.d.ts +7 -0
  38. package/dist/layer1/file-flags.d.ts.map +1 -0
  39. package/dist/layer1/file-flags.js +112 -0
  40. package/dist/layer1/file-flags.js.map +1 -0
  41. package/dist/layer1/index.d.ts +36 -0
  42. package/dist/layer1/index.d.ts.map +1 -0
  43. package/dist/layer1/index.js +132 -0
  44. package/dist/layer1/index.js.map +1 -0
  45. package/dist/layer1/patterns.d.ts +8 -0
  46. package/dist/layer1/patterns.d.ts.map +1 -0
  47. package/dist/layer1/patterns.js +482 -0
  48. package/dist/layer1/patterns.js.map +1 -0
  49. package/dist/layer1/urls.d.ts +8 -0
  50. package/dist/layer1/urls.d.ts.map +1 -0
  51. package/dist/layer1/urls.js +296 -0
  52. package/dist/layer1/urls.js.map +1 -0
  53. package/dist/layer1/weak-crypto.d.ts +7 -0
  54. package/dist/layer1/weak-crypto.d.ts.map +1 -0
  55. package/dist/layer1/weak-crypto.js +291 -0
  56. package/dist/layer1/weak-crypto.js.map +1 -0
  57. package/dist/layer2/ai-agent-tools.d.ts +19 -0
  58. package/dist/layer2/ai-agent-tools.d.ts.map +1 -0
  59. package/dist/layer2/ai-agent-tools.js +528 -0
  60. package/dist/layer2/ai-agent-tools.js.map +1 -0
  61. package/dist/layer2/ai-endpoint-protection.d.ts +36 -0
  62. package/dist/layer2/ai-endpoint-protection.d.ts.map +1 -0
  63. package/dist/layer2/ai-endpoint-protection.js +332 -0
  64. package/dist/layer2/ai-endpoint-protection.js.map +1 -0
  65. package/dist/layer2/ai-execution-sinks.d.ts +18 -0
  66. package/dist/layer2/ai-execution-sinks.d.ts.map +1 -0
  67. package/dist/layer2/ai-execution-sinks.js +496 -0
  68. package/dist/layer2/ai-execution-sinks.js.map +1 -0
  69. package/dist/layer2/ai-fingerprinting.d.ts +7 -0
  70. package/dist/layer2/ai-fingerprinting.d.ts.map +1 -0
  71. package/dist/layer2/ai-fingerprinting.js +654 -0
  72. package/dist/layer2/ai-fingerprinting.js.map +1 -0
  73. package/dist/layer2/ai-prompt-hygiene.d.ts +19 -0
  74. package/dist/layer2/ai-prompt-hygiene.d.ts.map +1 -0
  75. package/dist/layer2/ai-prompt-hygiene.js +356 -0
  76. package/dist/layer2/ai-prompt-hygiene.js.map +1 -0
  77. package/dist/layer2/ai-rag-safety.d.ts +21 -0
  78. package/dist/layer2/ai-rag-safety.d.ts.map +1 -0
  79. package/dist/layer2/ai-rag-safety.js +459 -0
  80. package/dist/layer2/ai-rag-safety.js.map +1 -0
  81. package/dist/layer2/ai-schema-validation.d.ts +25 -0
  82. package/dist/layer2/ai-schema-validation.d.ts.map +1 -0
  83. package/dist/layer2/ai-schema-validation.js +375 -0
  84. package/dist/layer2/ai-schema-validation.js.map +1 -0
  85. package/dist/layer2/auth-antipatterns.d.ts +20 -0
  86. package/dist/layer2/auth-antipatterns.d.ts.map +1 -0
  87. package/dist/layer2/auth-antipatterns.js +333 -0
  88. package/dist/layer2/auth-antipatterns.js.map +1 -0
  89. package/dist/layer2/byok-patterns.d.ts +12 -0
  90. package/dist/layer2/byok-patterns.d.ts.map +1 -0
  91. package/dist/layer2/byok-patterns.js +299 -0
  92. package/dist/layer2/byok-patterns.js.map +1 -0
  93. package/dist/layer2/dangerous-functions.d.ts +7 -0
  94. package/dist/layer2/dangerous-functions.d.ts.map +1 -0
  95. package/dist/layer2/dangerous-functions.js +1375 -0
  96. package/dist/layer2/dangerous-functions.js.map +1 -0
  97. package/dist/layer2/data-exposure.d.ts +16 -0
  98. package/dist/layer2/data-exposure.d.ts.map +1 -0
  99. package/dist/layer2/data-exposure.js +279 -0
  100. package/dist/layer2/data-exposure.js.map +1 -0
  101. package/dist/layer2/framework-checks.d.ts +7 -0
  102. package/dist/layer2/framework-checks.d.ts.map +1 -0
  103. package/dist/layer2/framework-checks.js +388 -0
  104. package/dist/layer2/framework-checks.js.map +1 -0
  105. package/dist/layer2/index.d.ts +58 -0
  106. package/dist/layer2/index.d.ts.map +1 -0
  107. package/dist/layer2/index.js +380 -0
  108. package/dist/layer2/index.js.map +1 -0
  109. package/dist/layer2/logic-gates.d.ts +7 -0
  110. package/dist/layer2/logic-gates.d.ts.map +1 -0
  111. package/dist/layer2/logic-gates.js +182 -0
  112. package/dist/layer2/logic-gates.js.map +1 -0
  113. package/dist/layer2/risky-imports.d.ts +7 -0
  114. package/dist/layer2/risky-imports.d.ts.map +1 -0
  115. package/dist/layer2/risky-imports.js +161 -0
  116. package/dist/layer2/risky-imports.js.map +1 -0
  117. package/dist/layer2/variables.d.ts +8 -0
  118. package/dist/layer2/variables.d.ts.map +1 -0
  119. package/dist/layer2/variables.js +152 -0
  120. package/dist/layer2/variables.js.map +1 -0
  121. package/dist/layer3/anthropic.d.ts +83 -0
  122. package/dist/layer3/anthropic.d.ts.map +1 -0
  123. package/dist/layer3/anthropic.js +1745 -0
  124. package/dist/layer3/anthropic.js.map +1 -0
  125. package/dist/layer3/index.d.ts +24 -0
  126. package/dist/layer3/index.d.ts.map +1 -0
  127. package/dist/layer3/index.js +119 -0
  128. package/dist/layer3/index.js.map +1 -0
  129. package/dist/layer3/openai.d.ts +25 -0
  130. package/dist/layer3/openai.d.ts.map +1 -0
  131. package/dist/layer3/openai.js +238 -0
  132. package/dist/layer3/openai.js.map +1 -0
  133. package/dist/layer3/package-check.d.ts +63 -0
  134. package/dist/layer3/package-check.d.ts.map +1 -0
  135. package/dist/layer3/package-check.js +508 -0
  136. package/dist/layer3/package-check.js.map +1 -0
  137. package/dist/modes/incremental.d.ts +66 -0
  138. package/dist/modes/incremental.d.ts.map +1 -0
  139. package/dist/modes/incremental.js +200 -0
  140. package/dist/modes/incremental.js.map +1 -0
  141. package/dist/tiers.d.ts +125 -0
  142. package/dist/tiers.d.ts.map +1 -0
  143. package/dist/tiers.js +234 -0
  144. package/dist/tiers.js.map +1 -0
  145. package/dist/types.d.ts +175 -0
  146. package/dist/types.d.ts.map +1 -0
  147. package/dist/types.js +50 -0
  148. package/dist/types.js.map +1 -0
  149. package/dist/utils/auth-helper-detector.d.ts +56 -0
  150. package/dist/utils/auth-helper-detector.d.ts.map +1 -0
  151. package/dist/utils/auth-helper-detector.js +360 -0
  152. package/dist/utils/auth-helper-detector.js.map +1 -0
  153. package/dist/utils/context-helpers.d.ts +96 -0
  154. package/dist/utils/context-helpers.d.ts.map +1 -0
  155. package/dist/utils/context-helpers.js +493 -0
  156. package/dist/utils/context-helpers.js.map +1 -0
  157. package/dist/utils/diff-detector.d.ts +53 -0
  158. package/dist/utils/diff-detector.d.ts.map +1 -0
  159. package/dist/utils/diff-detector.js +104 -0
  160. package/dist/utils/diff-detector.js.map +1 -0
  161. package/dist/utils/diff-parser.d.ts +80 -0
  162. package/dist/utils/diff-parser.d.ts.map +1 -0
  163. package/dist/utils/diff-parser.js +202 -0
  164. package/dist/utils/diff-parser.js.map +1 -0
  165. package/dist/utils/imported-auth-detector.d.ts +37 -0
  166. package/dist/utils/imported-auth-detector.d.ts.map +1 -0
  167. package/dist/utils/imported-auth-detector.js +251 -0
  168. package/dist/utils/imported-auth-detector.js.map +1 -0
  169. package/dist/utils/middleware-detector.d.ts +55 -0
  170. package/dist/utils/middleware-detector.d.ts.map +1 -0
  171. package/dist/utils/middleware-detector.js +260 -0
  172. package/dist/utils/middleware-detector.js.map +1 -0
  173. package/dist/utils/oauth-flow-detector.d.ts +41 -0
  174. package/dist/utils/oauth-flow-detector.d.ts.map +1 -0
  175. package/dist/utils/oauth-flow-detector.js +202 -0
  176. package/dist/utils/oauth-flow-detector.js.map +1 -0
  177. package/dist/utils/path-exclusions.d.ts +55 -0
  178. package/dist/utils/path-exclusions.d.ts.map +1 -0
  179. package/dist/utils/path-exclusions.js +222 -0
  180. package/dist/utils/path-exclusions.js.map +1 -0
  181. package/dist/utils/project-context-builder.d.ts +119 -0
  182. package/dist/utils/project-context-builder.d.ts.map +1 -0
  183. package/dist/utils/project-context-builder.js +534 -0
  184. package/dist/utils/project-context-builder.js.map +1 -0
  185. package/dist/utils/registry-clients.d.ts +93 -0
  186. package/dist/utils/registry-clients.d.ts.map +1 -0
  187. package/dist/utils/registry-clients.js +273 -0
  188. package/dist/utils/registry-clients.js.map +1 -0
  189. package/dist/utils/trpc-analyzer.d.ts +78 -0
  190. package/dist/utils/trpc-analyzer.d.ts.map +1 -0
  191. package/dist/utils/trpc-analyzer.js +297 -0
  192. package/dist/utils/trpc-analyzer.js.map +1 -0
  193. package/package.json +45 -0
  194. package/src/__tests__/benchmark/fixtures/false-positives.ts +227 -0
  195. package/src/__tests__/benchmark/fixtures/index.ts +68 -0
  196. package/src/__tests__/benchmark/fixtures/layer1/config-audit.ts +364 -0
  197. package/src/__tests__/benchmark/fixtures/layer1/hardcoded-secrets.ts +173 -0
  198. package/src/__tests__/benchmark/fixtures/layer1/high-entropy.ts +234 -0
  199. package/src/__tests__/benchmark/fixtures/layer1/index.ts +31 -0
  200. package/src/__tests__/benchmark/fixtures/layer1/sensitive-urls.ts +90 -0
  201. package/src/__tests__/benchmark/fixtures/layer1/weak-crypto.ts +197 -0
  202. package/src/__tests__/benchmark/fixtures/layer2/ai-agent-tools.ts +170 -0
  203. package/src/__tests__/benchmark/fixtures/layer2/ai-endpoint-protection.ts +418 -0
  204. package/src/__tests__/benchmark/fixtures/layer2/ai-execution-sinks.ts +189 -0
  205. package/src/__tests__/benchmark/fixtures/layer2/ai-fingerprinting.ts +316 -0
  206. package/src/__tests__/benchmark/fixtures/layer2/ai-prompt-hygiene.ts +178 -0
  207. package/src/__tests__/benchmark/fixtures/layer2/ai-rag-safety.ts +184 -0
  208. package/src/__tests__/benchmark/fixtures/layer2/ai-schema-validation.ts +434 -0
  209. package/src/__tests__/benchmark/fixtures/layer2/auth-antipatterns.ts +159 -0
  210. package/src/__tests__/benchmark/fixtures/layer2/byok-patterns.ts +112 -0
  211. package/src/__tests__/benchmark/fixtures/layer2/dangerous-functions.ts +246 -0
  212. package/src/__tests__/benchmark/fixtures/layer2/data-exposure.ts +168 -0
  213. package/src/__tests__/benchmark/fixtures/layer2/framework-checks.ts +346 -0
  214. package/src/__tests__/benchmark/fixtures/layer2/index.ts +67 -0
  215. package/src/__tests__/benchmark/fixtures/layer2/injection-vulnerabilities.ts +239 -0
  216. package/src/__tests__/benchmark/fixtures/layer2/logic-gates.ts +246 -0
  217. package/src/__tests__/benchmark/fixtures/layer2/risky-imports.ts +231 -0
  218. package/src/__tests__/benchmark/fixtures/layer2/variables.ts +167 -0
  219. package/src/__tests__/benchmark/index.ts +29 -0
  220. package/src/__tests__/benchmark/run-benchmark.ts +144 -0
  221. package/src/__tests__/benchmark/run-depth-validation.ts +206 -0
  222. package/src/__tests__/benchmark/run-real-world-test.ts +243 -0
  223. package/src/__tests__/benchmark/security-benchmark-script.ts +1737 -0
  224. package/src/__tests__/benchmark/tier-integration-script.ts +177 -0
  225. package/src/__tests__/benchmark/types.ts +144 -0
  226. package/src/__tests__/benchmark/utils/test-runner.ts +475 -0
  227. package/src/__tests__/regression/known-false-positives.test.ts +467 -0
  228. package/src/__tests__/snapshots/__snapshots__/scan-depth.test.ts.snap +178 -0
  229. package/src/__tests__/snapshots/scan-depth.test.ts +258 -0
  230. package/src/__tests__/validation/analyze-results.ts +542 -0
  231. package/src/__tests__/validation/extract-for-triage.ts +146 -0
  232. package/src/__tests__/validation/fp-deep-analysis.ts +327 -0
  233. package/src/__tests__/validation/run-validation.ts +364 -0
  234. package/src/__tests__/validation/triage-template.md +132 -0
  235. package/src/formatters/cli-terminal.ts +446 -0
  236. package/src/formatters/github-comment.ts +382 -0
  237. package/src/formatters/grouping.ts +190 -0
  238. package/src/formatters/index.ts +47 -0
  239. package/src/formatters/vscode-diagnostic.ts +243 -0
  240. package/src/index.ts +823 -0
  241. package/src/layer1/comments.ts +218 -0
  242. package/src/layer1/config-audit.ts +289 -0
  243. package/src/layer1/entropy.ts +583 -0
  244. package/src/layer1/file-flags.ts +127 -0
  245. package/src/layer1/index.ts +181 -0
  246. package/src/layer1/patterns.ts +516 -0
  247. package/src/layer1/urls.ts +334 -0
  248. package/src/layer1/weak-crypto.ts +328 -0
  249. package/src/layer2/ai-agent-tools.ts +601 -0
  250. package/src/layer2/ai-endpoint-protection.ts +387 -0
  251. package/src/layer2/ai-execution-sinks.ts +580 -0
  252. package/src/layer2/ai-fingerprinting.ts +758 -0
  253. package/src/layer2/ai-prompt-hygiene.ts +411 -0
  254. package/src/layer2/ai-rag-safety.ts +511 -0
  255. package/src/layer2/ai-schema-validation.ts +421 -0
  256. package/src/layer2/auth-antipatterns.ts +394 -0
  257. package/src/layer2/byok-patterns.ts +336 -0
  258. package/src/layer2/dangerous-functions.ts +1563 -0
  259. package/src/layer2/data-exposure.ts +315 -0
  260. package/src/layer2/framework-checks.ts +433 -0
  261. package/src/layer2/index.ts +473 -0
  262. package/src/layer2/logic-gates.ts +206 -0
  263. package/src/layer2/risky-imports.ts +186 -0
  264. package/src/layer2/variables.ts +166 -0
  265. package/src/layer3/anthropic.ts +2030 -0
  266. package/src/layer3/index.ts +130 -0
  267. package/src/layer3/package-check.ts +604 -0
  268. package/src/modes/incremental.ts +293 -0
  269. package/src/tiers.ts +318 -0
  270. package/src/types.ts +284 -0
  271. package/src/utils/auth-helper-detector.ts +443 -0
  272. package/src/utils/context-helpers.ts +535 -0
  273. package/src/utils/diff-detector.ts +135 -0
  274. package/src/utils/diff-parser.ts +272 -0
  275. package/src/utils/imported-auth-detector.ts +320 -0
  276. package/src/utils/middleware-detector.ts +333 -0
  277. package/src/utils/oauth-flow-detector.ts +246 -0
  278. package/src/utils/path-exclusions.ts +266 -0
  279. package/src/utils/project-context-builder.ts +707 -0
  280. package/src/utils/registry-clients.ts +351 -0
  281. package/src/utils/trpc-analyzer.ts +382 -0
@@ -0,0 +1,202 @@
1
+ "use strict";
2
+ /**
3
+ * OAuth Flow Detector
4
+ * Detects OAuth state generation and validation across multiple files
5
+ * to prevent false positives when state is implemented correctly but split across files.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.detectOAuthFlow = detectOAuthFlow;
9
+ exports.isOAuthStateImplemented = isOAuthStateImplemented;
10
+ exports.getOAuthFlowSummary = getOAuthFlowSummary;
11
+ /**
12
+ * Patterns that indicate OAuth state generation
13
+ */
14
+ const STATE_GENERATION_PATTERNS = [
15
+ /generateState\s*\(/i,
16
+ /crypto\.randomBytes.*state/i,
17
+ /state\s*=\s*.*random/i,
18
+ /setCookie.*oauth.*state/i,
19
+ /cookies?\(\s*\)\.set\s*\([^)]*state/i,
20
+ /state\s*=\s*generateRandomString/i,
21
+ /state\s*=\s*nanoid\s*\(/i,
22
+ /state\s*=\s*uuid/i,
23
+ /state\s*=\s*crypto\.randomUUID/i,
24
+ /createState\s*\(/i,
25
+ /oauth.*state.*=.*crypto/i,
26
+ /\.setState\s*\(/i,
27
+ /stateParam\s*=\s*/i,
28
+ /generateOAuthState/i,
29
+ ];
30
+ /**
31
+ * Patterns that indicate OAuth state validation
32
+ */
33
+ const STATE_VALIDATION_PATTERNS = [
34
+ /state\s*!==\s*storedState/i,
35
+ /storedState.*!==.*state/i,
36
+ /validateState\s*\(/i,
37
+ /getCookie.*oauth.*state/i,
38
+ /cookies?\(\s*\)\.get\s*\([^)]*state/i,
39
+ /verifyState\s*\(/i,
40
+ /checkState\s*\(/i,
41
+ /state\s*===\s*savedState/i,
42
+ /savedState\s*===\s*state/i,
43
+ /if\s*\(\s*!?\s*state\s*\)/i,
44
+ /state\s*!==\s*.*\.get\s*\(/i,
45
+ /\.getState\s*\(/i,
46
+ /compareState\s*\(/i,
47
+ ];
48
+ /**
49
+ * Patterns that indicate PKCE code_verifier usage
50
+ */
51
+ const CODE_VERIFIER_PATTERNS = [
52
+ /code_verifier/i,
53
+ /codeVerifier/i,
54
+ /generateCodeVerifier/i,
55
+ /createCodeVerifier/i,
56
+ /pkce/i,
57
+ /code_challenge/i,
58
+ /codeChallenge/i,
59
+ ];
60
+ /**
61
+ * Patterns that indicate client_credentials flow (no state needed)
62
+ */
63
+ const CLIENT_CREDENTIALS_PATTERNS = [
64
+ /grant_type.*client_credentials/i,
65
+ /client_credentials.*grant/i,
66
+ /\.clientCredentials\s*\(/i,
67
+ /getClientCredentialsToken/i,
68
+ /machine-to-machine/i,
69
+ /m2m.*auth/i,
70
+ ];
71
+ /**
72
+ * Known OAuth provider patterns
73
+ */
74
+ const OAUTH_PROVIDER_PATTERNS = {
75
+ google: [/googleapis\.com\/oauth/i, /accounts\.google\.com/i, /google.*oauth/i],
76
+ github: [/github\.com\/login\/oauth/i, /api\.github\.com.*oauth/i],
77
+ microsoft: [/login\.microsoftonline\.com/i, /microsoft.*oauth/i, /azure.*oauth/i],
78
+ facebook: [/facebook\.com\/.*oauth/i, /graph\.facebook\.com/i],
79
+ twitter: [/twitter\.com\/oauth/i, /api\.twitter\.com.*oauth/i],
80
+ apple: [/appleid\.apple\.com/i, /apple.*oauth/i],
81
+ auth0: [/auth0\.com/i, /\.auth0\./i],
82
+ okta: [/okta\.com/i, /\.okta\./i],
83
+ clerk: [/clerk\.dev/i, /clerk\.com/i, /@clerk\//i],
84
+ nextauth: [/next-auth/i, /nextauth/i, /authjs/i],
85
+ lucia: [/lucia-auth/i, /lucia\.ts/i],
86
+ arctic: [/arctic/i, /oslo\/oauth/i],
87
+ };
88
+ /**
89
+ * Detect OAuth flow patterns across multiple files
90
+ */
91
+ function detectOAuthFlow(files) {
92
+ const context = {
93
+ hasStateGeneration: false,
94
+ hasStateValidation: false,
95
+ hasCodeVerifier: false,
96
+ flowType: 'unknown',
97
+ providers: [],
98
+ };
99
+ const detectedProviders = new Set();
100
+ for (const file of files) {
101
+ const content = file.content;
102
+ const lines = content.split('\n');
103
+ // Check for state generation
104
+ if (!context.hasStateGeneration) {
105
+ for (let i = 0; i < lines.length; i++) {
106
+ const line = lines[i];
107
+ if (STATE_GENERATION_PATTERNS.some(p => p.test(line))) {
108
+ context.hasStateGeneration = true;
109
+ context.stateGenerationFile = file.path;
110
+ context.stateGenerationLine = i + 1;
111
+ break;
112
+ }
113
+ }
114
+ }
115
+ // Check for state validation
116
+ if (!context.hasStateValidation) {
117
+ for (let i = 0; i < lines.length; i++) {
118
+ const line = lines[i];
119
+ if (STATE_VALIDATION_PATTERNS.some(p => p.test(line))) {
120
+ context.hasStateValidation = true;
121
+ context.stateValidationFile = file.path;
122
+ context.stateValidationLine = i + 1;
123
+ break;
124
+ }
125
+ }
126
+ }
127
+ // Check for PKCE
128
+ if (!context.hasCodeVerifier) {
129
+ if (CODE_VERIFIER_PATTERNS.some(p => p.test(content))) {
130
+ context.hasCodeVerifier = true;
131
+ context.codeVerifierFile = file.path;
132
+ }
133
+ }
134
+ // Check for client_credentials flow
135
+ if (context.flowType === 'unknown') {
136
+ if (CLIENT_CREDENTIALS_PATTERNS.some(p => p.test(content))) {
137
+ context.flowType = 'client_credentials';
138
+ }
139
+ }
140
+ // Detect OAuth providers
141
+ for (const [provider, patterns] of Object.entries(OAUTH_PROVIDER_PATTERNS)) {
142
+ if (patterns.some(p => p.test(content))) {
143
+ detectedProviders.add(provider);
144
+ }
145
+ }
146
+ }
147
+ // Determine flow type
148
+ if (context.flowType === 'unknown') {
149
+ if (context.hasCodeVerifier) {
150
+ context.flowType = 'pkce';
151
+ }
152
+ else if (context.hasStateGeneration || context.hasStateValidation) {
153
+ context.flowType = 'authorization_code';
154
+ }
155
+ }
156
+ context.providers = Array.from(detectedProviders);
157
+ return context;
158
+ }
159
+ /**
160
+ * Check if OAuth state is properly implemented across files
161
+ */
162
+ function isOAuthStateImplemented(context) {
163
+ // client_credentials flow doesn't need state
164
+ if (context.flowType === 'client_credentials') {
165
+ return true;
166
+ }
167
+ // PKCE flow with code_verifier is secure even without traditional state
168
+ if (context.hasCodeVerifier) {
169
+ return true;
170
+ }
171
+ // Both generation and validation must be present
172
+ return context.hasStateGeneration && context.hasStateValidation;
173
+ }
174
+ /**
175
+ * Get a summary of the OAuth flow for logging/context
176
+ */
177
+ function getOAuthFlowSummary(context) {
178
+ const parts = [];
179
+ if (context.flowType !== 'unknown') {
180
+ parts.push(`Flow: ${context.flowType}`);
181
+ }
182
+ if (context.providers.length > 0) {
183
+ parts.push(`Providers: ${context.providers.join(', ')}`);
184
+ }
185
+ if (context.hasStateGeneration) {
186
+ parts.push(`State generated in: ${context.stateGenerationFile}`);
187
+ }
188
+ if (context.hasStateValidation) {
189
+ parts.push(`State validated in: ${context.stateValidationFile}`);
190
+ }
191
+ if (context.hasCodeVerifier) {
192
+ parts.push(`PKCE enabled (${context.codeVerifierFile})`);
193
+ }
194
+ if (isOAuthStateImplemented(context)) {
195
+ parts.push('✓ OAuth state properly implemented');
196
+ }
197
+ else if (context.hasStateGeneration || context.hasStateValidation) {
198
+ parts.push('⚠ Partial OAuth state implementation detected');
199
+ }
200
+ return parts.join('; ');
201
+ }
202
+ //# sourceMappingURL=oauth-flow-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth-flow-detector.js","sourceRoot":"","sources":["../../src/utils/oauth-flow-detector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Path Exclusion Utility
3
+ * Provides configurable exclusion of test files, seed files, examples, and fixtures
4
+ * to reduce false positives in security scans.
5
+ */
6
+ import type { Vulnerability } from '../types';
7
+ export interface ExclusionConfig {
8
+ testPatterns: string[];
9
+ seedPatterns: string[];
10
+ examplePatterns: string[];
11
+ fixturePatterns: string[];
12
+ }
13
+ export type ExclusionReason = 'test_file' | 'seed_file' | 'example_file' | 'fixture_file' | null;
14
+ /**
15
+ * Check if a file path should be excluded from scanning
16
+ * Returns the exclusion reason or null if not excluded
17
+ */
18
+ export declare function getExclusionReason(filePath: string, config?: ExclusionConfig): ExclusionReason;
19
+ /**
20
+ * Check if a file path should be excluded
21
+ */
22
+ export declare function isExcludedPath(filePath: string, config?: Partial<ExclusionConfig>): boolean;
23
+ /**
24
+ * Determine if a finding should be suppressed based on file path and category
25
+ *
26
+ * @param finding - The vulnerability finding
27
+ * @param exclusionReason - The reason the file is excluded (if any)
28
+ * @returns true if the finding should be suppressed
29
+ */
30
+ export declare function shouldSuppressFinding(finding: Vulnerability, exclusionReason: ExclusionReason): boolean;
31
+ /**
32
+ * Get a human-readable description of the exclusion reason
33
+ */
34
+ export declare function getExclusionDescription(reason: ExclusionReason): string;
35
+ /**
36
+ * Filter findings based on path exclusions
37
+ * Returns findings that should be kept and a list of suppressed findings with reasons
38
+ */
39
+ export declare function filterFindingsByPath(findings: Vulnerability[], config?: Partial<ExclusionConfig>): {
40
+ kept: Vulnerability[];
41
+ suppressed: Array<{
42
+ finding: Vulnerability;
43
+ reason: ExclusionReason;
44
+ description: string;
45
+ }>;
46
+ };
47
+ /**
48
+ * Get the default exclusion configuration
49
+ */
50
+ export declare function getDefaultExclusionConfig(): ExclusionConfig;
51
+ /**
52
+ * Merge custom exclusion patterns with defaults
53
+ */
54
+ export declare function mergeExclusionConfig(custom: Partial<ExclusionConfig>): ExclusionConfig;
55
+ //# sourceMappingURL=path-exclusions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path-exclusions.d.ts","sourceRoot":"","sources":["../../src/utils/path-exclusions.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAyB,MAAM,UAAU,CAAA;AAEpE,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,eAAe,EAAE,MAAM,EAAE,CAAA;IACzB,eAAe,EAAE,MAAM,EAAE,CAAA;CAC1B;AAwED,MAAM,MAAM,eAAe,GAAG,WAAW,GAAG,WAAW,GAAG,cAAc,GAAG,cAAc,GAAG,IAAI,CAAA;AA6BhG;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,MAAM,GAAE,eAAoC,GAC3C,eAAe,CAwBjB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,GAChC,OAAO,CAOT;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,aAAa,EACtB,eAAe,EAAE,eAAe,GAC/B,OAAO,CAkBT;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAavE;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,aAAa,EAAE,EACzB,MAAM,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,GAChC;IACD,IAAI,EAAE,aAAa,EAAE,CAAA;IACrB,UAAU,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,aAAa,CAAC;QAAC,MAAM,EAAE,eAAe,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAC5F,CAwBA;AAED;;GAEG;AACH,wBAAgB,yBAAyB,IAAI,eAAe,CAE3D;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,OAAO,CAAC,eAAe,CAAC,GAC/B,eAAe,CAOjB"}
@@ -0,0 +1,222 @@
1
+ "use strict";
2
+ /**
3
+ * Path Exclusion Utility
4
+ * Provides configurable exclusion of test files, seed files, examples, and fixtures
5
+ * to reduce false positives in security scans.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.getExclusionReason = getExclusionReason;
9
+ exports.isExcludedPath = isExcludedPath;
10
+ exports.shouldSuppressFinding = shouldSuppressFinding;
11
+ exports.getExclusionDescription = getExclusionDescription;
12
+ exports.filterFindingsByPath = filterFindingsByPath;
13
+ exports.getDefaultExclusionConfig = getDefaultExclusionConfig;
14
+ exports.mergeExclusionConfig = mergeExclusionConfig;
15
+ const DEFAULT_EXCLUSIONS = {
16
+ testPatterns: [
17
+ '**/*.spec.ts',
18
+ '**/*.spec.js',
19
+ '**/*.test.ts',
20
+ '**/*.test.js',
21
+ '**/test/**',
22
+ '**/tests/**',
23
+ '**/__tests__/**',
24
+ '**/e2e/**',
25
+ '**/app-tests/**',
26
+ '**/*.spec.tsx',
27
+ '**/*.spec.jsx',
28
+ '**/*.test.tsx',
29
+ '**/*.test.jsx',
30
+ '**/cypress/**',
31
+ '**/playwright/**',
32
+ ],
33
+ seedPatterns: [
34
+ '**/seed/**',
35
+ '**/seeds/**',
36
+ '**/prisma/seed/**',
37
+ '**/prisma/seed.ts',
38
+ '**/prisma/seed.js',
39
+ '**/db/seed/**',
40
+ '**/database/seed/**',
41
+ ],
42
+ examplePatterns: [
43
+ '**/examples/**',
44
+ '**/demo/**',
45
+ '**/sample/**',
46
+ '**/samples/**',
47
+ '**/playground/**',
48
+ ],
49
+ fixturePatterns: [
50
+ '**/fixtures/**',
51
+ '**/mocks/**',
52
+ '**/__mocks__/**',
53
+ '**/stubs/**',
54
+ '**/__fixtures__/**',
55
+ ],
56
+ };
57
+ /**
58
+ * Categories that should be SUPPRESSED in test/seed/example files
59
+ * These are typically false positives in non-production code
60
+ */
61
+ const SUPPRESSIBLE_CATEGORIES = [
62
+ 'weak_crypto', // Math.random in tests is fine
63
+ 'dangerous_function', // regex, eval in tests often intentional
64
+ 'hardcoded_secret', // test fixtures have fake secrets
65
+ 'high_entropy_string', // test data often looks like secrets
66
+ 'sensitive_url', // localhost in test configs
67
+ 'sensitive_variable', // test variables named 'password' etc.
68
+ 'insecure_config', // test configs are intentionally loose
69
+ 'ai_pattern', // AI patterns in test code
70
+ ];
71
+ /**
72
+ * Categories that should ALWAYS be scanned, even in test files
73
+ * These represent real vulnerabilities that matter in test code too
74
+ */
75
+ const ALWAYS_SCAN_CATEGORIES = [
76
+ 'sql_injection',
77
+ 'command_injection',
78
+ 'xss',
79
+ 'path_traversal', // Cast since not in original types
80
+ 'missing_auth', // Keep but may downgrade
81
+ ];
82
+ /**
83
+ * Convert glob pattern to regex for matching
84
+ */
85
+ function globToRegex(pattern) {
86
+ // Escape special regex characters except * and **
87
+ let regexStr = pattern
88
+ .replace(/[.+^${}()|[\]\\]/g, '\\$&')
89
+ .replace(/\*\*/g, '{{GLOBSTAR}}')
90
+ .replace(/\*/g, '[^/]*')
91
+ .replace(/\{\{GLOBSTAR\}\}/g, '.*');
92
+ return new RegExp(regexStr, 'i');
93
+ }
94
+ /**
95
+ * Check if a file path matches any pattern in a list
96
+ */
97
+ function matchesPatterns(filePath, patterns) {
98
+ // Normalize path separators
99
+ const normalizedPath = filePath.replace(/\\/g, '/');
100
+ return patterns.some(pattern => {
101
+ const regex = globToRegex(pattern);
102
+ return regex.test(normalizedPath);
103
+ });
104
+ }
105
+ /**
106
+ * Check if a file path should be excluded from scanning
107
+ * Returns the exclusion reason or null if not excluded
108
+ */
109
+ function getExclusionReason(filePath, config = DEFAULT_EXCLUSIONS) {
110
+ const normalizedPath = filePath.replace(/\\/g, '/');
111
+ // Check test patterns
112
+ if (matchesPatterns(normalizedPath, config.testPatterns)) {
113
+ return 'test_file';
114
+ }
115
+ // Check seed patterns
116
+ if (matchesPatterns(normalizedPath, config.seedPatterns)) {
117
+ return 'seed_file';
118
+ }
119
+ // Check example patterns
120
+ if (matchesPatterns(normalizedPath, config.examplePatterns)) {
121
+ return 'example_file';
122
+ }
123
+ // Check fixture patterns
124
+ if (matchesPatterns(normalizedPath, config.fixturePatterns)) {
125
+ return 'fixture_file';
126
+ }
127
+ return null;
128
+ }
129
+ /**
130
+ * Check if a file path should be excluded
131
+ */
132
+ function isExcludedPath(filePath, config) {
133
+ const mergedConfig = {
134
+ ...DEFAULT_EXCLUSIONS,
135
+ ...config,
136
+ };
137
+ return getExclusionReason(filePath, mergedConfig) !== null;
138
+ }
139
+ /**
140
+ * Determine if a finding should be suppressed based on file path and category
141
+ *
142
+ * @param finding - The vulnerability finding
143
+ * @param exclusionReason - The reason the file is excluded (if any)
144
+ * @returns true if the finding should be suppressed
145
+ */
146
+ function shouldSuppressFinding(finding, exclusionReason) {
147
+ // If file is not excluded, don't suppress
148
+ if (!exclusionReason) {
149
+ return false;
150
+ }
151
+ // Always scan certain critical categories even in test files
152
+ if (ALWAYS_SCAN_CATEGORIES.includes(finding.category)) {
153
+ return false;
154
+ }
155
+ // Suppress suppressible categories in excluded files
156
+ if (SUPPRESSIBLE_CATEGORIES.includes(finding.category)) {
157
+ return true;
158
+ }
159
+ // Default: don't suppress
160
+ return false;
161
+ }
162
+ /**
163
+ * Get a human-readable description of the exclusion reason
164
+ */
165
+ function getExclusionDescription(reason) {
166
+ switch (reason) {
167
+ case 'test_file':
168
+ return 'Finding in test file';
169
+ case 'seed_file':
170
+ return 'Finding in seed/fixture data file';
171
+ case 'example_file':
172
+ return 'Finding in example/demo file';
173
+ case 'fixture_file':
174
+ return 'Finding in mock/fixture file';
175
+ default:
176
+ return '';
177
+ }
178
+ }
179
+ /**
180
+ * Filter findings based on path exclusions
181
+ * Returns findings that should be kept and a list of suppressed findings with reasons
182
+ */
183
+ function filterFindingsByPath(findings, config) {
184
+ const mergedConfig = {
185
+ ...DEFAULT_EXCLUSIONS,
186
+ ...config,
187
+ };
188
+ const kept = [];
189
+ const suppressed = [];
190
+ for (const finding of findings) {
191
+ const exclusionReason = getExclusionReason(finding.filePath, mergedConfig);
192
+ if (shouldSuppressFinding(finding, exclusionReason)) {
193
+ suppressed.push({
194
+ finding,
195
+ reason: exclusionReason,
196
+ description: getExclusionDescription(exclusionReason),
197
+ });
198
+ }
199
+ else {
200
+ kept.push(finding);
201
+ }
202
+ }
203
+ return { kept, suppressed };
204
+ }
205
+ /**
206
+ * Get the default exclusion configuration
207
+ */
208
+ function getDefaultExclusionConfig() {
209
+ return { ...DEFAULT_EXCLUSIONS };
210
+ }
211
+ /**
212
+ * Merge custom exclusion patterns with defaults
213
+ */
214
+ function mergeExclusionConfig(custom) {
215
+ return {
216
+ testPatterns: [...DEFAULT_EXCLUSIONS.testPatterns, ...(custom.testPatterns || [])],
217
+ seedPatterns: [...DEFAULT_EXCLUSIONS.seedPatterns, ...(custom.seedPatterns || [])],
218
+ examplePatterns: [...DEFAULT_EXCLUSIONS.examplePatterns, ...(custom.examplePatterns || [])],
219
+ fixturePatterns: [...DEFAULT_EXCLUSIONS.fixturePatterns, ...(custom.fixturePatterns || [])],
220
+ };
221
+ }
222
+ //# sourceMappingURL=path-exclusions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path-exclusions.js","sourceRoot":"","sources":["../../src/utils/path-exclusions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Project Context Builder
3
+ *
4
+ * Builds a generic project context summary for AI validation by analyzing
5
+ * common patterns across the codebase. This context helps the AI validator
6
+ * understand the project's security architecture without hardcoding any
7
+ * specific framework or vendor.
8
+ *
9
+ * Key areas analyzed:
10
+ * - Authentication & access control patterns
11
+ * - Data access patterns (ORMs, query builders, raw queries)
12
+ * - Secrets & configuration handling
13
+ * - Framework detection
14
+ */
15
+ import type { ScanFile } from '../types';
16
+ import { type AuthHelperContext, type AuthHelper } from './auth-helper-detector';
17
+ import { type OAuthFlowContext } from './oauth-flow-detector';
18
+ import { type TRPCRouterContext } from './trpc-analyzer';
19
+ export interface ProjectContext {
20
+ /** Summary string for AI prompt injection */
21
+ summary: string;
22
+ /** Authentication & access control patterns */
23
+ auth: AuthContext;
24
+ /** Data access patterns */
25
+ dataAccess: DataAccessContext;
26
+ /** Secrets & configuration patterns */
27
+ secrets: SecretsContext;
28
+ /** Detected frameworks and libraries */
29
+ frameworks: FrameworkContext;
30
+ /** File structure insights */
31
+ structure: StructureContext;
32
+ /** OAuth flow context */
33
+ oauth: OAuthFlowContext;
34
+ /** tRPC router context */
35
+ trpc: TRPCRouterContext;
36
+ }
37
+ export interface AuthContext {
38
+ /** Whether global auth middleware is detected */
39
+ hasGlobalMiddleware: boolean;
40
+ /** Type of auth provider (clerk, nextauth, auth0, custom, unknown) */
41
+ authProvider?: string;
42
+ /** Middleware file path */
43
+ middlewareFile?: string;
44
+ /** Protected path patterns */
45
+ protectedPaths: string[];
46
+ /** Public/excluded path patterns */
47
+ publicPaths: string[];
48
+ /** Auth helper functions detected (names only) */
49
+ authHelpers: string[];
50
+ /** Full auth helper context with throwing/return info */
51
+ authHelperContext?: AuthHelperContext;
52
+ /** Throwing auth helpers that guarantee authenticated context */
53
+ throwingAuthHelpers: AuthHelper[];
54
+ /** Whether user scoping is used in queries */
55
+ hasUserScoping: boolean;
56
+ /** User scoping patterns found */
57
+ userScopingPatterns: string[];
58
+ }
59
+ export interface DataAccessContext {
60
+ /** ORM/query builder detected */
61
+ orm?: 'prisma' | 'drizzle' | 'supabase' | 'mongoose' | 'sequelize' | 'typeorm' | 'knex' | 'raw_sql' | 'unknown';
62
+ /** Whether parameterized queries are the default */
63
+ usesParameterizedQueries: boolean;
64
+ /** Database type if detectable */
65
+ databaseType?: 'postgres' | 'mysql' | 'mongodb' | 'sqlite' | 'unknown';
66
+ /** Whether RLS (Row Level Security) is mentioned */
67
+ hasRLS: boolean;
68
+ /** Data validation library detected */
69
+ validationLibrary?: string;
70
+ }
71
+ export interface SecretsContext {
72
+ /** Uses environment variables for secrets */
73
+ usesEnvVars: boolean;
74
+ /** Uses a secret manager */
75
+ usesSecretManager: boolean;
76
+ /** Secret manager type if detected */
77
+ secretManagerType?: string;
78
+ /** Has .env files */
79
+ hasEnvFiles: boolean;
80
+ /** Uses NEXT_PUBLIC_ pattern (client-exposed) */
81
+ hasClientExposedEnvVars: boolean;
82
+ }
83
+ export interface FrameworkContext {
84
+ /** Primary framework */
85
+ primary?: 'nextjs' | 'express' | 'fastify' | 'nestjs' | 'django' | 'flask' | 'rails' | 'unknown';
86
+ /** Frontend framework */
87
+ frontend?: 'react' | 'vue' | 'svelte' | 'angular' | 'unknown';
88
+ /** Is this a monorepo? */
89
+ isMonorepo: boolean;
90
+ /** Uses TypeScript */
91
+ usesTypeScript: boolean;
92
+ /** Uses server components (Next.js 13+) */
93
+ usesServerComponents: boolean;
94
+ /** Uses server actions */
95
+ usesServerActions: boolean;
96
+ }
97
+ export interface StructureContext {
98
+ /** Has API routes */
99
+ hasApiRoutes: boolean;
100
+ /** Has middleware */
101
+ hasMiddleware: boolean;
102
+ /** Has server actions */
103
+ hasServerActions: boolean;
104
+ /** Total files analyzed */
105
+ totalFiles: number;
106
+ /** File types breakdown */
107
+ fileTypes: Record<string, number>;
108
+ }
109
+ /**
110
+ * Build a comprehensive project context from scanned files
111
+ * This context is used to inform AI validation decisions
112
+ */
113
+ export declare function buildProjectContext(files: ScanFile[]): ProjectContext;
114
+ /**
115
+ * Generate a compact context string for a single file validation
116
+ * Used when validating findings in a specific file
117
+ */
118
+ export declare function getFileValidationContext(file: ScanFile, projectContext: ProjectContext): string;
119
+ //# sourceMappingURL=project-context-builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-context-builder.d.ts","sourceRoot":"","sources":["../../src/utils/project-context-builder.ts"],"names":[],"mappings":"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"}