@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,237 +0,0 @@
1
- /**
2
- * VC-AUTH-010: Auth-by-UI with Server Gap
3
- *
4
- * Detects patterns where authentication appears to be enforced only
5
- * on the client side (via useSession, conditionally rendering UI, etc.)
6
- * but the corresponding API routes lack server-side auth checks.
7
- *
8
- * Severity: Critical
9
- * Category: auth
10
- * Confidence: 0.85
11
- */
12
- import crypto from "node:crypto";
13
- import path from "node:path";
14
- import { buildRouteMap, buildAllProofTraces } from "../proof-trace-builder.js";
15
- const RULE_ID = "VC-AUTH-010";
16
- /**
17
- * Client-side auth patterns that suggest UI-level protection
18
- */
19
- const CLIENT_AUTH_PATTERNS = [
20
- // React/Next.js session hooks
21
- /\buseSession\s*\(/,
22
- /\buseAuth\s*\(/,
23
- /\buseUser\s*\(/,
24
- /\bsession\s*&&/,
25
- /\bsession\s*\?/,
26
- /\bisAuthenticated\s*&&/,
27
- /\bisLoggedIn\s*&&/,
28
- // Conditional rendering based on auth
29
- /{\s*session\s*&&/,
30
- /{\s*user\s*&&/,
31
- /{\s*isAuthenticated\s*&&/,
32
- // Auth redirects in client components
33
- /redirect\([^)]*login/i,
34
- /router\.push\([^)]*login/i,
35
- /useRouter.*login/i,
36
- ];
37
- /**
38
- * Patterns indicating the component makes API calls
39
- */
40
- const API_CALL_PATTERNS = [
41
- // Fetch to API routes
42
- /fetch\s*\(\s*['"`]\/api\//,
43
- /fetch\s*\(\s*['"`]\.\.?\/api\//,
44
- // Axios to API routes
45
- /axios\.[a-z]+\s*\(\s*['"`]\/api\//,
46
- // Form actions
47
- /action\s*=\s*['"`]\/api\//,
48
- // SWR/React Query to API routes
49
- /useSWR\s*\(\s*['"`]\/api\//,
50
- /useQuery\s*\([^)]*['"`]\/api\//,
51
- ];
52
- export async function scanAuthByUiServerGap(ctx) {
53
- const findings = [];
54
- // Build route map and proof traces
55
- const routes = buildRouteMap(ctx);
56
- const proofTraces = buildAllProofTraces(ctx, routes);
57
- // Find state-changing routes without auth
58
- const unprotectedRoutes = routes.filter((r) => {
59
- if (!["POST", "PUT", "PATCH", "DELETE"].includes(r.method)) {
60
- return false;
61
- }
62
- const trace = proofTraces.get(r.routeId);
63
- return trace && !trace.authProven && !trace.middlewareCovered;
64
- });
65
- if (unprotectedRoutes.length === 0) {
66
- return findings;
67
- }
68
- // Scan client components for UI-level auth patterns
69
- const clientComponents = ctx.fileIndex.allSourceFiles.filter((f) => (f.endsWith(".tsx") || f.endsWith(".jsx")) &&
70
- !f.includes("/api/") &&
71
- !f.includes("route."));
72
- for (const componentFile of clientComponents) {
73
- const sourceFile = ctx.helpers.parseFile(componentFile);
74
- if (!sourceFile)
75
- continue;
76
- const fullText = sourceFile.getFullText();
77
- const relPath = path.relative(ctx.repoRoot, componentFile).replace(/\\/g, "/");
78
- // Check for client-side auth patterns
79
- const hasClientAuth = CLIENT_AUTH_PATTERNS.some((p) => p.test(fullText));
80
- if (!hasClientAuth)
81
- continue;
82
- // Find API calls in this component
83
- const apiCalls = findApiCalls(fullText, relPath, sourceFile);
84
- if (apiCalls.length === 0)
85
- continue;
86
- // Check if any API calls target unprotected routes
87
- for (const apiCall of apiCalls) {
88
- const matchingUnprotected = findMatchingUnprotectedRoute(apiCall.path, apiCall.method, unprotectedRoutes);
89
- if (matchingUnprotected) {
90
- const clientAuthLocation = findClientAuthLocation(sourceFile, fullText);
91
- findings.push({
92
- id: `f-${crypto.randomUUID().slice(0, 8)}`,
93
- severity: "critical",
94
- confidence: 0.85,
95
- category: "auth",
96
- ruleId: RULE_ID,
97
- title: `Client-side auth with unprotected server endpoint ${matchingUnprotected.method} ${matchingUnprotected.path}`,
98
- description: generateDescription(relPath, matchingUnprotected, apiCall),
99
- evidence: [
100
- {
101
- file: relPath,
102
- startLine: clientAuthLocation.line,
103
- endLine: clientAuthLocation.line,
104
- snippet: clientAuthLocation.snippet,
105
- label: "Client-side auth check",
106
- },
107
- {
108
- file: relPath,
109
- startLine: apiCall.line,
110
- endLine: apiCall.line,
111
- snippet: apiCall.snippet,
112
- label: "API call to unprotected endpoint",
113
- },
114
- {
115
- file: matchingUnprotected.file,
116
- startLine: matchingUnprotected.startLine,
117
- endLine: matchingUnprotected.endLine,
118
- snippet: `export async function ${matchingUnprotected.method}(request: Request)`,
119
- label: "Server endpoint without auth check",
120
- },
121
- ],
122
- remediation: {
123
- recommendedFix: generateRemediation(matchingUnprotected),
124
- },
125
- fingerprint: generateFingerprint(relPath, matchingUnprotected),
126
- });
127
- }
128
- }
129
- }
130
- return findings;
131
- }
132
- function findApiCalls(fullText, relPath, sourceFile) {
133
- const calls = [];
134
- // Find fetch calls to /api routes
135
- const fetchMatches = fullText.matchAll(/fetch\s*\(\s*['"`](\/api\/[^'"`]+)['"`](?:,\s*\{[^}]*method:\s*['"`](\w+)['"`])?/g);
136
- for (const match of fetchMatches) {
137
- const pos = match.index || 0;
138
- const line = sourceFile.getLineAndColumnAtPos(pos).line;
139
- calls.push({
140
- path: match[1],
141
- method: match[2]?.toUpperCase() || "GET",
142
- line,
143
- snippet: match[0].slice(0, 80),
144
- });
145
- }
146
- // Find axios calls
147
- const axiosMatches = fullText.matchAll(/axios\.(\w+)\s*\(\s*['"`](\/api\/[^'"`]+)['"`]/g);
148
- for (const match of axiosMatches) {
149
- const pos = match.index || 0;
150
- const line = sourceFile.getLineAndColumnAtPos(pos).line;
151
- calls.push({
152
- path: match[2],
153
- method: match[1].toUpperCase(),
154
- line,
155
- snippet: match[0].slice(0, 80),
156
- });
157
- }
158
- // Find form actions
159
- const actionMatches = fullText.matchAll(/action\s*=\s*['"`](\/api\/[^'"`]+)['"`]/g);
160
- for (const match of actionMatches) {
161
- const pos = match.index || 0;
162
- const line = sourceFile.getLineAndColumnAtPos(pos).line;
163
- calls.push({
164
- path: match[1],
165
- method: "POST", // Form actions are typically POST
166
- line,
167
- snippet: match[0],
168
- });
169
- }
170
- return calls;
171
- }
172
- function findMatchingUnprotectedRoute(apiPath, method, unprotectedRoutes) {
173
- // Normalize the API path
174
- const normalizedPath = apiPath.split("?")[0]; // Remove query string
175
- for (const route of unprotectedRoutes) {
176
- // Check method match
177
- if (route.method !== method)
178
- continue;
179
- // Check path match (accounting for dynamic segments)
180
- if (pathsMatch(normalizedPath, route.path)) {
181
- return route;
182
- }
183
- }
184
- return undefined;
185
- }
186
- function pathsMatch(clientPath, routePath) {
187
- // Exact match
188
- if (clientPath === routePath)
189
- return true;
190
- // Convert route path pattern to regex
191
- const routePattern = routePath
192
- .replace(/\[([^\]]+)\]/g, "[^/]+") // Replace [param] with regex
193
- .replace(/\//g, "\\/"); // Escape slashes
194
- try {
195
- const regex = new RegExp(`^${routePattern}$`);
196
- return regex.test(clientPath);
197
- }
198
- catch {
199
- return false;
200
- }
201
- }
202
- function findClientAuthLocation(sourceFile, fullText) {
203
- // Find the first client auth pattern
204
- for (const pattern of CLIENT_AUTH_PATTERNS) {
205
- const match = fullText.match(pattern);
206
- if (match) {
207
- const pos = match.index || 0;
208
- const line = sourceFile.getLineAndColumnAtPos(pos).line;
209
- return {
210
- line,
211
- snippet: match[0],
212
- };
213
- }
214
- }
215
- return { line: 1, snippet: "Client-side auth" };
216
- }
217
- function generateDescription(componentFile, route, apiCall) {
218
- return (`The component ${componentFile} uses client-side authentication checks ` +
219
- `(useSession, session &&, etc.) before calling the API endpoint ` +
220
- `${route.method} ${route.path}. However, this endpoint lacks server-side ` +
221
- `authentication verification. An attacker can bypass the UI and directly ` +
222
- `call the API endpoint without authentication, potentially gaining ` +
223
- `unauthorized access to sensitive operations.`);
224
- }
225
- function generateRemediation(route) {
226
- return (`Add server-side authentication check to the ${route.method} ${route.path} handler. ` +
227
- `Example:\n` +
228
- `const session = await getServerSession();\n` +
229
- `if (!session) {\n` +
230
- ` return Response.json({ error: "Unauthorized" }, { status: 401 });\n` +
231
- `}\n\n` +
232
- `Client-side auth checks are for UX only and must never be the sole protection mechanism.`);
233
- }
234
- function generateFingerprint(componentFile, route) {
235
- const data = `${RULE_ID}:${componentFile}:${route.file}:${route.method}`;
236
- return `sha256:${crypto.createHash("sha256").update(data).digest("hex")}`;
237
- }
@@ -1,14 +0,0 @@
1
- /**
2
- * VC-HALL-010: Comment Claims Protection But Unproven
3
- *
4
- * Detects comments that claim security protection but the actual
5
- * implementation doesn't prove it.
6
- *
7
- * Severity: Medium
8
- * Category: hallucinations
9
- * Confidence: 0.75
10
- */
11
- import type { Finding } from "@vibecheck/schema";
12
- import type { ScanContext } from "../../scanners/types.js";
13
- export declare function scanCommentClaimUnproven(ctx: ScanContext): Promise<Finding[]>;
14
- //# sourceMappingURL=comment-claim-unproven.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"comment-claim-unproven.d.ts","sourceRoot":"","sources":["../../../src/phase3/scanners/comment-claim-unproven.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,WAAW,EAAsC,MAAM,yBAAyB,CAAC;AAM/F,wBAAsB,wBAAwB,CAC5C,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,OAAO,EAAE,CAAC,CAsDpB"}
@@ -1,161 +0,0 @@
1
- /**
2
- * VC-HALL-010: Comment Claims Protection But Unproven
3
- *
4
- * Detects comments that claim security protection but the actual
5
- * implementation doesn't prove it.
6
- *
7
- * Severity: Medium
8
- * Category: hallucinations
9
- * Confidence: 0.75
10
- */
11
- import crypto from "node:crypto";
12
- import { buildRouteMap, buildAllProofTraces } from "../proof-trace-builder.js";
13
- import { mineAllIntentClaims } from "../intent-miner.js";
14
- const RULE_ID = "VC-HALL-010";
15
- export async function scanCommentClaimUnproven(ctx) {
16
- const findings = [];
17
- // Build route map and proof traces
18
- const routes = buildRouteMap(ctx);
19
- const proofTraces = buildAllProofTraces(ctx, routes);
20
- // Mine intent claims from comments
21
- const allClaims = mineAllIntentClaims(ctx, routes);
22
- const commentClaims = allClaims.filter((c) => c.source === "comment");
23
- // Find claims that aren't proven
24
- const unprovenClaims = findUnprovenCommentClaims(commentClaims, proofTraces, routes);
25
- for (const claim of unprovenClaims) {
26
- const route = routes.find((r) => r.routeId === claim.targetRouteId);
27
- const trace = claim.targetRouteId ? proofTraces.get(claim.targetRouteId) : undefined;
28
- findings.push({
29
- id: generateFindingId(claim),
30
- severity: "medium",
31
- confidence: 0.75,
32
- category: "hallucinations",
33
- ruleId: RULE_ID,
34
- title: `Comment claims ${formatClaimType(claim.type)} but implementation doesn't prove it`,
35
- description: generateDescription(claim, route, trace),
36
- evidence: [
37
- {
38
- file: claim.location.file,
39
- startLine: claim.location.startLine,
40
- endLine: claim.location.endLine,
41
- snippet: claim.textEvidence,
42
- label: "Security claim in comment",
43
- },
44
- ...(route
45
- ? [
46
- {
47
- file: route.file,
48
- startLine: route.startLine,
49
- endLine: route.endLine,
50
- snippet: `${route.method} ${route.path}`,
51
- label: "Associated route without proof",
52
- },
53
- ]
54
- : []),
55
- ],
56
- remediation: {
57
- recommendedFix: generateRemediation(claim),
58
- },
59
- fingerprint: generateFingerprint(claim),
60
- });
61
- }
62
- return findings;
63
- }
64
- function findUnprovenCommentClaims(claims, proofTraces, routes) {
65
- const unproven = [];
66
- for (const claim of claims) {
67
- // Skip claims without route association for auth/validation
68
- if ((claim.type === "AUTH_ENFORCED" || claim.type === "INPUT_VALIDATED") &&
69
- !claim.targetRouteId) {
70
- // Check if there are ANY routes in the file without proof
71
- const fileRoutes = routes.filter((r) => r.file === claim.location.file);
72
- for (const route of fileRoutes) {
73
- const proof = proofTraces.get(route.routeId);
74
- if (claim.type === "AUTH_ENFORCED" && proof && !proof.authProven && !proof.middlewareCovered) {
75
- unproven.push({ ...claim, targetRouteId: route.routeId });
76
- }
77
- else if (claim.type === "INPUT_VALIDATED" && proof && !proof.validationProven) {
78
- unproven.push({ ...claim, targetRouteId: route.routeId });
79
- }
80
- }
81
- continue;
82
- }
83
- if (!claim.targetRouteId)
84
- continue;
85
- const proof = proofTraces.get(claim.targetRouteId);
86
- if (!proof) {
87
- unproven.push(claim);
88
- continue;
89
- }
90
- // Check specific claim types
91
- if (claim.type === "AUTH_ENFORCED" && !proof.authProven && !proof.middlewareCovered) {
92
- unproven.push(claim);
93
- }
94
- else if (claim.type === "INPUT_VALIDATED" && !proof.validationProven) {
95
- unproven.push(claim);
96
- }
97
- else if (claim.type === "MIDDLEWARE_PROTECTED" && !proof.middlewareCovered) {
98
- unproven.push(claim);
99
- }
100
- }
101
- return unproven;
102
- }
103
- function formatClaimType(type) {
104
- switch (type) {
105
- case "AUTH_ENFORCED":
106
- return "authentication";
107
- case "INPUT_VALIDATED":
108
- return "input validation";
109
- case "MIDDLEWARE_PROTECTED":
110
- return "middleware protection";
111
- case "CSRF_ENABLED":
112
- return "CSRF protection";
113
- case "RATE_LIMITED":
114
- return "rate limiting";
115
- default:
116
- return type.toLowerCase().replace(/_/g, " ");
117
- }
118
- }
119
- function generateDescription(claim, route, trace) {
120
- let desc = `A comment claims that ${formatClaimType(claim.type)} is in place`;
121
- if (route) {
122
- desc += ` for the ${route.method} ${route.path} endpoint`;
123
- }
124
- desc += ", but static analysis couldn't verify this claim.";
125
- if (trace) {
126
- const missing = [];
127
- if (claim.type === "AUTH_ENFORCED" && !trace.authProven && !trace.middlewareCovered) {
128
- missing.push("authentication check");
129
- }
130
- if (claim.type === "INPUT_VALIDATED" && !trace.validationProven) {
131
- missing.push("validation usage");
132
- }
133
- if (claim.type === "MIDDLEWARE_PROTECTED" && !trace.middlewareCovered) {
134
- missing.push("middleware coverage");
135
- }
136
- if (missing.length > 0) {
137
- desc += ` Missing: ${missing.join(", ")}.`;
138
- }
139
- }
140
- desc += " This could be a documentation issue or missing implementation.";
141
- return desc;
142
- }
143
- function generateRemediation(claim) {
144
- switch (claim.type) {
145
- case "AUTH_ENFORCED":
146
- return "Add authentication check using getServerSession(), auth(), or similar before performing operations. Alternatively, update the comment if the claim is incorrect.";
147
- case "INPUT_VALIDATED":
148
- return "Add input validation using Zod, Yup, or Joi and ensure the validated result is used. Alternatively, update the comment if validation isn't needed.";
149
- case "MIDDLEWARE_PROTECTED":
150
- return "Ensure the middleware matcher covers this route, or add explicit auth check in the handler.";
151
- default:
152
- return "Verify the security claim matches the implementation, or update documentation to reflect actual behavior.";
153
- }
154
- }
155
- function generateFindingId(claim) {
156
- return `f-${crypto.randomUUID().slice(0, 8)}`;
157
- }
158
- function generateFingerprint(claim) {
159
- const data = `${RULE_ID}:${claim.location.file}:${claim.location.startLine}:${claim.type}`;
160
- return `sha256:${crypto.createHash("sha256").update(data).digest("hex")}`;
161
- }
@@ -1,31 +0,0 @@
1
- /**
2
- * Phase 3 Scanner Exports
3
- */
4
- export { scanCommentClaimUnproven } from "./comment-claim-unproven.js";
5
- export { scanMiddlewareAssumedNotMatching } from "./middleware-assumed-not-matching.js";
6
- export { scanValidationClaimedMissing } from "./validation-claimed-missing.js";
7
- export { scanAuthByUiServerGap } from "./auth-by-ui-server-gap.js";
8
- import type { Scanner } from "../../scanners/types.js";
9
- import { scanCommentClaimUnproven } from "./comment-claim-unproven.js";
10
- import { scanAuthByUiServerGap } from "./auth-by-ui-server-gap.js";
11
- /**
12
- * All Phase 3 scanners
13
- */
14
- export declare const phase3Scanners: Scanner[];
15
- /**
16
- * Phase 3 Hallucination Pack
17
- */
18
- export declare const hallucinationsPack: {
19
- id: string;
20
- name: string;
21
- scanners: (typeof scanCommentClaimUnproven)[];
22
- };
23
- /**
24
- * Phase 3 Auth Pack extension
25
- */
26
- export declare const authPackPhase3: {
27
- id: string;
28
- name: string;
29
- scanners: (typeof scanAuthByUiServerGap)[];
30
- };
31
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/phase3/scanners/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AACvE,OAAO,EAAE,gCAAgC,EAAE,MAAM,sCAAsC,CAAC;AACxF,OAAO,EAAE,4BAA4B,EAAE,MAAM,iCAAiC,CAAC;AAC/E,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAEnE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AAGvE,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAEnE;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,OAAO,EAKnC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB;;;;CAQ9B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc;;;;CAI1B,CAAC"}
@@ -1,40 +0,0 @@
1
- /**
2
- * Phase 3 Scanner Exports
3
- */
4
- export { scanCommentClaimUnproven } from "./comment-claim-unproven.js";
5
- export { scanMiddlewareAssumedNotMatching } from "./middleware-assumed-not-matching.js";
6
- export { scanValidationClaimedMissing } from "./validation-claimed-missing.js";
7
- export { scanAuthByUiServerGap } from "./auth-by-ui-server-gap.js";
8
- import { scanCommentClaimUnproven } from "./comment-claim-unproven.js";
9
- import { scanMiddlewareAssumedNotMatching } from "./middleware-assumed-not-matching.js";
10
- import { scanValidationClaimedMissing } from "./validation-claimed-missing.js";
11
- import { scanAuthByUiServerGap } from "./auth-by-ui-server-gap.js";
12
- /**
13
- * All Phase 3 scanners
14
- */
15
- export const phase3Scanners = [
16
- scanCommentClaimUnproven,
17
- scanMiddlewareAssumedNotMatching,
18
- scanValidationClaimedMissing,
19
- scanAuthByUiServerGap,
20
- ];
21
- /**
22
- * Phase 3 Hallucination Pack
23
- */
24
- export const hallucinationsPack = {
25
- id: "hallucinations",
26
- name: "Hallucinations Pack (Phase 3)",
27
- scanners: [
28
- scanCommentClaimUnproven,
29
- scanMiddlewareAssumedNotMatching,
30
- scanValidationClaimedMissing,
31
- ],
32
- };
33
- /**
34
- * Phase 3 Auth Pack extension
35
- */
36
- export const authPackPhase3 = {
37
- id: "auth-phase3",
38
- name: "Auth Pack (Phase 3)",
39
- scanners: [scanAuthByUiServerGap],
40
- };
@@ -1,14 +0,0 @@
1
- /**
2
- * VC-HALL-011: Middleware Assumed But Not Matching
3
- *
4
- * Detects routes that appear to expect middleware protection
5
- * but are not covered by the middleware matcher patterns.
6
- *
7
- * Severity: High
8
- * Category: hallucinations
9
- * Confidence: 0.70
10
- */
11
- import type { Finding } from "@vibecheck/schema";
12
- import type { ScanContext } from "../../scanners/types.js";
13
- export declare function scanMiddlewareAssumedNotMatching(ctx: ScanContext): Promise<Finding[]>;
14
- //# sourceMappingURL=middleware-assumed-not-matching.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"middleware-assumed-not-matching.d.ts","sourceRoot":"","sources":["../../../src/phase3/scanners/middleware-assumed-not-matching.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,WAAW,EAA0B,MAAM,yBAAyB,CAAC;AA0BnF,wBAAsB,gCAAgC,CACpD,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,OAAO,EAAE,CAAC,CAqEpB"}