@kairosinternational/watchman 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. package/PHASE_3A_COMPLETE.md +63 -0
  2. package/dist/engine.d.ts +9 -0
  3. package/dist/engine.d.ts.map +1 -0
  4. package/dist/engine.js +99 -0
  5. package/dist/engine.js.map +1 -0
  6. package/dist/index.d.ts +12 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +21 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/scanners/ai-tool-integrity/index.d.ts +2 -0
  11. package/dist/scanners/ai-tool-integrity/index.d.ts.map +1 -0
  12. package/dist/scanners/ai-tool-integrity/index.js +6 -0
  13. package/dist/scanners/ai-tool-integrity/index.js.map +1 -0
  14. package/dist/scanners/ai-tool-integrity/patterns/injection-signatures.d.ts +7 -0
  15. package/dist/scanners/ai-tool-integrity/patterns/injection-signatures.d.ts.map +1 -0
  16. package/dist/scanners/ai-tool-integrity/patterns/injection-signatures.js +51 -0
  17. package/dist/scanners/ai-tool-integrity/patterns/injection-signatures.js.map +1 -0
  18. package/dist/scanners/ai-tool-integrity/rules/prompt-injection.rule.d.ts +3 -0
  19. package/dist/scanners/ai-tool-integrity/rules/prompt-injection.rule.d.ts.map +1 -0
  20. package/dist/scanners/ai-tool-integrity/rules/prompt-injection.rule.js +49 -0
  21. package/dist/scanners/ai-tool-integrity/rules/prompt-injection.rule.js.map +1 -0
  22. package/dist/scanners/ai-tool-integrity/rules/tool-manifest-drift.rule.d.ts +3 -0
  23. package/dist/scanners/ai-tool-integrity/rules/tool-manifest-drift.rule.d.ts.map +1 -0
  24. package/dist/scanners/ai-tool-integrity/rules/tool-manifest-drift.rule.js +71 -0
  25. package/dist/scanners/ai-tool-integrity/rules/tool-manifest-drift.rule.js.map +1 -0
  26. package/dist/scanners/ai-tool-integrity/rules/unauthorized-model-call.rule.d.ts +3 -0
  27. package/dist/scanners/ai-tool-integrity/rules/unauthorized-model-call.rule.d.ts.map +1 -0
  28. package/dist/scanners/ai-tool-integrity/rules/unauthorized-model-call.rule.js +56 -0
  29. package/dist/scanners/ai-tool-integrity/rules/unauthorized-model-call.rule.js.map +1 -0
  30. package/dist/scanners/ai-tool-integrity/scanner.d.ts +3 -0
  31. package/dist/scanners/ai-tool-integrity/scanner.d.ts.map +1 -0
  32. package/dist/scanners/ai-tool-integrity/scanner.js +26 -0
  33. package/dist/scanners/ai-tool-integrity/scanner.js.map +1 -0
  34. package/dist/scanners/dependency-integrity/index.d.ts +2 -0
  35. package/dist/scanners/dependency-integrity/index.d.ts.map +1 -0
  36. package/dist/scanners/dependency-integrity/index.js +6 -0
  37. package/dist/scanners/dependency-integrity/index.js.map +1 -0
  38. package/dist/scanners/dependency-integrity/patterns/known-typosquats.d.ts +8 -0
  39. package/dist/scanners/dependency-integrity/patterns/known-typosquats.d.ts.map +1 -0
  40. package/dist/scanners/dependency-integrity/patterns/known-typosquats.js +38 -0
  41. package/dist/scanners/dependency-integrity/patterns/known-typosquats.js.map +1 -0
  42. package/dist/scanners/dependency-integrity/rules/hash-validation.rule.d.ts +3 -0
  43. package/dist/scanners/dependency-integrity/rules/hash-validation.rule.d.ts.map +1 -0
  44. package/dist/scanners/dependency-integrity/rules/hash-validation.rule.js +64 -0
  45. package/dist/scanners/dependency-integrity/rules/hash-validation.rule.js.map +1 -0
  46. package/dist/scanners/dependency-integrity/rules/transitive-drift.rule.d.ts +3 -0
  47. package/dist/scanners/dependency-integrity/rules/transitive-drift.rule.d.ts.map +1 -0
  48. package/dist/scanners/dependency-integrity/rules/transitive-drift.rule.js +69 -0
  49. package/dist/scanners/dependency-integrity/rules/transitive-drift.rule.js.map +1 -0
  50. package/dist/scanners/dependency-integrity/rules/typosquat-check.rule.d.ts +3 -0
  51. package/dist/scanners/dependency-integrity/rules/typosquat-check.rule.d.ts.map +1 -0
  52. package/dist/scanners/dependency-integrity/rules/typosquat-check.rule.js +94 -0
  53. package/dist/scanners/dependency-integrity/rules/typosquat-check.rule.js.map +1 -0
  54. package/dist/scanners/dependency-integrity/scanner.d.ts +3 -0
  55. package/dist/scanners/dependency-integrity/scanner.d.ts.map +1 -0
  56. package/dist/scanners/dependency-integrity/scanner.js +26 -0
  57. package/dist/scanners/dependency-integrity/scanner.js.map +1 -0
  58. package/dist/scanners/runtime-monitor/index.d.ts +2 -0
  59. package/dist/scanners/runtime-monitor/index.d.ts.map +1 -0
  60. package/dist/scanners/runtime-monitor/index.js +6 -0
  61. package/dist/scanners/runtime-monitor/index.js.map +1 -0
  62. package/dist/scanners/runtime-monitor/patterns/known-bad-destinations.d.ts +8 -0
  63. package/dist/scanners/runtime-monitor/patterns/known-bad-destinations.d.ts.map +1 -0
  64. package/dist/scanners/runtime-monitor/patterns/known-bad-destinations.js +52 -0
  65. package/dist/scanners/runtime-monitor/patterns/known-bad-destinations.js.map +1 -0
  66. package/dist/scanners/runtime-monitor/rules/filesystem-access.rule.d.ts +3 -0
  67. package/dist/scanners/runtime-monitor/rules/filesystem-access.rule.d.ts.map +1 -0
  68. package/dist/scanners/runtime-monitor/rules/filesystem-access.rule.js +68 -0
  69. package/dist/scanners/runtime-monitor/rules/filesystem-access.rule.js.map +1 -0
  70. package/dist/scanners/runtime-monitor/rules/outbound-network.rule.d.ts +3 -0
  71. package/dist/scanners/runtime-monitor/rules/outbound-network.rule.d.ts.map +1 -0
  72. package/dist/scanners/runtime-monitor/rules/outbound-network.rule.js +62 -0
  73. package/dist/scanners/runtime-monitor/rules/outbound-network.rule.js.map +1 -0
  74. package/dist/scanners/runtime-monitor/rules/process-spawn.rule.d.ts +3 -0
  75. package/dist/scanners/runtime-monitor/rules/process-spawn.rule.d.ts.map +1 -0
  76. package/dist/scanners/runtime-monitor/rules/process-spawn.rule.js +55 -0
  77. package/dist/scanners/runtime-monitor/rules/process-spawn.rule.js.map +1 -0
  78. package/dist/scanners/runtime-monitor/rules/resource-anomaly.rule.d.ts +3 -0
  79. package/dist/scanners/runtime-monitor/rules/resource-anomaly.rule.d.ts.map +1 -0
  80. package/dist/scanners/runtime-monitor/rules/resource-anomaly.rule.js +76 -0
  81. package/dist/scanners/runtime-monitor/rules/resource-anomaly.rule.js.map +1 -0
  82. package/dist/scanners/runtime-monitor/scanner.d.ts +3 -0
  83. package/dist/scanners/runtime-monitor/scanner.d.ts.map +1 -0
  84. package/dist/scanners/runtime-monitor/scanner.js +28 -0
  85. package/dist/scanners/runtime-monitor/scanner.js.map +1 -0
  86. package/dist/scanners/secrets-exposure/index.d.ts +2 -0
  87. package/dist/scanners/secrets-exposure/index.d.ts.map +1 -0
  88. package/dist/scanners/secrets-exposure/index.js +6 -0
  89. package/dist/scanners/secrets-exposure/index.js.map +1 -0
  90. package/dist/scanners/secrets-exposure/patterns/secret-signatures.d.ts +7 -0
  91. package/dist/scanners/secrets-exposure/patterns/secret-signatures.d.ts.map +1 -0
  92. package/dist/scanners/secrets-exposure/patterns/secret-signatures.js +76 -0
  93. package/dist/scanners/secrets-exposure/patterns/secret-signatures.js.map +1 -0
  94. package/dist/scanners/secrets-exposure/rules/entropy-check.rule.d.ts +3 -0
  95. package/dist/scanners/secrets-exposure/rules/entropy-check.rule.d.ts.map +1 -0
  96. package/dist/scanners/secrets-exposure/rules/entropy-check.rule.js +77 -0
  97. package/dist/scanners/secrets-exposure/rules/entropy-check.rule.js.map +1 -0
  98. package/dist/scanners/secrets-exposure/rules/known-patterns.rule.d.ts +3 -0
  99. package/dist/scanners/secrets-exposure/rules/known-patterns.rule.d.ts.map +1 -0
  100. package/dist/scanners/secrets-exposure/rules/known-patterns.rule.js +62 -0
  101. package/dist/scanners/secrets-exposure/rules/known-patterns.rule.js.map +1 -0
  102. package/dist/scanners/secrets-exposure/rules/response-echo.rule.d.ts +3 -0
  103. package/dist/scanners/secrets-exposure/rules/response-echo.rule.d.ts.map +1 -0
  104. package/dist/scanners/secrets-exposure/rules/response-echo.rule.js +67 -0
  105. package/dist/scanners/secrets-exposure/rules/response-echo.rule.js.map +1 -0
  106. package/dist/scanners/secrets-exposure/scanner.d.ts +3 -0
  107. package/dist/scanners/secrets-exposure/scanner.d.ts.map +1 -0
  108. package/dist/scanners/secrets-exposure/scanner.js +26 -0
  109. package/dist/scanners/secrets-exposure/scanner.js.map +1 -0
  110. package/dist/types/config.types.d.ts +22 -0
  111. package/dist/types/config.types.d.ts.map +1 -0
  112. package/dist/types/config.types.js +15 -0
  113. package/dist/types/config.types.js.map +1 -0
  114. package/dist/types/context.types.d.ts +23 -0
  115. package/dist/types/context.types.d.ts.map +1 -0
  116. package/dist/types/context.types.js +3 -0
  117. package/dist/types/context.types.js.map +1 -0
  118. package/dist/types/finding.types.d.ts +33 -0
  119. package/dist/types/finding.types.d.ts.map +1 -0
  120. package/dist/types/finding.types.js +3 -0
  121. package/dist/types/finding.types.js.map +1 -0
  122. package/dist/types/index.d.ts +5 -0
  123. package/dist/types/index.d.ts.map +1 -0
  124. package/dist/types/index.js +6 -0
  125. package/dist/types/index.js.map +1 -0
  126. package/package.json +32 -0
  127. package/src/engine.ts +129 -0
  128. package/src/index.ts +28 -0
  129. package/src/scanners/ai-tool-integrity/index.ts +1 -0
  130. package/src/scanners/ai-tool-integrity/patterns/injection-signatures.ts +53 -0
  131. package/src/scanners/ai-tool-integrity/rules/prompt-injection.rule.ts +50 -0
  132. package/src/scanners/ai-tool-integrity/rules/tool-manifest-drift.rule.ts +81 -0
  133. package/src/scanners/ai-tool-integrity/rules/unauthorized-model-call.rule.ts +59 -0
  134. package/src/scanners/ai-tool-integrity/scanner.ts +25 -0
  135. package/src/scanners/dependency-integrity/index.ts +1 -0
  136. package/src/scanners/dependency-integrity/patterns/known-typosquats.ts +41 -0
  137. package/src/scanners/dependency-integrity/rules/hash-validation.rule.ts +72 -0
  138. package/src/scanners/dependency-integrity/rules/transitive-drift.rule.ts +71 -0
  139. package/src/scanners/dependency-integrity/rules/typosquat-check.rule.ts +100 -0
  140. package/src/scanners/dependency-integrity/scanner.ts +25 -0
  141. package/src/scanners/runtime-monitor/index.ts +1 -0
  142. package/src/scanners/runtime-monitor/patterns/known-bad-destinations.ts +55 -0
  143. package/src/scanners/runtime-monitor/rules/filesystem-access.rule.ts +74 -0
  144. package/src/scanners/runtime-monitor/rules/outbound-network.rule.ts +67 -0
  145. package/src/scanners/runtime-monitor/rules/process-spawn.rule.ts +58 -0
  146. package/src/scanners/runtime-monitor/rules/resource-anomaly.rule.ts +79 -0
  147. package/src/scanners/runtime-monitor/scanner.ts +27 -0
  148. package/src/scanners/secrets-exposure/index.ts +1 -0
  149. package/src/scanners/secrets-exposure/patterns/secret-signatures.ts +78 -0
  150. package/src/scanners/secrets-exposure/rules/entropy-check.rule.ts +79 -0
  151. package/src/scanners/secrets-exposure/rules/known-patterns.rule.ts +64 -0
  152. package/src/scanners/secrets-exposure/rules/response-echo.rule.ts +70 -0
  153. package/src/scanners/secrets-exposure/scanner.ts +25 -0
  154. package/src/types/config.types.ts +40 -0
  155. package/src/types/context.types.ts +25 -0
  156. package/src/types/finding.types.ts +36 -0
  157. package/src/types/index.ts +21 -0
  158. package/tsconfig.json +21 -0
  159. package/watchman.config.ts +16 -0
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.processSpawnRule = void 0;
4
+ const promises_1 = require("node:fs/promises");
5
+ const CODE_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs']);
6
+ function isCodeFile(file) {
7
+ const dot = file.lastIndexOf('.');
8
+ return dot !== -1 && CODE_EXTENSIONS.has(file.slice(dot).toLowerCase());
9
+ }
10
+ const SPAWN_PATTERNS = [
11
+ { pattern: /child_process.*(?:exec|execSync|spawn|spawnSync|fork)\s*\(/g, label: 'child_process' },
12
+ { pattern: /\bexec\s*\(\s*['"`]/g, label: 'exec-string' },
13
+ { pattern: /\beval\s*\(\s*[^)]/g, label: 'eval' },
14
+ { pattern: /new\s+Function\s*\(/g, label: 'Function-constructor' },
15
+ { pattern: /child_process.*\bexec\s*\(\s*(?:req\.|params\.|query\.|body\.)/g, label: 'user-input-exec' },
16
+ { pattern: /\.exec\s*\(\s*`[^`]*\$\{/g, label: 'template-exec' },
17
+ ];
18
+ exports.processSpawnRule = {
19
+ id: 'process-spawn',
20
+ name: 'Process Spawn Detection',
21
+ description: 'Flags shell command execution and dynamic code evaluation patterns',
22
+ async run(ctx) {
23
+ const codeFiles = ctx.files.filter(isCodeFile);
24
+ for (const file of codeFiles) {
25
+ let content;
26
+ try {
27
+ content = await (0, promises_1.readFile)(file, 'utf-8');
28
+ }
29
+ catch {
30
+ continue;
31
+ }
32
+ const lines = content.split('\n');
33
+ for (let i = 0; i < lines.length; i++) {
34
+ const line = lines[i];
35
+ for (const { pattern, label } of SPAWN_PATTERNS) {
36
+ pattern.lastIndex = 0;
37
+ if (pattern.test(line)) {
38
+ const isUserInput = label === 'user-input-exec' || label === 'template-exec';
39
+ ctx.addFinding({
40
+ rule: 'process-spawn',
41
+ severity: isUserInput ? 'critical' : 'medium',
42
+ message: `Process spawn/eval detected: ${label}`,
43
+ location: { file, line: i + 1 },
44
+ evidence: line.trim().slice(0, 200),
45
+ suggestion: isUserInput
46
+ ? 'CRITICAL: User input flows into shell execution. This is a command injection vulnerability.'
47
+ : 'Review whether this shell execution is necessary. Prefer native Node.js APIs.',
48
+ });
49
+ }
50
+ }
51
+ }
52
+ }
53
+ },
54
+ };
55
+ //# sourceMappingURL=process-spawn.rule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process-spawn.rule.js","sourceRoot":"","sources":["../../../../src/scanners/runtime-monitor/rules/process-spawn.rule.ts"],"names":[],"mappings":";;;AAAA,+CAA4C;AAG5C,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAEhF,SAAS,UAAU,CAAC,IAAY;IAC9B,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAClC,OAAO,GAAG,KAAK,CAAC,CAAC,IAAI,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;AAC1E,CAAC;AAED,MAAM,cAAc,GAAG;IACrB,EAAE,OAAO,EAAE,6DAA6D,EAAE,KAAK,EAAE,eAAe,EAAE;IAClG,EAAE,OAAO,EAAE,sBAAsB,EAAE,KAAK,EAAE,aAAa,EAAE;IACzD,EAAE,OAAO,EAAE,qBAAqB,EAAE,KAAK,EAAE,MAAM,EAAE;IACjD,EAAE,OAAO,EAAE,sBAAsB,EAAE,KAAK,EAAE,sBAAsB,EAAE;IAClE,EAAE,OAAO,EAAE,iEAAiE,EAAE,KAAK,EAAE,iBAAiB,EAAE;IACxG,EAAE,OAAO,EAAE,2BAA2B,EAAE,KAAK,EAAE,eAAe,EAAE;CACjE,CAAC;AAEW,QAAA,gBAAgB,GAAS;IACpC,EAAE,EAAE,eAAe;IACnB,IAAI,EAAE,yBAAyB;IAC/B,WAAW,EAAE,oEAAoE;IAEjF,KAAK,CAAC,GAAG,CAAC,GAAgB;QACxB,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAE/C,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;YAC7B,IAAI,OAAe,CAAC;YACpB,IAAI,CAAC;gBACH,OAAO,GAAG,MAAM,IAAA,mBAAQ,EAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAC1C,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;YAED,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAClC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBACtB,KAAK,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,cAAc,EAAE,CAAC;oBAChD,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC;oBACtB,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;wBACvB,MAAM,WAAW,GAAG,KAAK,KAAK,iBAAiB,IAAI,KAAK,KAAK,eAAe,CAAC;wBAC7E,GAAG,CAAC,UAAU,CAAC;4BACb,IAAI,EAAE,eAAe;4BACrB,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ;4BAC7C,OAAO,EAAE,gCAAgC,KAAK,EAAE;4BAChD,QAAQ,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE;4BAC/B,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;4BACnC,UAAU,EAAE,WAAW;gCACrB,CAAC,CAAC,6FAA6F;gCAC/F,CAAC,CAAC,+EAA+E;yBACpF,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;CACF,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Rule } from '../../../types/index.js';
2
+ export declare const resourceAnomalyRule: Rule;
3
+ //# sourceMappingURL=resource-anomaly.rule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource-anomaly.rule.d.ts","sourceRoot":"","sources":["../../../../src/scanners/runtime-monitor/rules/resource-anomaly.rule.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAe,MAAM,yBAAyB,CAAC;AA0CjE,eAAO,MAAM,mBAAmB,EAAE,IAmCjC,CAAC"}
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resourceAnomalyRule = void 0;
4
+ const promises_1 = require("node:fs/promises");
5
+ const CODE_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs']);
6
+ function isCodeFile(file) {
7
+ const dot = file.lastIndexOf('.');
8
+ return dot !== -1 && CODE_EXTENSIONS.has(file.slice(dot).toLowerCase());
9
+ }
10
+ const ANOMALY_PATTERNS = [
11
+ {
12
+ pattern: /while\s*\(\s*true\s*\)/g,
13
+ label: 'infinite-loop',
14
+ severity: 'medium',
15
+ message: 'Infinite loop detected — potential denial of service',
16
+ },
17
+ {
18
+ pattern: /setInterval\s*\([^,]+,\s*\d{1,3}\s*\)/g,
19
+ label: 'tight-interval',
20
+ severity: 'medium',
21
+ message: 'Very short setInterval (< 1s) — potential resource exhaustion',
22
+ },
23
+ {
24
+ pattern: /Buffer\.alloc(?:Unsafe)?\s*\(\s*(?:\d{8,}|[a-zA-Z_$][\w$]*\s*\*\s*[a-zA-Z_$][\w$]*)\s*\)/g,
25
+ label: 'large-buffer',
26
+ severity: 'medium',
27
+ message: 'Large buffer allocation — potential memory exhaustion attack',
28
+ },
29
+ {
30
+ pattern: /new\s+RegExp\s*\(\s*(?:req\.|params\.|query\.|body\.|args\.)/g,
31
+ label: 'user-regex',
32
+ severity: 'high',
33
+ message: 'User input used in RegExp constructor — ReDoS vulnerability',
34
+ },
35
+ {
36
+ pattern: /crypto\.(?:pbkdf2|scrypt).*(?:iterations|cost)\s*[:=]\s*(?:req\.|params\.|query\.|body\.)/g,
37
+ label: 'user-controlled-crypto',
38
+ severity: 'high',
39
+ message: 'User input controls crypto parameters — potential algorithmic complexity attack',
40
+ },
41
+ ];
42
+ exports.resourceAnomalyRule = {
43
+ id: 'resource-anomaly',
44
+ name: 'Resource Anomaly Detection',
45
+ description: 'Detects patterns that could cause resource exhaustion or denial of service',
46
+ async run(ctx) {
47
+ const codeFiles = ctx.files.filter(isCodeFile);
48
+ for (const file of codeFiles) {
49
+ let content;
50
+ try {
51
+ content = await (0, promises_1.readFile)(file, 'utf-8');
52
+ }
53
+ catch {
54
+ continue;
55
+ }
56
+ const lines = content.split('\n');
57
+ for (let i = 0; i < lines.length; i++) {
58
+ const line = lines[i];
59
+ for (const anomaly of ANOMALY_PATTERNS) {
60
+ anomaly.pattern.lastIndex = 0;
61
+ if (anomaly.pattern.test(line)) {
62
+ ctx.addFinding({
63
+ rule: 'resource-anomaly',
64
+ severity: anomaly.severity,
65
+ message: anomaly.message,
66
+ location: { file, line: i + 1 },
67
+ evidence: line.trim().slice(0, 200),
68
+ suggestion: 'Review this pattern for potential resource exhaustion.',
69
+ });
70
+ }
71
+ }
72
+ }
73
+ }
74
+ },
75
+ };
76
+ //# sourceMappingURL=resource-anomaly.rule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource-anomaly.rule.js","sourceRoot":"","sources":["../../../../src/scanners/runtime-monitor/rules/resource-anomaly.rule.ts"],"names":[],"mappings":";;;AAAA,+CAA4C;AAG5C,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAEhF,SAAS,UAAU,CAAC,IAAY;IAC9B,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAClC,OAAO,GAAG,KAAK,CAAC,CAAC,IAAI,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;AAC1E,CAAC;AAED,MAAM,gBAAgB,GAAG;IACvB;QACE,OAAO,EAAE,yBAAyB;QAClC,KAAK,EAAE,eAAe;QACtB,QAAQ,EAAE,QAAiB;QAC3B,OAAO,EAAE,sDAAsD;KAChE;IACD;QACE,OAAO,EAAE,wCAAwC;QACjD,KAAK,EAAE,gBAAgB;QACvB,QAAQ,EAAE,QAAiB;QAC3B,OAAO,EAAE,+DAA+D;KACzE;IACD;QACE,OAAO,EAAE,2FAA2F;QACpG,KAAK,EAAE,cAAc;QACrB,QAAQ,EAAE,QAAiB;QAC3B,OAAO,EAAE,8DAA8D;KACxE;IACD;QACE,OAAO,EAAE,+DAA+D;QACxE,KAAK,EAAE,YAAY;QACnB,QAAQ,EAAE,MAAe;QACzB,OAAO,EAAE,6DAA6D;KACvE;IACD;QACE,OAAO,EAAE,4FAA4F;QACrG,KAAK,EAAE,wBAAwB;QAC/B,QAAQ,EAAE,MAAe;QACzB,OAAO,EAAE,iFAAiF;KAC3F;CACF,CAAC;AAEW,QAAA,mBAAmB,GAAS;IACvC,EAAE,EAAE,kBAAkB;IACtB,IAAI,EAAE,4BAA4B;IAClC,WAAW,EAAE,4EAA4E;IAEzF,KAAK,CAAC,GAAG,CAAC,GAAgB;QACxB,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAE/C,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;YAC7B,IAAI,OAAe,CAAC;YACpB,IAAI,CAAC;gBACH,OAAO,GAAG,MAAM,IAAA,mBAAQ,EAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAC1C,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;YAED,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAClC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBACtB,KAAK,MAAM,OAAO,IAAI,gBAAgB,EAAE,CAAC;oBACvC,OAAO,CAAC,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC;oBAC9B,IAAI,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;wBAC/B,GAAG,CAAC,UAAU,CAAC;4BACb,IAAI,EAAE,kBAAkB;4BACxB,QAAQ,EAAE,OAAO,CAAC,QAAQ;4BAC1B,OAAO,EAAE,OAAO,CAAC,OAAO;4BACxB,QAAQ,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE;4BAC/B,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;4BACnC,UAAU,EAAE,wDAAwD;yBACrE,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;CACF,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Scanner } from '../../types/index.js';
2
+ export declare const runtimeMonitorScanner: Scanner;
3
+ //# sourceMappingURL=scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../../src/scanners/runtime-monitor/scanner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAqB,MAAM,sBAAsB,CAAC;AAavE,eAAO,MAAM,qBAAqB,EAAE,OAanC,CAAC"}
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runtimeMonitorScanner = void 0;
4
+ const process_spawn_rule_js_1 = require("./rules/process-spawn.rule.js");
5
+ const filesystem_access_rule_js_1 = require("./rules/filesystem-access.rule.js");
6
+ const outbound_network_rule_js_1 = require("./rules/outbound-network.rule.js");
7
+ const resource_anomaly_rule_js_1 = require("./rules/resource-anomaly.rule.js");
8
+ const rules = [
9
+ process_spawn_rule_js_1.processSpawnRule,
10
+ filesystem_access_rule_js_1.filesystemAccessRule,
11
+ outbound_network_rule_js_1.outboundNetworkRule,
12
+ resource_anomaly_rule_js_1.resourceAnomalyRule,
13
+ ];
14
+ exports.runtimeMonitorScanner = {
15
+ id: 'runtime-monitor',
16
+ name: 'Runtime Monitor',
17
+ description: 'Detects suspicious runtime behavior: process spawning, filesystem access, network calls, resource anomalies',
18
+ rules,
19
+ async scan(ctx) {
20
+ for (const rule of rules) {
21
+ const ruleConfig = ctx.scannerConfig.rules?.[rule.id];
22
+ if (ruleConfig?.enabled === false)
23
+ continue;
24
+ await rule.run(ctx);
25
+ }
26
+ },
27
+ };
28
+ //# sourceMappingURL=scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../../../src/scanners/runtime-monitor/scanner.ts"],"names":[],"mappings":";;;AACA,yEAAiE;AACjE,iFAAyE;AACzE,+EAAuE;AACvE,+EAAuE;AAEvE,MAAM,KAAK,GAAW;IACpB,wCAAgB;IAChB,gDAAoB;IACpB,8CAAmB;IACnB,8CAAmB;CACpB,CAAC;AAEW,QAAA,qBAAqB,GAAY;IAC5C,EAAE,EAAE,iBAAiB;IACrB,IAAI,EAAE,iBAAiB;IACvB,WAAW,EAAE,6GAA6G;IAC1H,KAAK;IAEL,KAAK,CAAC,IAAI,CAAC,GAAgB;QACzB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,UAAU,GAAG,GAAG,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACtD,IAAI,UAAU,EAAE,OAAO,KAAK,KAAK;gBAAE,SAAS;YAC5C,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;CACF,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { secretsExposureScanner } from './scanner.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/scanners/secrets-exposure/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.secretsExposureScanner = void 0;
4
+ var scanner_js_1 = require("./scanner.js");
5
+ Object.defineProperty(exports, "secretsExposureScanner", { enumerable: true, get: function () { return scanner_js_1.secretsExposureScanner; } });
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/scanners/secrets-exposure/index.ts"],"names":[],"mappings":";;;AAAA,2CAAsD;AAA7C,oHAAA,sBAAsB,OAAA"}
@@ -0,0 +1,7 @@
1
+ export interface SecretSignature {
2
+ pattern: RegExp;
3
+ label: string;
4
+ description: string;
5
+ }
6
+ export declare const SECRET_SIGNATURES: SecretSignature[];
7
+ //# sourceMappingURL=secret-signatures.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secret-signatures.d.ts","sourceRoot":"","sources":["../../../../src/scanners/secrets-exposure/patterns/secret-signatures.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,iBAAiB,EAAE,eAAe,EAuE9C,CAAC"}
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SECRET_SIGNATURES = void 0;
4
+ exports.SECRET_SIGNATURES = [
5
+ {
6
+ pattern: /sk-ant-api\d{2}-[A-Za-z0-9_-]{20,}/,
7
+ label: 'anthropic-api-key',
8
+ description: 'Anthropic API key',
9
+ },
10
+ {
11
+ pattern: /sk-[A-Za-z0-9]{48,}/,
12
+ label: 'openai-api-key',
13
+ description: 'OpenAI API key',
14
+ },
15
+ {
16
+ pattern: /ghp_[A-Za-z0-9]{36,}/,
17
+ label: 'github-pat',
18
+ description: 'GitHub personal access token',
19
+ },
20
+ {
21
+ pattern: /gho_[A-Za-z0-9]{36,}/,
22
+ label: 'github-oauth',
23
+ description: 'GitHub OAuth access token',
24
+ },
25
+ {
26
+ pattern: /github_pat_[A-Za-z0-9_]{20,}/,
27
+ label: 'github-fine-grained-pat',
28
+ description: 'GitHub fine-grained personal access token',
29
+ },
30
+ {
31
+ pattern: /xoxb-[0-9]{10,}-[0-9]{10,}-[A-Za-z0-9]{24,}/,
32
+ label: 'slack-bot-token',
33
+ description: 'Slack bot token',
34
+ },
35
+ {
36
+ pattern: /xoxp-[0-9]{10,}-[0-9]{10,}-[A-Za-z0-9]{24,}/,
37
+ label: 'slack-user-token',
38
+ description: 'Slack user token',
39
+ },
40
+ {
41
+ pattern: /eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9\.[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}/,
42
+ label: 'supabase-jwt',
43
+ description: 'Supabase JWT (anon or service_role key)',
44
+ },
45
+ {
46
+ pattern: /AKIA[0-9A-Z]{16}/,
47
+ label: 'aws-access-key',
48
+ description: 'AWS access key ID',
49
+ },
50
+ {
51
+ pattern: /npm_[A-Za-z0-9]{36,}/,
52
+ label: 'npm-token',
53
+ description: 'npm access token',
54
+ },
55
+ {
56
+ pattern: /sk_live_[A-Za-z0-9]{24,}/,
57
+ label: 'stripe-secret-key',
58
+ description: 'Stripe secret key',
59
+ },
60
+ {
61
+ pattern: /sq0csp-[A-Za-z0-9_-]{43}/,
62
+ label: 'square-oauth-secret',
63
+ description: 'Square OAuth secret',
64
+ },
65
+ {
66
+ pattern: /SG\.[A-Za-z0-9_-]{22}\.[A-Za-z0-9_-]{43}/,
67
+ label: 'sendgrid-api-key',
68
+ description: 'SendGrid API key',
69
+ },
70
+ {
71
+ pattern: /-----BEGIN (RSA |EC |DSA )?PRIVATE KEY-----/,
72
+ label: 'private-key',
73
+ description: 'Private key file',
74
+ },
75
+ ];
76
+ //# sourceMappingURL=secret-signatures.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secret-signatures.js","sourceRoot":"","sources":["../../../../src/scanners/secrets-exposure/patterns/secret-signatures.ts"],"names":[],"mappings":";;;AAMa,QAAA,iBAAiB,GAAsB;IAClD;QACE,OAAO,EAAE,oCAAoC;QAC7C,KAAK,EAAE,mBAAmB;QAC1B,WAAW,EAAE,mBAAmB;KACjC;IACD;QACE,OAAO,EAAE,qBAAqB;QAC9B,KAAK,EAAE,gBAAgB;QACvB,WAAW,EAAE,gBAAgB;KAC9B;IACD;QACE,OAAO,EAAE,sBAAsB;QAC/B,KAAK,EAAE,YAAY;QACnB,WAAW,EAAE,8BAA8B;KAC5C;IACD;QACE,OAAO,EAAE,sBAAsB;QAC/B,KAAK,EAAE,cAAc;QACrB,WAAW,EAAE,2BAA2B;KACzC;IACD;QACE,OAAO,EAAE,8BAA8B;QACvC,KAAK,EAAE,yBAAyB;QAChC,WAAW,EAAE,2CAA2C;KACzD;IACD;QACE,OAAO,EAAE,6CAA6C;QACtD,KAAK,EAAE,iBAAiB;QACxB,WAAW,EAAE,iBAAiB;KAC/B;IACD;QACE,OAAO,EAAE,6CAA6C;QACtD,KAAK,EAAE,kBAAkB;QACzB,WAAW,EAAE,kBAAkB;KAChC;IACD;QACE,OAAO,EAAE,8EAA8E;QACvF,KAAK,EAAE,cAAc;QACrB,WAAW,EAAE,yCAAyC;KACvD;IACD;QACE,OAAO,EAAE,kBAAkB;QAC3B,KAAK,EAAE,gBAAgB;QACvB,WAAW,EAAE,mBAAmB;KACjC;IACD;QACE,OAAO,EAAE,sBAAsB;QAC/B,KAAK,EAAE,WAAW;QAClB,WAAW,EAAE,kBAAkB;KAChC;IACD;QACE,OAAO,EAAE,0BAA0B;QACnC,KAAK,EAAE,mBAAmB;QAC1B,WAAW,EAAE,mBAAmB;KACjC;IACD;QACE,OAAO,EAAE,0BAA0B;QACnC,KAAK,EAAE,qBAAqB;QAC5B,WAAW,EAAE,qBAAqB;KACnC;IACD;QACE,OAAO,EAAE,0CAA0C;QACnD,KAAK,EAAE,kBAAkB;QACzB,WAAW,EAAE,kBAAkB;KAChC;IACD;QACE,OAAO,EAAE,6CAA6C;QACtD,KAAK,EAAE,aAAa;QACpB,WAAW,EAAE,kBAAkB;KAChC;CACF,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Rule } from '../../../types/index.js';
2
+ export declare const entropyCheckRule: Rule;
3
+ //# sourceMappingURL=entropy-check.rule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entropy-check.rule.d.ts","sourceRoot":"","sources":["../../../../src/scanners/secrets-exposure/rules/entropy-check.rule.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAe,MAAM,yBAAyB,CAAC;AAiCjE,eAAO,MAAM,gBAAgB,EAAE,IA2C9B,CAAC"}
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.entropyCheckRule = void 0;
4
+ const promises_1 = require("node:fs/promises");
5
+ const node_path_1 = require("node:path");
6
+ const CODE_EXTENSIONS = new Set([
7
+ '.ts', '.tsx', '.js', '.jsx', '.json', '.yaml', '.yml',
8
+ '.toml', '.cfg', '.ini', '.env',
9
+ ]);
10
+ function isTargetFile(file) {
11
+ const dot = file.lastIndexOf('.');
12
+ if (dot === -1)
13
+ return (0, node_path_1.basename)(file).startsWith('.env');
14
+ return CODE_EXTENSIONS.has(file.slice(dot).toLowerCase());
15
+ }
16
+ function shannonEntropy(s) {
17
+ if (s.length === 0)
18
+ return 0;
19
+ const freq = new Map();
20
+ for (const ch of s) {
21
+ freq.set(ch, (freq.get(ch) ?? 0) + 1);
22
+ }
23
+ let entropy = 0;
24
+ for (const count of freq.values()) {
25
+ const p = count / s.length;
26
+ entropy -= p * Math.log2(p);
27
+ }
28
+ return entropy;
29
+ }
30
+ // Match assignment-like patterns: KEY=value, "key": "value", key: value
31
+ const ASSIGNMENT_PATTERN = /(?:['"]?(?:key|token|secret|password|api_key|apikey|auth|credential|private)['"_\s]*[:=]\s*['"]?)([A-Za-z0-9+/=_-]{16,})/gi;
32
+ const ENTROPY_THRESHOLD = 4.5;
33
+ const MIN_LENGTH = 16;
34
+ exports.entropyCheckRule = {
35
+ id: 'entropy-check',
36
+ name: 'High Entropy String Detection',
37
+ description: 'Flags high-entropy strings in assignment contexts that may be hardcoded secrets',
38
+ async run(ctx) {
39
+ for (const file of ctx.files) {
40
+ if (!isTargetFile(file))
41
+ continue;
42
+ let content;
43
+ try {
44
+ content = await (0, promises_1.readFile)(file, 'utf-8');
45
+ }
46
+ catch {
47
+ continue;
48
+ }
49
+ const lines = content.split('\n');
50
+ for (let i = 0; i < lines.length; i++) {
51
+ const line = lines[i];
52
+ if (/^\s*#/.test(line) || /^\s*\/\//.test(line))
53
+ continue;
54
+ ASSIGNMENT_PATTERN.lastIndex = 0;
55
+ let match;
56
+ while ((match = ASSIGNMENT_PATTERN.exec(line)) !== null) {
57
+ const value = match[1];
58
+ if (value.length < MIN_LENGTH)
59
+ continue;
60
+ const entropy = shannonEntropy(value);
61
+ if (entropy >= ENTROPY_THRESHOLD) {
62
+ ctx.addFinding({
63
+ rule: 'entropy-check',
64
+ severity: 'high',
65
+ message: `High-entropy string (${entropy.toFixed(2)} bits) in secret-like assignment`,
66
+ location: { file, line: i + 1 },
67
+ evidence: value.slice(0, 8) + '...[REDACTED]',
68
+ suggestion: 'This looks like a hardcoded credential. Move it to an environment variable.',
69
+ metadata: { entropy },
70
+ });
71
+ }
72
+ }
73
+ }
74
+ }
75
+ },
76
+ };
77
+ //# sourceMappingURL=entropy-check.rule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entropy-check.rule.js","sourceRoot":"","sources":["../../../../src/scanners/secrets-exposure/rules/entropy-check.rule.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Rule } from '../../../types/index.js';
2
+ export declare const knownPatternsRule: Rule;
3
+ //# sourceMappingURL=known-patterns.rule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"known-patterns.rule.d.ts","sourceRoot":"","sources":["../../../../src/scanners/secrets-exposure/rules/known-patterns.rule.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAe,MAAM,yBAAyB,CAAC;AAqBjE,eAAO,MAAM,iBAAiB,EAAE,IAwC/B,CAAC"}
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.knownPatternsRule = void 0;
4
+ const promises_1 = require("node:fs/promises");
5
+ const node_path_1 = require("node:path");
6
+ const secret_signatures_js_1 = require("../patterns/secret-signatures.js");
7
+ const SKIP_FILES = new Set([
8
+ 'package-lock.json', 'yarn.lock', 'pnpm-lock.yaml',
9
+ '.gitignore', '.dockerignore',
10
+ ]);
11
+ const BINARY_EXTENSIONS = new Set([
12
+ '.png', '.jpg', '.jpeg', '.gif', '.ico', '.woff', '.woff2',
13
+ '.ttf', '.eot', '.zip', '.tar', '.gz', '.pdf',
14
+ ]);
15
+ function shouldSkip(file) {
16
+ const name = (0, node_path_1.basename)(file);
17
+ if (SKIP_FILES.has(name))
18
+ return true;
19
+ const dot = file.lastIndexOf('.');
20
+ if (dot !== -1 && BINARY_EXTENSIONS.has(file.slice(dot).toLowerCase()))
21
+ return true;
22
+ return false;
23
+ }
24
+ exports.knownPatternsRule = {
25
+ id: 'known-patterns',
26
+ name: 'Known Secret Patterns',
27
+ description: 'Matches known API key and credential patterns in source files',
28
+ async run(ctx) {
29
+ for (const file of ctx.files) {
30
+ if (shouldSkip(file))
31
+ continue;
32
+ let content;
33
+ try {
34
+ content = await (0, promises_1.readFile)(file, 'utf-8');
35
+ }
36
+ catch {
37
+ continue;
38
+ }
39
+ const lines = content.split('\n');
40
+ for (let i = 0; i < lines.length; i++) {
41
+ const line = lines[i];
42
+ // Skip lines that are env template placeholders
43
+ if (/^\s*#/.test(line) || /=\s*$/.test(line) || /YOUR_.*_HERE/.test(line)) {
44
+ continue;
45
+ }
46
+ for (const sig of secret_signatures_js_1.SECRET_SIGNATURES) {
47
+ if (sig.pattern.test(line)) {
48
+ ctx.addFinding({
49
+ rule: 'known-patterns',
50
+ severity: 'critical',
51
+ message: `${sig.description} found in source code`,
52
+ location: { file, line: i + 1 },
53
+ evidence: line.trim().slice(0, 40) + '...[REDACTED]',
54
+ suggestion: `Move this ${sig.label} to an environment variable. Never commit secrets to source control.`,
55
+ });
56
+ }
57
+ }
58
+ }
59
+ }
60
+ },
61
+ };
62
+ //# sourceMappingURL=known-patterns.rule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"known-patterns.rule.js","sourceRoot":"","sources":["../../../../src/scanners/secrets-exposure/rules/known-patterns.rule.ts"],"names":[],"mappings":";;;AAAA,+CAA4C;AAC5C,yCAAqC;AAErC,2EAAqE;AAErE,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC;IACzB,mBAAmB,EAAE,WAAW,EAAE,gBAAgB;IAClD,YAAY,EAAE,eAAe;CAC9B,CAAC,CAAC;AAEH,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC;IAChC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ;IAC1D,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;CAC9C,CAAC,CAAC;AAEH,SAAS,UAAU,CAAC,IAAY;IAC9B,MAAM,IAAI,GAAG,IAAA,oBAAQ,EAAC,IAAI,CAAC,CAAC;IAC5B,IAAI,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACtC,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,GAAG,KAAK,CAAC,CAAC,IAAI,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;QAAE,OAAO,IAAI,CAAC;IACpF,OAAO,KAAK,CAAC;AACf,CAAC;AAEY,QAAA,iBAAiB,GAAS;IACrC,EAAE,EAAE,gBAAgB;IACpB,IAAI,EAAE,uBAAuB;IAC7B,WAAW,EAAE,+DAA+D;IAE5E,KAAK,CAAC,GAAG,CAAC,GAAgB;QACxB,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;YAC7B,IAAI,UAAU,CAAC,IAAI,CAAC;gBAAE,SAAS;YAE/B,IAAI,OAAe,CAAC;YACpB,IAAI,CAAC;gBACH,OAAO,GAAG,MAAM,IAAA,mBAAQ,EAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAC1C,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;YAED,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAClC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBAEtB,gDAAgD;gBAChD,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC1E,SAAS;gBACX,CAAC;gBAED,KAAK,MAAM,GAAG,IAAI,wCAAiB,EAAE,CAAC;oBACpC,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;wBAC3B,GAAG,CAAC,UAAU,CAAC;4BACb,IAAI,EAAE,gBAAgB;4BACtB,QAAQ,EAAE,UAAU;4BACpB,OAAO,EAAE,GAAG,GAAG,CAAC,WAAW,uBAAuB;4BAClD,QAAQ,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE;4BAC/B,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,eAAe;4BACpD,UAAU,EAAE,aAAa,GAAG,CAAC,KAAK,sEAAsE;yBACzG,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;CACF,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Rule } from '../../../types/index.js';
2
+ export declare const responseEchoRule: Rule;
3
+ //# sourceMappingURL=response-echo.rule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response-echo.rule.d.ts","sourceRoot":"","sources":["../../../../src/scanners/secrets-exposure/rules/response-echo.rule.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAe,MAAM,yBAAyB,CAAC;AAiCjE,eAAO,MAAM,gBAAgB,EAAE,IAmC9B,CAAC"}
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.responseEchoRule = void 0;
4
+ const promises_1 = require("node:fs/promises");
5
+ const CODE_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs']);
6
+ function isCodeFile(file) {
7
+ const dot = file.lastIndexOf('.');
8
+ return dot !== -1 && CODE_EXTENSIONS.has(file.slice(dot).toLowerCase());
9
+ }
10
+ // Patterns where env vars are passed into responses, logs, or error messages
11
+ const ECHO_PATTERNS = [
12
+ {
13
+ pattern: /(?:res\.(?:json|send|write)|console\.(?:log|error|warn))\s*\([^)]*process\.env\.[A-Z_]*(?:KEY|SECRET|TOKEN|PASSWORD)/g,
14
+ label: 'env-var-in-response',
15
+ description: 'Environment variable containing a secret echoed in response or log',
16
+ },
17
+ {
18
+ pattern: /(?:JSON\.stringify|toString)\s*\([^)]*process\.env\b/g,
19
+ label: 'env-serialization',
20
+ description: 'process.env serialized — may leak all environment variables',
21
+ },
22
+ {
23
+ pattern: /(?:res\.(?:json|send))\s*\(\s*\{\s*\.\.\.(?:process\.env|req\.)/g,
24
+ label: 'spread-leak',
25
+ description: 'Object spread may leak sensitive fields into response',
26
+ },
27
+ {
28
+ pattern: /error\.stack|err\.stack/g,
29
+ label: 'stack-trace-exposure',
30
+ description: 'Stack trace exposed — may reveal file paths and internal structure',
31
+ },
32
+ ];
33
+ exports.responseEchoRule = {
34
+ id: 'response-echo',
35
+ name: 'Response Echo Detection',
36
+ description: 'Detects secrets or sensitive data being echoed in HTTP responses or logs',
37
+ async run(ctx) {
38
+ const codeFiles = ctx.files.filter(isCodeFile);
39
+ for (const file of codeFiles) {
40
+ let content;
41
+ try {
42
+ content = await (0, promises_1.readFile)(file, 'utf-8');
43
+ }
44
+ catch {
45
+ continue;
46
+ }
47
+ const lines = content.split('\n');
48
+ for (let i = 0; i < lines.length; i++) {
49
+ const line = lines[i];
50
+ for (const { pattern, label, description } of ECHO_PATTERNS) {
51
+ pattern.lastIndex = 0;
52
+ if (pattern.test(line)) {
53
+ ctx.addFinding({
54
+ rule: 'response-echo',
55
+ severity: label === 'stack-trace-exposure' ? 'medium' : 'high',
56
+ message: description,
57
+ location: { file, line: i + 1 },
58
+ evidence: line.trim().slice(0, 200),
59
+ suggestion: 'Never echo secrets or full env objects in responses. Sanitize output.',
60
+ });
61
+ }
62
+ }
63
+ }
64
+ }
65
+ },
66
+ };
67
+ //# sourceMappingURL=response-echo.rule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response-echo.rule.js","sourceRoot":"","sources":["../../../../src/scanners/secrets-exposure/rules/response-echo.rule.ts"],"names":[],"mappings":";;;AAAA,+CAA4C;AAG5C,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAEhF,SAAS,UAAU,CAAC,IAAY;IAC9B,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAClC,OAAO,GAAG,KAAK,CAAC,CAAC,IAAI,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;AAC1E,CAAC;AAED,6EAA6E;AAC7E,MAAM,aAAa,GAAG;IACpB;QACE,OAAO,EAAE,uHAAuH;QAChI,KAAK,EAAE,qBAAqB;QAC5B,WAAW,EAAE,oEAAoE;KAClF;IACD;QACE,OAAO,EAAE,uDAAuD;QAChE,KAAK,EAAE,mBAAmB;QAC1B,WAAW,EAAE,6DAA6D;KAC3E;IACD;QACE,OAAO,EAAE,kEAAkE;QAC3E,KAAK,EAAE,aAAa;QACpB,WAAW,EAAE,uDAAuD;KACrE;IACD;QACE,OAAO,EAAE,0BAA0B;QACnC,KAAK,EAAE,sBAAsB;QAC7B,WAAW,EAAE,oEAAoE;KAClF;CACF,CAAC;AAEW,QAAA,gBAAgB,GAAS;IACpC,EAAE,EAAE,eAAe;IACnB,IAAI,EAAE,yBAAyB;IAC/B,WAAW,EAAE,0EAA0E;IAEvF,KAAK,CAAC,GAAG,CAAC,GAAgB;QACxB,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAE/C,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;YAC7B,IAAI,OAAe,CAAC;YACpB,IAAI,CAAC;gBACH,OAAO,GAAG,MAAM,IAAA,mBAAQ,EAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAC1C,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;YAED,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAClC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBACtB,KAAK,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,aAAa,EAAE,CAAC;oBAC5D,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC;oBACtB,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;wBACvB,GAAG,CAAC,UAAU,CAAC;4BACb,IAAI,EAAE,eAAe;4BACrB,QAAQ,EAAE,KAAK,KAAK,sBAAsB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM;4BAC9D,OAAO,EAAE,WAAW;4BACpB,QAAQ,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE;4BAC/B,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;4BACnC,UAAU,EAAE,uEAAuE;yBACpF,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;CACF,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Scanner } from '../../types/index.js';
2
+ export declare const secretsExposureScanner: Scanner;
3
+ //# sourceMappingURL=scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../../src/scanners/secrets-exposure/scanner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAqB,MAAM,sBAAsB,CAAC;AAWvE,eAAO,MAAM,sBAAsB,EAAE,OAapC,CAAC"}
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.secretsExposureScanner = void 0;
4
+ const entropy_check_rule_js_1 = require("./rules/entropy-check.rule.js");
5
+ const known_patterns_rule_js_1 = require("./rules/known-patterns.rule.js");
6
+ const response_echo_rule_js_1 = require("./rules/response-echo.rule.js");
7
+ const rules = [
8
+ known_patterns_rule_js_1.knownPatternsRule,
9
+ entropy_check_rule_js_1.entropyCheckRule,
10
+ response_echo_rule_js_1.responseEchoRule,
11
+ ];
12
+ exports.secretsExposureScanner = {
13
+ id: 'secrets-exposure',
14
+ name: 'Secrets Exposure',
15
+ description: 'Detects hardcoded secrets, high-entropy strings, and response echo vulnerabilities',
16
+ rules,
17
+ async scan(ctx) {
18
+ for (const rule of rules) {
19
+ const ruleConfig = ctx.scannerConfig.rules?.[rule.id];
20
+ if (ruleConfig?.enabled === false)
21
+ continue;
22
+ await rule.run(ctx);
23
+ }
24
+ },
25
+ };
26
+ //# sourceMappingURL=scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../../../src/scanners/secrets-exposure/scanner.ts"],"names":[],"mappings":";;;AACA,yEAAiE;AACjE,2EAAmE;AACnE,yEAAiE;AAEjE,MAAM,KAAK,GAAW;IACpB,0CAAiB;IACjB,wCAAgB;IAChB,wCAAgB;CACjB,CAAC;AAEW,QAAA,sBAAsB,GAAY;IAC7C,EAAE,EAAE,kBAAkB;IACtB,IAAI,EAAE,kBAAkB;IACxB,WAAW,EAAE,oFAAoF;IACjG,KAAK;IAEL,KAAK,CAAC,IAAI,CAAC,GAAgB;QACzB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,UAAU,GAAG,GAAG,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACtD,IAAI,UAAU,EAAE,OAAO,KAAK,KAAK;gBAAE,SAAS;YAC5C,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;CACF,CAAC"}
@@ -0,0 +1,22 @@
1
+ export type Severity = 'critical' | 'high' | 'medium' | 'low' | 'info';
2
+ export type ScannerId = 'ai-tool-integrity' | 'secrets-exposure' | 'dependency-integrity' | 'runtime-monitor';
3
+ export interface RuleConfig {
4
+ enabled: boolean;
5
+ severity?: Severity;
6
+ options?: Record<string, unknown>;
7
+ }
8
+ export interface ScannerConfig {
9
+ enabled: boolean;
10
+ rules?: Record<string, RuleConfig>;
11
+ }
12
+ export interface WatchmanConfig {
13
+ projectRoot: string;
14
+ scanners: Partial<Record<ScannerId, ScannerConfig>>;
15
+ include?: string[];
16
+ exclude?: string[];
17
+ failOn?: Severity;
18
+ quiet?: boolean;
19
+ maxFindings?: number;
20
+ }
21
+ export declare const DEFAULT_CONFIG: Omit<WatchmanConfig, 'projectRoot'>;
22
+ //# sourceMappingURL=config.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.types.d.ts","sourceRoot":"","sources":["../../src/types/config.types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;AAEvE,MAAM,MAAM,SAAS,GACjB,mBAAmB,GACnB,kBAAkB,GAClB,sBAAsB,GACtB,iBAAiB,CAAC;AAEtB,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC;IACpD,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE,aAAa,CAU9D,CAAC"}