@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,14 +0,0 @@
1
- import type { Finding } from "@vibecheck/schema";
2
- import type { ScanContext } from "../types.js";
3
- /**
4
- * VC-CRYPTO-002: JWT decoded but not verified
5
- *
6
- * Detects:
7
- * - jwt.decode(...) usage (jsonwebtoken)
8
- * - OR custom decode without verify call
9
- *
10
- * Precision:
11
- * - If jsonwebtoken is used, flag when decode is used AND no jwt.verify in same file
12
- */
13
- export declare function scanJwtDecodeUnverified(context: ScanContext): Promise<Finding[]>;
14
- //# sourceMappingURL=jwt-decode-unverified.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"jwt-decode-unverified.d.ts","sourceRoot":"","sources":["../../../src/scanners/crypto/jwt-decode-unverified.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAgB,MAAM,mBAAmB,CAAC;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAM/C;;;;;;;;;GASG;AACH,wBAAsB,uBAAuB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CA+EtF"}
@@ -1,87 +0,0 @@
1
- import { resolvePath } from "../../utils/file-utils.js";
2
- import { generateFingerprint, generateFindingId } from "../../utils/fingerprint.js";
3
- const RULE_ID = "VC-CRYPTO-002";
4
- /**
5
- * VC-CRYPTO-002: JWT decoded but not verified
6
- *
7
- * Detects:
8
- * - jwt.decode(...) usage (jsonwebtoken)
9
- * - OR custom decode without verify call
10
- *
11
- * Precision:
12
- * - If jsonwebtoken is used, flag when decode is used AND no jwt.verify in same file
13
- */
14
- export async function scanJwtDecodeUnverified(context) {
15
- const { repoRoot, fileIndex, helpers } = context;
16
- const findings = [];
17
- for (const relPath of fileIndex.allSourceFiles) {
18
- const absPath = resolvePath(repoRoot, relPath);
19
- const sourceFile = helpers.parseFile(absPath);
20
- if (!sourceFile)
21
- continue;
22
- const jwtDecodes = helpers.findJwtDecodeWithoutVerify(sourceFile);
23
- for (const decode of jwtDecodes) {
24
- // Only flag if no verify in the same file
25
- if (decode.hasVerifyInFile)
26
- continue;
27
- const evidence = [
28
- {
29
- file: relPath,
30
- startLine: decode.line,
31
- endLine: decode.line,
32
- snippet: decode.snippet,
33
- label: "jwt.decode() used without jwt.verify()",
34
- },
35
- ];
36
- const fingerprint = generateFingerprint({
37
- ruleId: RULE_ID,
38
- file: relPath,
39
- symbol: "jwt.decode",
40
- startLine: decode.line,
41
- });
42
- findings.push({
43
- id: generateFindingId({
44
- ruleId: RULE_ID,
45
- file: relPath,
46
- symbol: "jwt.decode",
47
- startLine: decode.line,
48
- }),
49
- ruleId: RULE_ID,
50
- title: "JWT decoded without signature verification",
51
- description: `jwt.decode() is used without a corresponding jwt.verify() call in this file. The decode function only parses the JWT payload without verifying the signature, meaning an attacker could forge tokens with arbitrary claims. Always verify JWT signatures before trusting the payload.`,
52
- severity: "critical",
53
- confidence: 0.9,
54
- category: "crypto",
55
- evidence,
56
- remediation: {
57
- recommendedFix: `Use jwt.verify() instead of jwt.decode() to ensure the token signature is valid.`,
58
- patch: `import jwt from 'jsonwebtoken';
59
-
60
- // WRONG - doesn't verify signature:
61
- // const payload = jwt.decode(token);
62
-
63
- // CORRECT - verifies signature:
64
- try {
65
- const payload = jwt.verify(token, process.env.JWT_SECRET);
66
- // Token is valid, payload can be trusted
67
- } catch (error) {
68
- // Token is invalid or expired
69
- throw new Error('Invalid token');
70
- }
71
-
72
- // If you need to read claims before verification (e.g., to get kid for key lookup):
73
- const header = jwt.decode(token, { complete: true })?.header;
74
- const kid = header?.kid;
75
- // ... look up the correct key ...
76
- const payload = jwt.verify(token, key); // MUST verify before trusting`,
77
- },
78
- links: {
79
- cwe: "https://cwe.mitre.org/data/definitions/347.html",
80
- owasp: "https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_for_Java_Cheat_Sheet.html",
81
- },
82
- fingerprint,
83
- });
84
- }
85
- }
86
- return findings;
87
- }
@@ -1,13 +0,0 @@
1
- import type { Finding } from "@vibecheck/schema";
2
- import type { ScanContext } from "../types.js";
3
- /**
4
- * VC-CRYPTO-001: Math.random used for tokens/secrets
5
- *
6
- * Detects Math.random used to generate:
7
- * - tokens, api keys, reset codes, session ids
8
- *
9
- * Two-signal:
10
- * - Math.random present AND variable/function name includes sensitive keywords
11
- */
12
- export declare function scanMathRandomTokens(context: ScanContext): Promise<Finding[]>;
13
- //# sourceMappingURL=math-random-tokens.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"math-random-tokens.d.ts","sourceRoot":"","sources":["../../../src/scanners/crypto/math-random-tokens.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAgB,MAAM,mBAAmB,CAAC;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAM/C;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAyEnF"}
@@ -1,80 +0,0 @@
1
- import { resolvePath } from "../../utils/file-utils.js";
2
- import { generateFingerprint, generateFindingId } from "../../utils/fingerprint.js";
3
- const RULE_ID = "VC-CRYPTO-001";
4
- /**
5
- * VC-CRYPTO-001: Math.random used for tokens/secrets
6
- *
7
- * Detects Math.random used to generate:
8
- * - tokens, api keys, reset codes, session ids
9
- *
10
- * Two-signal:
11
- * - Math.random present AND variable/function name includes sensitive keywords
12
- */
13
- export async function scanMathRandomTokens(context) {
14
- const { repoRoot, fileIndex, helpers } = context;
15
- const findings = [];
16
- for (const relPath of fileIndex.allSourceFiles) {
17
- const absPath = resolvePath(repoRoot, relPath);
18
- const sourceFile = helpers.parseFile(absPath);
19
- if (!sourceFile)
20
- continue;
21
- const mathRandomUsages = helpers.findMathRandomUsage(sourceFile);
22
- for (const usage of mathRandomUsages) {
23
- if (!usage.isSensitiveContext)
24
- continue;
25
- const evidence = [
26
- {
27
- file: relPath,
28
- startLine: usage.line,
29
- endLine: usage.line,
30
- snippet: usage.snippet,
31
- label: `Math.random used for "${usage.variableName}"`,
32
- },
33
- ];
34
- const fingerprint = generateFingerprint({
35
- ruleId: RULE_ID,
36
- file: relPath,
37
- symbol: usage.variableName,
38
- startLine: usage.line,
39
- });
40
- findings.push({
41
- id: generateFindingId({
42
- ruleId: RULE_ID,
43
- file: relPath,
44
- symbol: usage.variableName,
45
- startLine: usage.line,
46
- }),
47
- ruleId: RULE_ID,
48
- title: `Insecure random for ${usage.variableName}`,
49
- description: `Math.random() is used to generate "${usage.variableName}" which appears to be a security-sensitive value. Math.random() is not cryptographically secure - its output can be predicted if an attacker knows the internal state. This makes tokens, session IDs, or reset codes guessable.`,
50
- severity: "high",
51
- confidence: 0.85,
52
- category: "crypto",
53
- evidence,
54
- remediation: {
55
- recommendedFix: `Use crypto.randomBytes() or crypto.randomUUID() for security-sensitive random values.`,
56
- patch: `import { randomBytes, randomUUID } from 'crypto';
57
-
58
- // For tokens/keys (hex string):
59
- const token = randomBytes(32).toString('hex');
60
-
61
- // For session IDs (URL-safe base64):
62
- const sessionId = randomBytes(24).toString('base64url');
63
-
64
- // For UUIDs:
65
- const id = randomUUID();
66
-
67
- // For numbers in a range (e.g., 6-digit code):
68
- const code = randomBytes(4).readUInt32BE() % 1000000;
69
- const resetCode = code.toString().padStart(6, '0');`,
70
- },
71
- links: {
72
- cwe: "https://cwe.mitre.org/data/definitions/338.html",
73
- owasp: "https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html",
74
- },
75
- fingerprint,
76
- });
77
- }
78
- }
79
- return findings;
80
- }
@@ -1,11 +0,0 @@
1
- import type { Finding } from "@vibecheck/schema";
2
- import type { ScanContext } from "../types.js";
3
- /**
4
- * VC-CRYPTO-003: Weak hashing for passwords
5
- *
6
- * Detect:
7
- * - bcrypt usage with saltRounds < 10
8
- * - crypto.createHash('md5'|'sha1') used on password-like vars
9
- */
10
- export declare function scanWeakHashing(context: ScanContext): Promise<Finding[]>;
11
- //# sourceMappingURL=weak-hashing.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"weak-hashing.d.ts","sourceRoot":"","sources":["../../../src/scanners/crypto/weak-hashing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAgB,MAAM,mBAAmB,CAAC;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAM/C;;;;;;GAMG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CA0F9E"}
@@ -1,95 +0,0 @@
1
- import { resolvePath } from "../../utils/file-utils.js";
2
- import { generateFingerprint, generateFindingId } from "../../utils/fingerprint.js";
3
- const RULE_ID = "VC-CRYPTO-003";
4
- /**
5
- * VC-CRYPTO-003: Weak hashing for passwords
6
- *
7
- * Detect:
8
- * - bcrypt usage with saltRounds < 10
9
- * - crypto.createHash('md5'|'sha1') used on password-like vars
10
- */
11
- export async function scanWeakHashing(context) {
12
- const { repoRoot, fileIndex, helpers } = context;
13
- const findings = [];
14
- for (const relPath of fileIndex.allSourceFiles) {
15
- const absPath = resolvePath(repoRoot, relPath);
16
- const sourceFile = helpers.parseFile(absPath);
17
- if (!sourceFile)
18
- continue;
19
- const weakHashUsages = helpers.findWeakHashUsage(sourceFile);
20
- for (const usage of weakHashUsages) {
21
- const evidence = [
22
- {
23
- file: relPath,
24
- startLine: usage.line,
25
- endLine: usage.line,
26
- snippet: usage.snippet,
27
- label: `Weak hash algorithm: ${usage.algorithm}`,
28
- },
29
- ];
30
- const fingerprint = generateFingerprint({
31
- ruleId: RULE_ID,
32
- file: relPath,
33
- symbol: usage.algorithm,
34
- startLine: usage.line,
35
- });
36
- // Determine title and description based on algorithm
37
- let title;
38
- let description;
39
- let patch;
40
- if (usage.algorithm.startsWith("bcrypt")) {
41
- title = "Bcrypt with insufficient salt rounds";
42
- description = `Bcrypt is configured with low salt rounds (${usage.algorithm}). The cost factor should be at least 10 (ideally 12+) to provide adequate protection against brute-force attacks. Lower values make password cracking significantly faster.`;
43
- patch = `import bcrypt from 'bcrypt';
44
-
45
- // Use at least 10 salt rounds (12 recommended):
46
- const SALT_ROUNDS = 12;
47
-
48
- const hashedPassword = await bcrypt.hash(password, SALT_ROUNDS);`;
49
- }
50
- else if (usage.algorithm === "md5" || usage.algorithm === "sha1") {
51
- title = `Weak hash algorithm (${usage.algorithm.toUpperCase()}) ${usage.isPasswordContext ? "for password" : "detected"}`;
52
- description = `${usage.algorithm.toUpperCase()} is cryptographically broken and should not be used for security purposes${usage.isPasswordContext ? ", especially for passwords" : ""}. MD5 can be brute-forced or attacked with rainbow tables in seconds. SHA1 has known collision vulnerabilities.`;
53
- patch = `// For passwords, use bcrypt or argon2:
54
- import bcrypt from 'bcrypt';
55
- const hashedPassword = await bcrypt.hash(password, 12);
56
-
57
- // For non-password hashing (integrity checks, etc.):
58
- import { createHash } from 'crypto';
59
- const hash = createHash('sha256').update(data).digest('hex');`;
60
- }
61
- else {
62
- title = `Weak cryptographic configuration: ${usage.algorithm}`;
63
- description = `The cryptographic configuration "${usage.algorithm}" is considered weak and should be updated to current standards.`;
64
- patch = `// Use modern, secure algorithms and configurations`;
65
- }
66
- findings.push({
67
- id: generateFindingId({
68
- ruleId: RULE_ID,
69
- file: relPath,
70
- symbol: usage.algorithm,
71
- startLine: usage.line,
72
- }),
73
- ruleId: RULE_ID,
74
- title,
75
- description,
76
- severity: usage.isPasswordContext ? "high" : "medium",
77
- confidence: usage.isPasswordContext ? 0.9 : 0.75,
78
- category: "crypto",
79
- evidence,
80
- remediation: {
81
- recommendedFix: usage.isPasswordContext
82
- ? "Use bcrypt with at least 10 salt rounds, or argon2id for new applications."
83
- : "Use SHA-256 or stronger for integrity checks. For passwords, use bcrypt or argon2.",
84
- patch,
85
- },
86
- links: {
87
- cwe: "https://cwe.mitre.org/data/definitions/328.html",
88
- owasp: "https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html",
89
- },
90
- fingerprint,
91
- });
92
- }
93
- }
94
- return findings;
95
- }
@@ -1,24 +0,0 @@
1
- import type { Finding } from "@vibecheck/schema";
2
- import type { ScanContext } from "./types.js";
3
- interface EnvUsage {
4
- name: string;
5
- file: string;
6
- line: number;
7
- snippet: string;
8
- }
9
- /**
10
- * Parse .env.example file and extract defined variable names
11
- */
12
- export declare function parseEnvExample(content: string): Set<string>;
13
- /**
14
- * Find all process.env usages in source files
15
- */
16
- export declare function findEnvUsages(sourceFiles: string[], targetDir: string): EnvUsage[];
17
- /**
18
- * ENV/Config Mirage Scanner
19
- *
20
- * Finds process.env usage and checks if variables are documented in .env.example
21
- */
22
- export declare function scanEnvConfig(context: ScanContext): Promise<Finding[]>;
23
- export {};
24
- //# sourceMappingURL=env-config.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"env-config.d.ts","sourceRoot":"","sources":["../../src/scanners/env-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAA0B,MAAM,mBAAmB,CAAC;AAGzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAyB9C,UAAU,QAAQ;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAiB5D;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,WAAW,EAAE,MAAM,EAAE,EACrB,SAAS,EAAE,MAAM,GAChB,QAAQ,EAAE,CA6CZ;AASD;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAmF5E"}
@@ -1,164 +0,0 @@
1
- import { readFileSync, resolvePath } from "../utils/file-utils.js";
2
- import { generateFingerprint, generateFindingId } from "../utils/fingerprint.js";
3
- const RULE_ID = "VC-CONFIG-001";
4
- /**
5
- * Patterns that indicate a secret-like environment variable
6
- */
7
- const SECRET_PATTERNS = /SECRET|KEY|TOKEN|PASSWORD|PRIVATE|CREDENTIAL|API_KEY|AUTH/i;
8
- /**
9
- * Regex to find process.env.VARIABLE_NAME usage
10
- * Captures the variable name in group 1
11
- *
12
- * Limitations:
13
- * - Does not handle computed property access like process.env[varName]
14
- * - Does not handle destructuring like const { FOO } = process.env
15
- * - May match in comments (basic regex limitation)
16
- */
17
- const PROCESS_ENV_REGEX = /process\.env\.([A-Z][A-Z0-9_]*)/g;
18
- /**
19
- * Regex to find process.env["VARIABLE"] or process.env['VARIABLE'] usage
20
- */
21
- const PROCESS_ENV_BRACKET_REGEX = /process\.env\[['"]([A-Z][A-Z0-9_]*)['"]\]/g;
22
- /**
23
- * Parse .env.example file and extract defined variable names
24
- */
25
- export function parseEnvExample(content) {
26
- const vars = new Set();
27
- const lines = content.split("\n");
28
- for (const line of lines) {
29
- const trimmed = line.trim();
30
- // Skip comments and empty lines
31
- if (trimmed.startsWith("#") || trimmed === "")
32
- continue;
33
- // Match VAR_NAME= or VAR_NAME (without value)
34
- const match = trimmed.match(/^([A-Z][A-Z0-9_]*)(?:=|$)/);
35
- if (match) {
36
- vars.add(match[1]);
37
- }
38
- }
39
- return vars;
40
- }
41
- /**
42
- * Find all process.env usages in source files
43
- */
44
- export function findEnvUsages(sourceFiles, targetDir) {
45
- const usages = [];
46
- for (const relFile of sourceFiles) {
47
- const absPath = resolvePath(targetDir, relFile);
48
- const content = readFileSync(absPath);
49
- if (!content)
50
- continue;
51
- const lines = content.split("\n");
52
- // Find dot notation: process.env.VAR_NAME
53
- for (const match of content.matchAll(PROCESS_ENV_REGEX)) {
54
- const varName = match[1];
55
- const index = match.index;
56
- // Find line number
57
- const beforeMatch = content.slice(0, index);
58
- const lineNumber = beforeMatch.split("\n").length;
59
- usages.push({
60
- name: varName,
61
- file: relFile,
62
- line: lineNumber,
63
- snippet: lines[lineNumber - 1]?.trim() ?? "",
64
- });
65
- }
66
- // Find bracket notation: process.env["VAR_NAME"]
67
- for (const match of content.matchAll(PROCESS_ENV_BRACKET_REGEX)) {
68
- const varName = match[1];
69
- const index = match.index;
70
- const beforeMatch = content.slice(0, index);
71
- const lineNumber = beforeMatch.split("\n").length;
72
- usages.push({
73
- name: varName,
74
- file: relFile,
75
- line: lineNumber,
76
- snippet: lines[lineNumber - 1]?.trim() ?? "",
77
- });
78
- }
79
- }
80
- return usages;
81
- }
82
- /**
83
- * Determine severity based on variable name
84
- */
85
- function getSeverity(varName) {
86
- return SECRET_PATTERNS.test(varName) ? "high" : "medium";
87
- }
88
- /**
89
- * ENV/Config Mirage Scanner
90
- *
91
- * Finds process.env usage and checks if variables are documented in .env.example
92
- */
93
- export async function scanEnvConfig(context) {
94
- const { targetDir, sourceFiles } = context;
95
- const findings = [];
96
- // Check for .env.example
97
- const envExamplePath = resolvePath(targetDir, ".env.example");
98
- const envExampleContent = readFileSync(envExamplePath);
99
- // Get documented env vars (empty set if no .env.example)
100
- const documentedVars = envExampleContent
101
- ? parseEnvExample(envExampleContent)
102
- : new Set();
103
- // Find all env usages
104
- const usages = findEnvUsages(sourceFiles, targetDir);
105
- // Group usages by variable name
106
- const usagesByVar = new Map();
107
- for (const usage of usages) {
108
- const existing = usagesByVar.get(usage.name) ?? [];
109
- existing.push(usage);
110
- usagesByVar.set(usage.name, existing);
111
- }
112
- // Check each variable
113
- for (const [varName, varUsages] of usagesByVar) {
114
- if (documentedVars.has(varName)) {
115
- continue; // Variable is documented, no finding
116
- }
117
- const severity = getSeverity(varName);
118
- const firstUsage = varUsages[0];
119
- const evidence = varUsages.slice(0, 3).map((u) => ({
120
- file: u.file,
121
- startLine: u.line,
122
- endLine: u.line,
123
- snippet: u.snippet,
124
- label: `Usage of process.env.${varName}`,
125
- }));
126
- if (varUsages.length > 3) {
127
- evidence.push({
128
- file: varUsages[3].file,
129
- startLine: varUsages[3].line,
130
- endLine: varUsages[3].line,
131
- label: `...and ${varUsages.length - 3} more usages`,
132
- });
133
- }
134
- const fingerprint = generateFingerprint({
135
- ruleId: RULE_ID,
136
- file: firstUsage.file,
137
- symbol: varName,
138
- });
139
- const hasEnvExample = envExampleContent !== null;
140
- findings.push({
141
- id: generateFindingId({
142
- ruleId: RULE_ID,
143
- file: firstUsage.file,
144
- symbol: varName,
145
- }),
146
- severity,
147
- confidence: 0.85,
148
- category: "config",
149
- ruleId: RULE_ID,
150
- title: `Undocumented environment variable: ${varName}`,
151
- description: hasEnvExample
152
- ? `The environment variable "${varName}" is used in the codebase but is not listed in .env.example. This can lead to deployment issues or confusion for other developers.`
153
- : `The environment variable "${varName}" is used but no .env.example file exists. Consider creating one to document required configuration.`,
154
- evidence,
155
- remediation: {
156
- recommendedFix: hasEnvExample
157
- ? `Add "${varName}=" to .env.example with an appropriate default or placeholder value.`
158
- : `Create a .env.example file and add "${varName}=" with documentation.`,
159
- },
160
- fingerprint,
161
- });
162
- }
163
- return findings;
164
- }
@@ -1,4 +0,0 @@
1
- import type { ScannerPack } from "../types.js";
2
- export declare const hallucinationsPack: ScannerPack;
3
- export { scanUnusedSecurityImports, scanNextAuthNotEnforced, findSecurityImports, checkIdentifierUsage, } from "./unused-security-imports.js";
4
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/scanners/hallucinations/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAQ/C,eAAO,MAAM,kBAAkB,EAAE,WAIhC,CAAC;AAGF,OAAO,EACL,yBAAyB,EACzB,uBAAuB,EACvB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,8BAA8B,CAAC"}
@@ -1,8 +0,0 @@
1
- import { scanUnusedSecurityImports, scanNextAuthNotEnforced, } from "./unused-security-imports.js";
2
- export const hallucinationsPack = {
3
- id: "hallucinations",
4
- name: "Security Hallucinations",
5
- scanners: [scanUnusedSecurityImports, scanNextAuthNotEnforced],
6
- };
7
- // Re-export for testing
8
- export { scanUnusedSecurityImports, scanNextAuthNotEnforced, findSecurityImports, checkIdentifierUsage, } from "./unused-security-imports.js";
@@ -1,36 +0,0 @@
1
- import type { Finding } from "@vibecheck/schema";
2
- import type { ScanContext } from "../types.js";
3
- interface ImportMatch {
4
- library: string;
5
- importedNames: string[];
6
- line: number;
7
- snippet: string;
8
- isDefaultImport: boolean;
9
- isNamespaceImport: boolean;
10
- }
11
- /**
12
- * Find imports of security libraries in a file
13
- */
14
- export declare function findSecurityImports(content: string, libraries: string[]): ImportMatch[];
15
- /**
16
- * Check if any imported identifiers are used after the import line
17
- */
18
- export declare function checkIdentifierUsage(content: string, importLine: number, identifiers: string[], isNamespaceImport: boolean): {
19
- identifier: string;
20
- used: boolean;
21
- }[];
22
- /**
23
- * VC-HALL-001: Unused Security Imports
24
- *
25
- * Detects when security libraries are imported but not used
26
- */
27
- export declare function scanUnusedSecurityImports(context: ScanContext): Promise<Finding[]>;
28
- /**
29
- * VC-HALL-002: next-auth present but not enforced
30
- *
31
- * Detects when next-auth is installed but there's no middleware
32
- * or server-side auth enforcement in route handlers
33
- */
34
- export declare function scanNextAuthNotEnforced(context: ScanContext): Promise<Finding[]>;
35
- export {};
36
- //# sourceMappingURL=unused-security-imports.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"unused-security-imports.d.ts","sourceRoot":"","sources":["../../../src/scanners/hallucinations/unused-security-imports.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAoC,MAAM,mBAAmB,CAAC;AAGnF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAwE/C,UAAU,WAAW;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,OAAO,CAAC;IACzB,iBAAiB,EAAE,OAAO,CAAC;CAC5B;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,WAAW,EAAE,CA8DvF;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EAAE,EACrB,iBAAiB,EAAE,OAAO,GACzB;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,EAAE,CAiBzC;AAED;;;;GAIG;AACH,wBAAsB,yBAAyB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAgFxF;AAED;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAiGtF"}