@quantracode/vibecheck 0.0.1 → 0.0.2

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 (208) hide show
  1. package/README.md +6 -6
  2. package/dist/index.d.ts +0 -2
  3. package/dist/index.js +7902 -8
  4. package/package.json +13 -7
  5. package/dist/__tests__/cli.test.d.ts +0 -2
  6. package/dist/__tests__/cli.test.d.ts.map +0 -1
  7. package/dist/__tests__/cli.test.js +0 -243
  8. package/dist/__tests__/fixtures/safe-app/app/api/users/route.js +0 -36
  9. package/dist/__tests__/fixtures/vulnerable-app/app/api/users/route.js +0 -28
  10. package/dist/__tests__/fixtures/vulnerable-app/lib/config.d.ts +0 -4
  11. package/dist/__tests__/fixtures/vulnerable-app/lib/config.d.ts.map +0 -1
  12. package/dist/__tests__/fixtures/vulnerable-app/lib/config.js +0 -6
  13. package/dist/__tests__/scanners/env-config.test.d.ts +0 -2
  14. package/dist/__tests__/scanners/env-config.test.d.ts.map +0 -1
  15. package/dist/__tests__/scanners/env-config.test.js +0 -142
  16. package/dist/__tests__/scanners/nextjs-middleware.test.d.ts +0 -2
  17. package/dist/__tests__/scanners/nextjs-middleware.test.d.ts.map +0 -1
  18. package/dist/__tests__/scanners/nextjs-middleware.test.js +0 -193
  19. package/dist/__tests__/scanners/scanner-packs.test.d.ts +0 -2
  20. package/dist/__tests__/scanners/scanner-packs.test.d.ts.map +0 -1
  21. package/dist/__tests__/scanners/scanner-packs.test.js +0 -126
  22. package/dist/__tests__/scanners/unused-security-imports.test.d.ts +0 -2
  23. package/dist/__tests__/scanners/unused-security-imports.test.d.ts.map +0 -1
  24. package/dist/__tests__/scanners/unused-security-imports.test.js +0 -145
  25. package/dist/commands/demo-artifact.d.ts +0 -7
  26. package/dist/commands/demo-artifact.d.ts.map +0 -1
  27. package/dist/commands/demo-artifact.js +0 -322
  28. package/dist/commands/evaluate.d.ts +0 -30
  29. package/dist/commands/evaluate.d.ts.map +0 -1
  30. package/dist/commands/evaluate.js +0 -258
  31. package/dist/commands/explain.d.ts +0 -12
  32. package/dist/commands/explain.d.ts.map +0 -1
  33. package/dist/commands/explain.js +0 -214
  34. package/dist/commands/index.d.ts +0 -7
  35. package/dist/commands/index.d.ts.map +0 -1
  36. package/dist/commands/index.js +0 -6
  37. package/dist/commands/intent.d.ts +0 -21
  38. package/dist/commands/intent.d.ts.map +0 -1
  39. package/dist/commands/intent.js +0 -192
  40. package/dist/commands/scan.d.ts +0 -44
  41. package/dist/commands/scan.d.ts.map +0 -1
  42. package/dist/commands/scan.js +0 -497
  43. package/dist/commands/waivers.d.ts +0 -30
  44. package/dist/commands/waivers.d.ts.map +0 -1
  45. package/dist/commands/waivers.js +0 -249
  46. package/dist/index.d.ts.map +0 -1
  47. package/dist/phase3/index.d.ts +0 -11
  48. package/dist/phase3/index.d.ts.map +0 -1
  49. package/dist/phase3/index.js +0 -12
  50. package/dist/phase3/intent-miner.d.ts +0 -32
  51. package/dist/phase3/intent-miner.d.ts.map +0 -1
  52. package/dist/phase3/intent-miner.js +0 -323
  53. package/dist/phase3/proof-trace-builder.d.ts +0 -42
  54. package/dist/phase3/proof-trace-builder.d.ts.map +0 -1
  55. package/dist/phase3/proof-trace-builder.js +0 -441
  56. package/dist/phase3/scanners/auth-by-ui-server-gap.d.ts +0 -15
  57. package/dist/phase3/scanners/auth-by-ui-server-gap.d.ts.map +0 -1
  58. package/dist/phase3/scanners/auth-by-ui-server-gap.js +0 -237
  59. package/dist/phase3/scanners/comment-claim-unproven.d.ts +0 -14
  60. package/dist/phase3/scanners/comment-claim-unproven.d.ts.map +0 -1
  61. package/dist/phase3/scanners/comment-claim-unproven.js +0 -161
  62. package/dist/phase3/scanners/index.d.ts +0 -31
  63. package/dist/phase3/scanners/index.d.ts.map +0 -1
  64. package/dist/phase3/scanners/index.js +0 -40
  65. package/dist/phase3/scanners/middleware-assumed-not-matching.d.ts +0 -14
  66. package/dist/phase3/scanners/middleware-assumed-not-matching.d.ts.map +0 -1
  67. package/dist/phase3/scanners/middleware-assumed-not-matching.js +0 -172
  68. package/dist/phase3/scanners/validation-claimed-missing.d.ts +0 -15
  69. package/dist/phase3/scanners/validation-claimed-missing.d.ts.map +0 -1
  70. package/dist/phase3/scanners/validation-claimed-missing.js +0 -204
  71. package/dist/scanners/abuse/compute-abuse.d.ts +0 -20
  72. package/dist/scanners/abuse/compute-abuse.d.ts.map +0 -1
  73. package/dist/scanners/abuse/compute-abuse.js +0 -509
  74. package/dist/scanners/abuse/index.d.ts +0 -12
  75. package/dist/scanners/abuse/index.d.ts.map +0 -1
  76. package/dist/scanners/abuse/index.js +0 -15
  77. package/dist/scanners/auth/index.d.ts +0 -5
  78. package/dist/scanners/auth/index.d.ts.map +0 -1
  79. package/dist/scanners/auth/index.js +0 -10
  80. package/dist/scanners/auth/middleware-gap.d.ts +0 -22
  81. package/dist/scanners/auth/middleware-gap.d.ts.map +0 -1
  82. package/dist/scanners/auth/middleware-gap.js +0 -203
  83. package/dist/scanners/auth/unprotected-api-route.d.ts +0 -12
  84. package/dist/scanners/auth/unprotected-api-route.d.ts.map +0 -1
  85. package/dist/scanners/auth/unprotected-api-route.js +0 -126
  86. package/dist/scanners/config/index.d.ts +0 -5
  87. package/dist/scanners/config/index.d.ts.map +0 -1
  88. package/dist/scanners/config/index.js +0 -10
  89. package/dist/scanners/config/insecure-defaults.d.ts +0 -12
  90. package/dist/scanners/config/insecure-defaults.d.ts.map +0 -1
  91. package/dist/scanners/config/insecure-defaults.js +0 -77
  92. package/dist/scanners/config/undocumented-env.d.ts +0 -24
  93. package/dist/scanners/config/undocumented-env.d.ts.map +0 -1
  94. package/dist/scanners/config/undocumented-env.js +0 -159
  95. package/dist/scanners/crypto/index.d.ts +0 -6
  96. package/dist/scanners/crypto/index.d.ts.map +0 -1
  97. package/dist/scanners/crypto/index.js +0 -11
  98. package/dist/scanners/crypto/jwt-decode-unverified.d.ts +0 -14
  99. package/dist/scanners/crypto/jwt-decode-unverified.d.ts.map +0 -1
  100. package/dist/scanners/crypto/jwt-decode-unverified.js +0 -87
  101. package/dist/scanners/crypto/math-random-tokens.d.ts +0 -13
  102. package/dist/scanners/crypto/math-random-tokens.d.ts.map +0 -1
  103. package/dist/scanners/crypto/math-random-tokens.js +0 -80
  104. package/dist/scanners/crypto/weak-hashing.d.ts +0 -11
  105. package/dist/scanners/crypto/weak-hashing.d.ts.map +0 -1
  106. package/dist/scanners/crypto/weak-hashing.js +0 -95
  107. package/dist/scanners/env-config.d.ts +0 -24
  108. package/dist/scanners/env-config.d.ts.map +0 -1
  109. package/dist/scanners/env-config.js +0 -164
  110. package/dist/scanners/hallucinations/index.d.ts +0 -4
  111. package/dist/scanners/hallucinations/index.d.ts.map +0 -1
  112. package/dist/scanners/hallucinations/index.js +0 -8
  113. package/dist/scanners/hallucinations/unused-security-imports.d.ts +0 -36
  114. package/dist/scanners/hallucinations/unused-security-imports.d.ts.map +0 -1
  115. package/dist/scanners/hallucinations/unused-security-imports.js +0 -309
  116. package/dist/scanners/helpers/ast-helpers.d.ts +0 -6
  117. package/dist/scanners/helpers/ast-helpers.d.ts.map +0 -1
  118. package/dist/scanners/helpers/ast-helpers.js +0 -945
  119. package/dist/scanners/helpers/context-builder.d.ts +0 -17
  120. package/dist/scanners/helpers/context-builder.d.ts.map +0 -1
  121. package/dist/scanners/helpers/context-builder.js +0 -148
  122. package/dist/scanners/helpers/index.d.ts +0 -3
  123. package/dist/scanners/helpers/index.d.ts.map +0 -1
  124. package/dist/scanners/helpers/index.js +0 -2
  125. package/dist/scanners/index.d.ts +0 -30
  126. package/dist/scanners/index.d.ts.map +0 -1
  127. package/dist/scanners/index.js +0 -102
  128. package/dist/scanners/middleware/index.d.ts +0 -4
  129. package/dist/scanners/middleware/index.d.ts.map +0 -1
  130. package/dist/scanners/middleware/index.js +0 -7
  131. package/dist/scanners/middleware/missing-rate-limit.d.ts +0 -13
  132. package/dist/scanners/middleware/missing-rate-limit.d.ts.map +0 -1
  133. package/dist/scanners/middleware/missing-rate-limit.js +0 -140
  134. package/dist/scanners/network/cors-misconfiguration.d.ts +0 -14
  135. package/dist/scanners/network/cors-misconfiguration.d.ts.map +0 -1
  136. package/dist/scanners/network/cors-misconfiguration.js +0 -89
  137. package/dist/scanners/network/index.d.ts +0 -7
  138. package/dist/scanners/network/index.d.ts.map +0 -1
  139. package/dist/scanners/network/index.js +0 -18
  140. package/dist/scanners/network/missing-timeout.d.ts +0 -15
  141. package/dist/scanners/network/missing-timeout.d.ts.map +0 -1
  142. package/dist/scanners/network/missing-timeout.js +0 -93
  143. package/dist/scanners/network/open-redirect.d.ts +0 -15
  144. package/dist/scanners/network/open-redirect.d.ts.map +0 -1
  145. package/dist/scanners/network/open-redirect.js +0 -88
  146. package/dist/scanners/network/ssrf-prone-fetch.d.ts +0 -12
  147. package/dist/scanners/network/ssrf-prone-fetch.d.ts.map +0 -1
  148. package/dist/scanners/network/ssrf-prone-fetch.js +0 -90
  149. package/dist/scanners/nextjs-middleware.d.ts +0 -26
  150. package/dist/scanners/nextjs-middleware.d.ts.map +0 -1
  151. package/dist/scanners/nextjs-middleware.js +0 -246
  152. package/dist/scanners/privacy/debug-flags.d.ts +0 -13
  153. package/dist/scanners/privacy/debug-flags.d.ts.map +0 -1
  154. package/dist/scanners/privacy/debug-flags.js +0 -124
  155. package/dist/scanners/privacy/index.d.ts +0 -6
  156. package/dist/scanners/privacy/index.d.ts.map +0 -1
  157. package/dist/scanners/privacy/index.js +0 -11
  158. package/dist/scanners/privacy/over-broad-response.d.ts +0 -15
  159. package/dist/scanners/privacy/over-broad-response.d.ts.map +0 -1
  160. package/dist/scanners/privacy/over-broad-response.js +0 -109
  161. package/dist/scanners/privacy/sensitive-logging.d.ts +0 -11
  162. package/dist/scanners/privacy/sensitive-logging.d.ts.map +0 -1
  163. package/dist/scanners/privacy/sensitive-logging.js +0 -78
  164. package/dist/scanners/types.d.ts +0 -456
  165. package/dist/scanners/types.d.ts.map +0 -1
  166. package/dist/scanners/types.js +0 -16
  167. package/dist/scanners/unused-security-imports.d.ts +0 -34
  168. package/dist/scanners/unused-security-imports.d.ts.map +0 -1
  169. package/dist/scanners/unused-security-imports.js +0 -206
  170. package/dist/scanners/uploads/index.d.ts +0 -5
  171. package/dist/scanners/uploads/index.d.ts.map +0 -1
  172. package/dist/scanners/uploads/index.js +0 -9
  173. package/dist/scanners/uploads/missing-constraints.d.ts +0 -15
  174. package/dist/scanners/uploads/missing-constraints.d.ts.map +0 -1
  175. package/dist/scanners/uploads/missing-constraints.js +0 -109
  176. package/dist/scanners/uploads/public-path.d.ts +0 -11
  177. package/dist/scanners/uploads/public-path.d.ts.map +0 -1
  178. package/dist/scanners/uploads/public-path.js +0 -87
  179. package/dist/scanners/validation/client-side-only.d.ts +0 -14
  180. package/dist/scanners/validation/client-side-only.d.ts.map +0 -1
  181. package/dist/scanners/validation/client-side-only.js +0 -140
  182. package/dist/scanners/validation/ignored-validation.d.ts +0 -12
  183. package/dist/scanners/validation/ignored-validation.d.ts.map +0 -1
  184. package/dist/scanners/validation/ignored-validation.js +0 -119
  185. package/dist/scanners/validation/index.d.ts +0 -5
  186. package/dist/scanners/validation/index.d.ts.map +0 -1
  187. package/dist/scanners/validation/index.js +0 -9
  188. package/dist/utils/exclude-patterns.d.ts +0 -35
  189. package/dist/utils/exclude-patterns.d.ts.map +0 -1
  190. package/dist/utils/exclude-patterns.js +0 -78
  191. package/dist/utils/file-utils.d.ts +0 -37
  192. package/dist/utils/file-utils.d.ts.map +0 -1
  193. package/dist/utils/file-utils.js +0 -77
  194. package/dist/utils/fingerprint.d.ts +0 -25
  195. package/dist/utils/fingerprint.d.ts.map +0 -1
  196. package/dist/utils/fingerprint.js +0 -28
  197. package/dist/utils/git-info.d.ts +0 -14
  198. package/dist/utils/git-info.d.ts.map +0 -1
  199. package/dist/utils/git-info.js +0 -55
  200. package/dist/utils/index.d.ts +0 -4
  201. package/dist/utils/index.d.ts.map +0 -1
  202. package/dist/utils/index.js +0 -3
  203. package/dist/utils/progress.d.ts +0 -42
  204. package/dist/utils/progress.d.ts.map +0 -1
  205. package/dist/utils/progress.js +0 -165
  206. package/dist/utils/sarif-formatter.d.ts +0 -92
  207. package/dist/utils/sarif-formatter.d.ts.map +0 -1
  208. package/dist/utils/sarif-formatter.js +0 -172
@@ -1,509 +0,0 @@
1
- import { resolvePath } from "../../utils/file-utils.js";
2
- import { generateFingerprint, generateFindingId } from "../../utils/fingerprint.js";
3
- // ============================================================================
4
- // Rule IDs
5
- // ============================================================================
6
- const RULE_IDS = {
7
- AI_GENERATION: "VC-ABUSE-001",
8
- CODE_EXECUTION: "VC-ABUSE-002",
9
- FILE_PROCESSING: "VC-ABUSE-003",
10
- EXPENSIVE_ENDPOINT: "VC-ABUSE-004",
11
- };
12
- // ============================================================================
13
- // Pattern Definitions
14
- // ============================================================================
15
- /**
16
- * Route patterns that indicate compute-intensive operations
17
- */
18
- const ROUTE_PATTERNS = {
19
- AI_GENERATION: [
20
- /generate[-_]?/i,
21
- /chat[-_]?completion/i,
22
- /completion/i,
23
- /embed[-_]?/i,
24
- /transcribe/i,
25
- /translate/i,
26
- /summarize/i,
27
- /code[-_]?expert/i,
28
- /ai[-_]?/i,
29
- /llm[-_]?/i,
30
- /gpt[-_]?/i,
31
- /claude[-_]?/i,
32
- /openai/i,
33
- /anthropic/i,
34
- ],
35
- CODE_EXECUTION: [
36
- /eval[-_]?/i,
37
- /execute[-_]?/i,
38
- /run[-_]?code/i,
39
- /sandbox/i,
40
- /repl/i,
41
- /compile/i,
42
- /interpret/i,
43
- ],
44
- FILE_PROCESSING: [
45
- /parse[-_]?/i,
46
- /convert[-_]?/i,
47
- /transform[-_]?/i,
48
- /process[-_]?file/i,
49
- /upload[-_]?/i,
50
- /import[-_]?/i,
51
- /export[-_]?/i,
52
- /render[-_]?/i,
53
- /resize[-_]?/i,
54
- /thumbnail/i,
55
- /pdf[-_]?/i,
56
- /image[-_]?/i,
57
- /video[-_]?/i,
58
- /audio[-_]?/i,
59
- ],
60
- DATA_EXPORT: [
61
- /bulk[-_]?/i,
62
- /batch[-_]?/i,
63
- /export[-_]?all/i,
64
- /download[-_]?all/i,
65
- /dump/i,
66
- ],
67
- };
68
- /**
69
- * Import patterns that indicate expensive operations
70
- */
71
- const EXPENSIVE_IMPORT_PATTERNS = [
72
- // AI/LLM SDKs
73
- { pattern: /openai/i, category: "ai_generation", costMultiplier: 100 },
74
- { pattern: /@anthropic-ai\/sdk/i, category: "ai_generation", costMultiplier: 100 },
75
- { pattern: /langchain/i, category: "ai_generation", costMultiplier: 100 },
76
- { pattern: /cohere/i, category: "ai_generation", costMultiplier: 80 },
77
- { pattern: /replicate/i, category: "ai_generation", costMultiplier: 150 },
78
- { pattern: /@huggingface/i, category: "ai_generation", costMultiplier: 50 },
79
- // Code execution
80
- { pattern: /vm2?/i, category: "code_execution", costMultiplier: 50 },
81
- { pattern: /isolated-vm/i, category: "code_execution", costMultiplier: 50 },
82
- { pattern: /child_process/i, category: "code_execution", costMultiplier: 30 },
83
- // File processing
84
- { pattern: /sharp/i, category: "file_processing", costMultiplier: 20 },
85
- { pattern: /jimp/i, category: "file_processing", costMultiplier: 15 },
86
- { pattern: /pdf-lib/i, category: "file_processing", costMultiplier: 25 },
87
- { pattern: /pdfkit/i, category: "file_processing", costMultiplier: 25 },
88
- { pattern: /puppeteer/i, category: "file_processing", costMultiplier: 100 },
89
- { pattern: /playwright/i, category: "file_processing", costMultiplier: 100 },
90
- { pattern: /ffmpeg/i, category: "file_processing", costMultiplier: 200 },
91
- { pattern: /fluent-ffmpeg/i, category: "file_processing", costMultiplier: 200 },
92
- // External APIs
93
- { pattern: /stripe/i, category: "external_api", costMultiplier: 10 },
94
- { pattern: /twilio/i, category: "external_api", costMultiplier: 20 },
95
- { pattern: /sendgrid/i, category: "external_api", costMultiplier: 5 },
96
- { pattern: /aws-sdk/i, category: "external_api", costMultiplier: 15 },
97
- { pattern: /@aws-sdk/i, category: "external_api", costMultiplier: 15 },
98
- ];
99
- /**
100
- * Function call patterns that indicate expensive operations
101
- */
102
- const EXPENSIVE_CALL_PATTERNS = [
103
- // OpenAI
104
- { pattern: /\.chat\.completions\.create/i, category: "ai_generation", costMultiplier: 100 },
105
- { pattern: /\.completions\.create/i, category: "ai_generation", costMultiplier: 100 },
106
- { pattern: /\.embeddings\.create/i, category: "ai_generation", costMultiplier: 20 },
107
- { pattern: /\.images\.generate/i, category: "ai_generation", costMultiplier: 500 },
108
- { pattern: /\.audio\.transcriptions/i, category: "ai_generation", costMultiplier: 50 },
109
- // Anthropic
110
- { pattern: /\.messages\.create/i, category: "ai_generation", costMultiplier: 100 },
111
- // Generic AI
112
- { pattern: /generateText/i, category: "ai_generation", costMultiplier: 80 },
113
- { pattern: /streamText/i, category: "ai_generation", costMultiplier: 80 },
114
- // Code execution
115
- { pattern: /eval\s*\(/i, category: "code_execution", costMultiplier: 50 },
116
- { pattern: /new\s+Function\s*\(/i, category: "code_execution", costMultiplier: 50 },
117
- { pattern: /vm\.run/i, category: "code_execution", costMultiplier: 50 },
118
- { pattern: /exec\s*\(/i, category: "code_execution", costMultiplier: 30 },
119
- { pattern: /spawn\s*\(/i, category: "code_execution", costMultiplier: 30 },
120
- // File processing
121
- { pattern: /sharp\s*\(/i, category: "file_processing", costMultiplier: 20 },
122
- { pattern: /\.resize\s*\(/i, category: "file_processing", costMultiplier: 15 },
123
- { pattern: /\.toBuffer\s*\(/i, category: "file_processing", costMultiplier: 10 },
124
- { pattern: /puppeteer.*launch/i, category: "file_processing", costMultiplier: 100 },
125
- { pattern: /page\.pdf\s*\(/i, category: "file_processing", costMultiplier: 50 },
126
- { pattern: /page\.screenshot\s*\(/i, category: "file_processing", costMultiplier: 30 },
127
- ];
128
- /**
129
- * Check for auth enforcement patterns
130
- */
131
- function detectAuthEnforcement(functionNode, helpers) {
132
- return helpers.containsAuthCheck(functionNode);
133
- }
134
- /**
135
- * Check for rate limit patterns
136
- */
137
- function detectRateLimitEnforcement(sourceFile, helpers) {
138
- return helpers.hasRateLimitSignals(sourceFile);
139
- }
140
- /**
141
- * Check for request size limit patterns
142
- */
143
- function detectRequestSizeLimit(functionNode, helpers) {
144
- const text = helpers.getNodeText(functionNode);
145
- const patterns = [
146
- /content-length/i,
147
- /maxBodyLength/i,
148
- /bodyParser.*limit/i,
149
- /\.size\s*[<>]/i,
150
- /MAX_SIZE/i,
151
- /sizeLimit/i,
152
- /maxSize/i,
153
- /fileSizeLimit/i,
154
- ];
155
- return patterns.some(p => p.test(text));
156
- }
157
- /**
158
- * Check for timeout patterns
159
- */
160
- function detectTimeoutEnforcement(functionNode, helpers) {
161
- const text = helpers.getNodeText(functionNode);
162
- const patterns = [
163
- /timeout/i,
164
- /AbortController/i,
165
- /signal/i,
166
- /setTimeout/i,
167
- /maxDuration/i,
168
- ];
169
- return patterns.some(p => p.test(text));
170
- }
171
- /**
172
- * Check for input validation patterns
173
- */
174
- function detectInputValidation(functionNode, helpers) {
175
- const validationUsage = helpers.findValidationUsage(functionNode);
176
- return validationUsage.length > 0;
177
- }
178
- /**
179
- * Get all enforcement status for a handler
180
- */
181
- function getEnforcementStatus(functionNode, sourceFile, helpers) {
182
- return {
183
- hasAuth: detectAuthEnforcement(functionNode, helpers),
184
- hasRateLimit: detectRateLimitEnforcement(sourceFile, helpers),
185
- hasRequestSizeLimit: detectRequestSizeLimit(functionNode, helpers),
186
- hasTimeout: detectTimeoutEnforcement(functionNode, helpers),
187
- hasInputValidation: detectInputValidation(functionNode, helpers),
188
- };
189
- }
190
- /**
191
- * Get list of missing enforcements
192
- */
193
- function getMissingEnforcements(status) {
194
- const missing = [];
195
- if (!status.hasAuth)
196
- missing.push("auth");
197
- if (!status.hasRateLimit)
198
- missing.push("rate_limit");
199
- if (!status.hasRequestSizeLimit)
200
- missing.push("request_size_limit");
201
- if (!status.hasTimeout)
202
- missing.push("timeout");
203
- if (!status.hasInputValidation)
204
- missing.push("input_validation");
205
- return missing;
206
- }
207
- /**
208
- * Check if route path matches abuse patterns
209
- */
210
- function matchRoutePatterns(routePath) {
211
- for (const [category, patterns] of Object.entries(ROUTE_PATTERNS)) {
212
- for (const pattern of patterns) {
213
- if (pattern.test(routePath)) {
214
- const categoryMap = {
215
- AI_GENERATION: "ai_generation",
216
- CODE_EXECUTION: "code_execution",
217
- FILE_PROCESSING: "file_processing",
218
- DATA_EXPORT: "data_export",
219
- };
220
- return {
221
- category: categoryMap[category] || "computation",
222
- costMultiplier: category === "AI_GENERATION" ? 100 :
223
- category === "CODE_EXECUTION" ? 50 :
224
- category === "FILE_PROCESSING" ? 25 : 10,
225
- matchedPattern: pattern.source,
226
- matchType: "route",
227
- };
228
- }
229
- }
230
- }
231
- return null;
232
- }
233
- /**
234
- * Check for expensive imports in file
235
- */
236
- function findExpensiveImports(sourceFile) {
237
- const matches = [];
238
- const imports = sourceFile.getImportDeclarations();
239
- for (const imp of imports) {
240
- const moduleSpecifier = imp.getModuleSpecifierValue();
241
- for (const { pattern, category, costMultiplier } of EXPENSIVE_IMPORT_PATTERNS) {
242
- if (pattern.test(moduleSpecifier)) {
243
- matches.push({
244
- category,
245
- costMultiplier,
246
- matchedPattern: moduleSpecifier,
247
- matchType: "import",
248
- });
249
- break;
250
- }
251
- }
252
- }
253
- return matches;
254
- }
255
- /**
256
- * Check for expensive function calls in handler
257
- */
258
- function findExpensiveCalls(functionNode, helpers) {
259
- const matches = [];
260
- const text = helpers.getNodeText(functionNode);
261
- for (const { pattern, category, costMultiplier } of EXPENSIVE_CALL_PATTERNS) {
262
- if (pattern.test(text)) {
263
- matches.push({
264
- category,
265
- costMultiplier,
266
- matchedPattern: pattern.source,
267
- matchType: "call",
268
- });
269
- }
270
- }
271
- return matches;
272
- }
273
- /**
274
- * Calculate abuse risk based on cost multiplier and missing enforcements
275
- */
276
- function calculateAbuseRisk(costMultiplier, missingCount) {
277
- // High cost + many missing enforcements = critical
278
- if (costMultiplier >= 100 && missingCount >= 3)
279
- return "critical";
280
- if (costMultiplier >= 50 && missingCount >= 2)
281
- return "high";
282
- if (costMultiplier >= 20 && missingCount >= 1)
283
- return "medium";
284
- if (missingCount >= 2)
285
- return "medium";
286
- return "low";
287
- }
288
- /**
289
- * Get route path from file path (Next.js App Router)
290
- */
291
- function getRoutePathFromFile(filePath) {
292
- // Convert app/api/generate/route.ts -> /api/generate
293
- const match = filePath.match(/app(\/api\/[^/]+(?:\/[^/]+)*?)\/route\.[tj]sx?$/);
294
- if (match) {
295
- return match[1].replace(/\\/g, "/");
296
- }
297
- // Handle dynamic routes [param] -> :param
298
- return filePath
299
- .replace(/.*?app/, "")
300
- .replace(/\/route\.[tj]sx?$/, "")
301
- .replace(/\[([^\]]+)\]/g, ":$1")
302
- .replace(/\\/g, "/");
303
- }
304
- // ============================================================================
305
- // Main Scanner
306
- // ============================================================================
307
- /**
308
- * VC-ABUSE-001 to VC-ABUSE-004: Compute Abuse Detection
309
- *
310
- * Detects compute-intensive endpoints that may be vulnerable to abuse:
311
- * - AI/LLM generation endpoints
312
- * - Code execution endpoints
313
- * - File processing endpoints
314
- * - Expensive API endpoints
315
- *
316
- * Checks for missing enforcement:
317
- * - Authentication
318
- * - Rate limiting
319
- * - Request size limits
320
- * - Timeouts
321
- * - Input validation
322
- */
323
- export async function scanComputeAbuse(context) {
324
- const { repoRoot, fileIndex, helpers } = context;
325
- const findings = [];
326
- for (const relPath of fileIndex.apiRouteFiles) {
327
- const absPath = resolvePath(repoRoot, relPath);
328
- const sourceFile = helpers.parseFile(absPath);
329
- if (!sourceFile)
330
- continue;
331
- const handlers = helpers.findRouteHandlers(sourceFile);
332
- const routePath = getRoutePathFromFile(relPath);
333
- const fileImports = findExpensiveImports(sourceFile);
334
- for (const handler of handlers) {
335
- // Collect all abuse matches
336
- const allMatches = [];
337
- // Check route patterns
338
- const routeMatch = matchRoutePatterns(routePath);
339
- if (routeMatch) {
340
- allMatches.push(routeMatch);
341
- }
342
- // Check expensive calls in handler
343
- const callMatches = findExpensiveCalls(handler.functionNode, helpers);
344
- allMatches.push(...callMatches);
345
- // Check expensive imports
346
- allMatches.push(...fileImports);
347
- // Skip if no abuse patterns matched
348
- if (allMatches.length === 0)
349
- continue;
350
- // Get enforcement status
351
- const enforcement = getEnforcementStatus(handler.functionNode, sourceFile, helpers);
352
- const missingEnforcements = getMissingEnforcements(enforcement);
353
- // Skip if all enforcements are present
354
- if (missingEnforcements.length === 0)
355
- continue;
356
- // Use highest cost multiplier
357
- const maxCost = Math.max(...allMatches.map(m => m.costMultiplier));
358
- const primaryMatch = allMatches.find(m => m.costMultiplier === maxCost) || allMatches[0];
359
- // Calculate risk
360
- const risk = calculateAbuseRisk(maxCost, missingEnforcements.length);
361
- // Determine severity based on risk
362
- const severityMap = {
363
- critical: "critical",
364
- high: "high",
365
- medium: "medium",
366
- low: "low",
367
- };
368
- // Determine rule ID based on category
369
- const ruleId = primaryMatch.category === "ai_generation" ? RULE_IDS.AI_GENERATION :
370
- primaryMatch.category === "code_execution" ? RULE_IDS.CODE_EXECUTION :
371
- primaryMatch.category === "file_processing" ? RULE_IDS.FILE_PROCESSING :
372
- RULE_IDS.EXPENSIVE_ENDPOINT;
373
- const handlerText = helpers.getNodeText(handler.functionNode);
374
- const evidence = [
375
- {
376
- file: relPath,
377
- startLine: handler.startLine,
378
- endLine: handler.endLine,
379
- snippet: handlerText.slice(0, 300) + (handlerText.length > 300 ? "..." : ""),
380
- label: `${handler.method} handler with ${primaryMatch.category.replace(/_/g, " ")} pattern`,
381
- },
382
- ];
383
- // Add match evidence
384
- for (const match of allMatches.slice(0, 3)) {
385
- evidence.push({
386
- file: relPath,
387
- startLine: handler.startLine,
388
- endLine: handler.startLine,
389
- snippet: `Matched: ${match.matchedPattern} (${match.matchType})`,
390
- label: `${match.category.replace(/_/g, " ")} pattern (${match.costMultiplier}x cost)`,
391
- });
392
- }
393
- const fingerprint = generateFingerprint({
394
- ruleId,
395
- file: relPath,
396
- symbol: `${handler.method}:${primaryMatch.category}`,
397
- startLine: handler.startLine,
398
- });
399
- const abuseClassification = {
400
- risk,
401
- category: primaryMatch.category,
402
- costAmplification: maxCost,
403
- missingEnforcement: missingEnforcements,
404
- confidence: 0.75,
405
- };
406
- findings.push({
407
- id: generateFindingId({
408
- ruleId,
409
- file: relPath,
410
- symbol: `${handler.method}:${primaryMatch.category}`,
411
- startLine: handler.startLine,
412
- }),
413
- ruleId,
414
- title: `${risk.charAt(0).toUpperCase() + risk.slice(1)} compute abuse risk: ${primaryMatch.category.replace(/_/g, " ")} endpoint`,
415
- description: generateDescription(primaryMatch, missingEnforcements, maxCost, routePath),
416
- severity: severityMap[risk],
417
- confidence: abuseClassification.confidence,
418
- category: "abuse",
419
- evidence,
420
- remediation: generateRemediation(primaryMatch.category, missingEnforcements),
421
- links: {
422
- owasp: "https://cheatsheetseries.owasp.org/cheatsheets/Denial_of_Service_Cheat_Sheet.html",
423
- cwe: "https://cwe.mitre.org/data/definitions/770.html",
424
- },
425
- fingerprint,
426
- abuseClassification,
427
- });
428
- }
429
- }
430
- return findings;
431
- }
432
- /**
433
- * Generate finding description
434
- */
435
- function generateDescription(match, missing, costMultiplier, routePath) {
436
- const categoryDescriptions = {
437
- ai_generation: "AI/LLM operations that consume significant compute resources and API costs",
438
- code_execution: "code execution capabilities that can be abused for cryptomining or resource exhaustion",
439
- file_processing: "file processing operations that can be abused with large or malicious files",
440
- external_api: "expensive external API calls that incur per-request costs",
441
- computation: "CPU-intensive operations vulnerable to resource exhaustion",
442
- data_export: "bulk data operations that can be abused to extract large datasets",
443
- upload_processing: "file upload processing that can be exploited with oversized files",
444
- };
445
- const missingText = missing.map(m => m.replace(/_/g, " ")).join(", ");
446
- return `This endpoint (${routePath}) performs ${categoryDescriptions[match.category]}. ` +
447
- `Without proper controls, attackers can abuse this endpoint causing significant financial damage or service degradation. ` +
448
- `Estimated cost amplification: ${costMultiplier}x per request. ` +
449
- `Missing enforcement: ${missingText}.`;
450
- }
451
- /**
452
- * Generate remediation based on category and missing enforcements
453
- */
454
- function generateRemediation(category, missing) {
455
- const patches = [];
456
- if (missing.includes("auth")) {
457
- patches.push(`// Add authentication
458
- const session = await getServerSession(authOptions);
459
- if (!session) {
460
- return Response.json({ error: "Unauthorized" }, { status: 401 });
461
- }`);
462
- }
463
- if (missing.includes("rate_limit")) {
464
- patches.push(`// Add rate limiting
465
- import { Ratelimit } from "@upstash/ratelimit";
466
- const ratelimit = new Ratelimit({
467
- redis: kv,
468
- limiter: Ratelimit.slidingWindow(10, "60 s"),
469
- });
470
- const { success } = await ratelimit.limit(userId);
471
- if (!success) {
472
- return Response.json({ error: "Rate limit exceeded" }, { status: 429 });
473
- }`);
474
- }
475
- if (missing.includes("request_size_limit")) {
476
- patches.push(`// Add request size limit
477
- const body = await request.json();
478
- const size = JSON.stringify(body).length;
479
- if (size > 100 * 1024) { // 100KB limit
480
- return Response.json({ error: "Request too large" }, { status: 413 });
481
- }`);
482
- }
483
- if (missing.includes("timeout")) {
484
- patches.push(`// Add timeout
485
- const controller = new AbortController();
486
- const timeout = setTimeout(() => controller.abort(), 30000); // 30s timeout
487
- try {
488
- const result = await expensiveOperation({ signal: controller.signal });
489
- } finally {
490
- clearTimeout(timeout);
491
- }`);
492
- }
493
- if (missing.includes("input_validation")) {
494
- patches.push(`// Add input validation
495
- import { z } from "zod";
496
- const schema = z.object({
497
- prompt: z.string().max(4000),
498
- model: z.enum(["gpt-4", "gpt-3.5-turbo"]),
499
- });
500
- const { success, data } = schema.safeParse(body);
501
- if (!success) {
502
- return Response.json({ error: "Invalid input" }, { status: 400 });
503
- }`);
504
- }
505
- return {
506
- recommendedFix: `Add the following enforcement controls to protect against compute abuse: ${missing.map(m => m.replace(/_/g, " ")).join(", ")}.`,
507
- patch: patches.join("\n\n"),
508
- };
509
- }
@@ -1,12 +0,0 @@
1
- import type { ScannerPack } from "../types.js";
2
- /**
3
- * Abuse detection scanner pack
4
- *
5
- * Detects compute-intensive endpoints vulnerable to abuse:
6
- * - AI/LLM generation endpoints without rate limiting
7
- * - Code execution endpoints without sandboxing
8
- * - File processing endpoints without size limits
9
- * - Expensive API calls without authentication
10
- */
11
- export declare const abusePack: ScannerPack;
12
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/scanners/abuse/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C;;;;;;;;GAQG;AACH,eAAO,MAAM,SAAS,EAAE,WAIvB,CAAC"}
@@ -1,15 +0,0 @@
1
- import { scanComputeAbuse } from "./compute-abuse.js";
2
- /**
3
- * Abuse detection scanner pack
4
- *
5
- * Detects compute-intensive endpoints vulnerable to abuse:
6
- * - AI/LLM generation endpoints without rate limiting
7
- * - Code execution endpoints without sandboxing
8
- * - File processing endpoints without size limits
9
- * - Expensive API calls without authentication
10
- */
11
- export const abusePack = {
12
- id: "abuse",
13
- name: "Compute Abuse Detection",
14
- scanners: [scanComputeAbuse],
15
- };
@@ -1,5 +0,0 @@
1
- import type { ScannerPack } from "../types.js";
2
- export declare const authPack: ScannerPack;
3
- export { scanUnprotectedApiRoutes } from "./unprotected-api-route.js";
4
- export { scanMiddlewareGap, parseMatcherConfig, matcherCoversApi } from "./middleware-gap.js";
5
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/scanners/auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI/C,eAAO,MAAM,QAAQ,EAAE,WAItB,CAAC;AAGF,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC"}
@@ -1,10 +0,0 @@
1
- import { scanUnprotectedApiRoutes } from "./unprotected-api-route.js";
2
- import { scanMiddlewareGap } from "./middleware-gap.js";
3
- export const authPack = {
4
- id: "auth",
5
- name: "Authentication & Authorization",
6
- scanners: [scanUnprotectedApiRoutes, scanMiddlewareGap],
7
- };
8
- // Re-export individual scanners and utilities for testing
9
- export { scanUnprotectedApiRoutes } from "./unprotected-api-route.js";
10
- export { scanMiddlewareGap, parseMatcherConfig, matcherCoversApi } from "./middleware-gap.js";
@@ -1,22 +0,0 @@
1
- import type { Finding } from "@vibecheck/schema";
2
- import type { ScanContext } from "../types.js";
3
- /**
4
- * Parse matcher config from middleware file
5
- *
6
- * Looks for patterns like:
7
- * - export const config = { matcher: '/api/:path*' }
8
- * - export const config = { matcher: ['/api/:path*', '/admin/:path*'] }
9
- */
10
- export declare function parseMatcherConfig(content: string): string[] | null;
11
- /**
12
- * Check if any matcher pattern covers /api routes
13
- */
14
- export declare function matcherCoversApi(matchers: string[]): boolean;
15
- /**
16
- * VC-MW-001: Middleware matcher gap for /api coverage
17
- * VC-AUTH-INFO-001: Missing middleware with next-auth
18
- *
19
- * Checks if middleware properly covers API routes
20
- */
21
- export declare function scanMiddlewareGap(context: ScanContext): Promise<Finding[]>;
22
- //# sourceMappingURL=middleware-gap.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"middleware-gap.d.ts","sourceRoot":"","sources":["../../../src/scanners/auth/middleware-gap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAgB,MAAM,mBAAmB,CAAC;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAO/C;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,CAkCnE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAyB5D;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAuJhF"}