kramscan 0.1.1 → 0.2.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 (72) hide show
  1. package/README.md +392 -236
  2. package/dist/agent/confirmation.d.ts +5 -1
  3. package/dist/agent/confirmation.js +29 -9
  4. package/dist/agent/context.js +2 -3
  5. package/dist/agent/orchestrator.d.ts +2 -0
  6. package/dist/agent/orchestrator.js +50 -8
  7. package/dist/agent/prompts/system.d.ts +1 -1
  8. package/dist/agent/prompts/system.js +5 -7
  9. package/dist/agent/skills/health-check.js +22 -2
  10. package/dist/agent/skills/index.d.ts +1 -0
  11. package/dist/agent/skills/index.js +3 -1
  12. package/dist/agent/skills/verify-finding.d.ts +17 -0
  13. package/dist/agent/skills/verify-finding.js +91 -0
  14. package/dist/agent/skills/web-scan.js +46 -0
  15. package/dist/cli.js +150 -149
  16. package/dist/commands/agent.js +38 -38
  17. package/dist/commands/ai.d.ts +2 -0
  18. package/dist/commands/ai.js +112 -0
  19. package/dist/commands/analyze.js +103 -54
  20. package/dist/commands/config.js +55 -29
  21. package/dist/commands/doctor.js +20 -15
  22. package/dist/commands/onboard.js +188 -141
  23. package/dist/commands/report.js +68 -76
  24. package/dist/commands/scan.js +261 -81
  25. package/dist/commands/scans.d.ts +2 -0
  26. package/dist/commands/scans.js +51 -0
  27. package/dist/core/ai-client.d.ts +6 -1
  28. package/dist/core/ai-client.js +80 -12
  29. package/dist/core/ai-payloads.d.ts +17 -0
  30. package/dist/core/ai-payloads.js +54 -0
  31. package/dist/core/config-schema.d.ts +197 -0
  32. package/dist/core/config-schema.js +68 -0
  33. package/dist/core/config-schema.test.d.ts +1 -0
  34. package/dist/core/config-schema.test.js +151 -0
  35. package/dist/core/config.d.ts +8 -31
  36. package/dist/core/config.js +68 -11
  37. package/dist/core/errors.d.ts +71 -0
  38. package/dist/core/errors.js +162 -0
  39. package/dist/core/scan-index.d.ts +19 -0
  40. package/dist/core/scan-index.js +52 -0
  41. package/dist/core/scan-storage.d.ts +11 -0
  42. package/dist/core/scan-storage.js +69 -0
  43. package/dist/core/scanner.d.ts +95 -13
  44. package/dist/core/scanner.js +336 -248
  45. package/dist/core/vulnerability-detector.d.ts +3 -0
  46. package/dist/core/vulnerability-detector.js +25 -15
  47. package/dist/core/vulnerability-detector.test.d.ts +1 -0
  48. package/dist/core/vulnerability-detector.test.js +210 -0
  49. package/dist/index.js +3 -0
  50. package/dist/plugins/PluginManager.d.ts +27 -0
  51. package/dist/plugins/PluginManager.js +166 -0
  52. package/dist/plugins/index.d.ts +7 -0
  53. package/dist/plugins/index.js +19 -0
  54. package/dist/plugins/types.d.ts +55 -0
  55. package/dist/plugins/types.js +25 -0
  56. package/dist/plugins/vulnerabilities/CSRFPlugin.d.ts +8 -0
  57. package/dist/plugins/vulnerabilities/CSRFPlugin.js +34 -0
  58. package/dist/plugins/vulnerabilities/SQLInjectionPlugin.d.ts +11 -0
  59. package/dist/plugins/vulnerabilities/SQLInjectionPlugin.js +109 -0
  60. package/dist/plugins/vulnerabilities/SecurityHeadersPlugin.d.ts +11 -0
  61. package/dist/plugins/vulnerabilities/SecurityHeadersPlugin.js +63 -0
  62. package/dist/plugins/vulnerabilities/SensitiveDataPlugin.d.ts +9 -0
  63. package/dist/plugins/vulnerabilities/SensitiveDataPlugin.js +32 -0
  64. package/dist/plugins/vulnerabilities/XSSPlugin.d.ts +15 -0
  65. package/dist/plugins/vulnerabilities/XSSPlugin.js +81 -0
  66. package/dist/reports/PdfGenerator.d.ts +36 -0
  67. package/dist/reports/PdfGenerator.js +379 -0
  68. package/dist/utils/logger.d.ts +33 -1
  69. package/dist/utils/logger.js +127 -8
  70. package/dist/utils/theme.d.ts +55 -0
  71. package/dist/utils/theme.js +195 -0
  72. package/package.json +1 -1
@@ -33,6 +33,9 @@ export declare class VulnerabilityDetector {
33
33
  private vulnerabilities;
34
34
  private reportedHeaders;
35
35
  private reportedPaths;
36
+ private onVulnerabilityFound?;
37
+ setOnVulnerabilityFound(callback: (vuln: Vulnerability) => void): void;
38
+ addVulnerability(vuln: Vulnerability): void;
36
39
  detectXSS(url: string, param: string, payload: string, response: string): void;
37
40
  detectStoredXSS(url: string, payload: string, response: string): void;
38
41
  detectSQLi(url: string, param: string, errorResponse: string): void;
@@ -5,12 +5,22 @@ class VulnerabilityDetector {
5
5
  vulnerabilities = [];
6
6
  reportedHeaders = new Set();
7
7
  reportedPaths = new Set();
8
+ onVulnerabilityFound;
9
+ setOnVulnerabilityFound(callback) {
10
+ this.onVulnerabilityFound = callback;
11
+ }
12
+ addVulnerability(vuln) {
13
+ this.vulnerabilities.push(vuln);
14
+ if (this.onVulnerabilityFound) {
15
+ this.onVulnerabilityFound(vuln);
16
+ }
17
+ }
8
18
  detectXSS(url, param, payload, response) {
9
19
  if (response.includes(payload)) {
10
20
  const existing = this.vulnerabilities.find(v => v.type === "xss" && v.url === url && v.evidence?.includes(param));
11
21
  if (existing)
12
22
  return;
13
- this.vulnerabilities.push({
23
+ this.addVulnerability({
14
24
  type: "xss",
15
25
  severity: "high",
16
26
  title: "Reflected Cross-Site Scripting (XSS)",
@@ -27,7 +37,7 @@ class VulnerabilityDetector {
27
37
  const existing = this.vulnerabilities.find(v => v.type === "xss" && v.url === url && v.title.includes("Stored"));
28
38
  if (existing)
29
39
  return;
30
- this.vulnerabilities.push({
40
+ this.addVulnerability({
31
41
  type: "xss",
32
42
  severity: "critical",
33
43
  title: "Stored Cross-Site Scripting (XSS)",
@@ -65,7 +75,7 @@ class VulnerabilityDetector {
65
75
  return;
66
76
  for (const error of sqlErrors) {
67
77
  if (errorResponse.includes(error)) {
68
- this.vulnerabilities.push({
78
+ this.addVulnerability({
69
79
  type: "sqli",
70
80
  severity: "critical",
71
81
  title: "SQL Injection",
@@ -84,7 +94,7 @@ class VulnerabilityDetector {
84
94
  const existing = this.vulnerabilities.find(v => v.type === "sqli" && v.url === url && v.title.includes("Blind"));
85
95
  if (existing)
86
96
  return;
87
- this.vulnerabilities.push({
97
+ this.addVulnerability({
88
98
  type: "sqli",
89
99
  severity: "high",
90
100
  title: "Blind SQL Injection",
@@ -105,7 +115,7 @@ class VulnerabilityDetector {
105
115
  const existing = this.vulnerabilities.find(v => v.type === "csrf" && v.url === url);
106
116
  if (existing)
107
117
  return;
108
- this.vulnerabilities.push({
118
+ this.addVulnerability({
109
119
  type: "csrf",
110
120
  severity: "medium",
111
121
  title: "Missing CSRF Protection",
@@ -157,7 +167,7 @@ class VulnerabilityDetector {
157
167
  for (const [header, config] of Object.entries(requiredHeaders)) {
158
168
  if (!headers[header.toLowerCase()]) {
159
169
  missingCount++;
160
- this.vulnerabilities.push({
170
+ this.addVulnerability({
161
171
  type: "header",
162
172
  severity: config.severity,
163
173
  title: config.title,
@@ -190,7 +200,7 @@ class VulnerabilityDetector {
190
200
  const existing = this.vulnerabilities.find(v => v.type === "sensitive_data" && v.url === url && v.title.includes(pattern.name));
191
201
  if (existing)
192
202
  continue;
193
- this.vulnerabilities.push({
203
+ this.addVulnerability({
194
204
  type: "sensitive_data",
195
205
  severity: pattern.severity,
196
206
  title: `Exposed ${pattern.name}`,
@@ -210,7 +220,7 @@ class VulnerabilityDetector {
210
220
  const existing = this.vulnerabilities.find(v => v.type === "idor" && v.url === url && v.evidence?.includes(paramName));
211
221
  if (existing)
212
222
  return;
213
- this.vulnerabilities.push({
223
+ this.addVulnerability({
214
224
  type: "idor",
215
225
  severity: "high",
216
226
  title: "Insecure Direct Object Reference (IDOR)",
@@ -239,7 +249,7 @@ class VulnerabilityDetector {
239
249
  const existing = this.vulnerabilities.find(v => v.type === "lfi" && v.url === url);
240
250
  if (existing)
241
251
  return;
242
- this.vulnerabilities.push({
252
+ this.addVulnerability({
243
253
  type: "lfi",
244
254
  severity: "critical",
245
255
  title: "Local File Inclusion (LFI)",
@@ -270,7 +280,7 @@ class VulnerabilityDetector {
270
280
  if (this.reportedPaths.has(pathKey))
271
281
  return;
272
282
  this.reportedPaths.add(pathKey);
273
- this.vulnerabilities.push({
283
+ this.addVulnerability({
274
284
  type: "lfi",
275
285
  severity: "high",
276
286
  title: "Path Traversal",
@@ -305,7 +315,7 @@ class VulnerabilityDetector {
305
315
  const existing = this.vulnerabilities.find(v => v.type === "cmdi" && v.url === url);
306
316
  if (existing)
307
317
  return;
308
- this.vulnerabilities.push({
318
+ this.addVulnerability({
309
319
  type: "cmdi",
310
320
  severity: "critical",
311
321
  title: "OS Command Injection",
@@ -336,7 +346,7 @@ class VulnerabilityDetector {
336
346
  const existing = this.vulnerabilities.find(v => v.type === "ssrf" && v.url === url);
337
347
  if (existing)
338
348
  return;
339
- this.vulnerabilities.push({
349
+ this.addVulnerability({
340
350
  type: "ssrf",
341
351
  severity: "high",
342
352
  title: "Server-Side Request Forgery (SSRF)",
@@ -361,7 +371,7 @@ class VulnerabilityDetector {
361
371
  const existing = this.vulnerabilities.find(v => v.type === "redirect" && v.url === url);
362
372
  if (existing)
363
373
  return;
364
- this.vulnerabilities.push({
374
+ this.addVulnerability({
365
375
  type: "redirect",
366
376
  severity: "medium",
367
377
  title: "Open Redirect",
@@ -378,7 +388,7 @@ class VulnerabilityDetector {
378
388
  const existing = this.vulnerabilities.find(v => v.type === "redirect" && v.url === url);
379
389
  if (existing)
380
390
  return;
381
- this.vulnerabilities.push({
391
+ this.addVulnerability({
382
392
  type: "redirect",
383
393
  severity: "medium",
384
394
  title: "Open Redirect",
@@ -412,7 +422,7 @@ class VulnerabilityDetector {
412
422
  const existing = this.vulnerabilities.find(v => v.type === "info" && v.url === url && v.title === pattern.name);
413
423
  if (existing)
414
424
  continue;
415
- this.vulnerabilities.push({
425
+ this.addVulnerability({
416
426
  type: "info",
417
427
  severity: pattern.severity,
418
428
  title: pattern.name,
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,210 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vulnerability_detector_1 = require("./vulnerability-detector");
4
+ describe("VulnerabilityDetector", () => {
5
+ let detector;
6
+ beforeEach(() => {
7
+ detector = new vulnerability_detector_1.VulnerabilityDetector();
8
+ });
9
+ // ─── detectXSS ─────────────────────────────────────────────────
10
+ describe("detectXSS", () => {
11
+ it("should detect reflected XSS when payload is in response", () => {
12
+ const payload = "<script>alert('XSS')</script>";
13
+ detector.detectXSS("https://example.com/search?q=test", "q", payload, `<html><body>${payload}</body></html>`);
14
+ const vulns = detector.getVulnerabilities();
15
+ expect(vulns).toHaveLength(1);
16
+ expect(vulns[0].type).toBe("xss");
17
+ expect(vulns[0].severity).toBe("high");
18
+ expect(vulns[0].cwe).toBe("CWE-79");
19
+ });
20
+ it("should not report XSS when payload is not reflected", () => {
21
+ detector.detectXSS("https://example.com/search", "q", "<script>alert(1)</script>", "<html><body>Safe content</body></html>");
22
+ expect(detector.getVulnerabilities()).toHaveLength(0);
23
+ });
24
+ it("should report XSS for each detection call (no deduplication)", () => {
25
+ const payload = "<script>alert('XSS')</script>";
26
+ const response = `<html>${payload}</html>`;
27
+ detector.detectXSS("https://example.com", "q", payload, response);
28
+ detector.detectXSS("https://example.com", "q", payload, response);
29
+ // XSS detection does not deduplicate — each call adds a separate finding
30
+ expect(detector.getVulnerabilities()).toHaveLength(2);
31
+ });
32
+ });
33
+ // ─── detectSQLi ────────────────────────────────────────────────
34
+ describe("detectSQLi", () => {
35
+ it("should detect SQL injection from error messages", () => {
36
+ detector.detectSQLi("https://example.com/users?id=1", "id", "You have an error in your SQL syntax near '1'");
37
+ const vulns = detector.getVulnerabilities();
38
+ expect(vulns).toHaveLength(1);
39
+ expect(vulns[0].type).toBe("sqli");
40
+ expect(vulns[0].severity).toBe("critical");
41
+ expect(vulns[0].cwe).toBe("CWE-89");
42
+ });
43
+ it("should detect PostgreSQL errors", () => {
44
+ detector.detectSQLi("https://example.com/api", "q", "ERROR: PostgreSQL syntax error at position 42");
45
+ expect(detector.getVulnerabilities()).toHaveLength(1);
46
+ });
47
+ it("should not report when no SQL errors found", () => {
48
+ detector.detectSQLi("https://example.com", "q", "<html><body>Normal content</body></html>");
49
+ expect(detector.getVulnerabilities()).toHaveLength(0);
50
+ });
51
+ it("should deduplicate SQLi findings for the same URL", () => {
52
+ detector.detectSQLi("https://example.com", "id", "SQL syntax error");
53
+ detector.detectSQLi("https://example.com", "name", "ORA-00933 error");
54
+ expect(detector.getVulnerabilities()).toHaveLength(1);
55
+ });
56
+ });
57
+ // ─── detectBlindSQLi ───────────────────────────────────────────
58
+ describe("detectBlindSQLi", () => {
59
+ it("should detect time-based blind SQLi when delay exceeds threshold", () => {
60
+ detector.detectBlindSQLi("https://example.com", "id", 500, 4000);
61
+ const vulns = detector.getVulnerabilities();
62
+ expect(vulns).toHaveLength(1);
63
+ expect(vulns[0].type).toBe("sqli");
64
+ expect(vulns[0].title).toContain("Blind");
65
+ });
66
+ it("should not report when delay is within threshold", () => {
67
+ detector.detectBlindSQLi("https://example.com", "id", 500, 2000);
68
+ expect(detector.getVulnerabilities()).toHaveLength(0);
69
+ });
70
+ });
71
+ // ─── detectCSRF ────────────────────────────────────────────────
72
+ describe("detectCSRF", () => {
73
+ it("should detect missing CSRF token", () => {
74
+ detector.detectCSRF("https://example.com/form", '<form method="POST"><input name="email" /></form>');
75
+ const vulns = detector.getVulnerabilities();
76
+ expect(vulns).toHaveLength(1);
77
+ expect(vulns[0].type).toBe("csrf");
78
+ expect(vulns[0].severity).toBe("medium");
79
+ });
80
+ it("should not report when CSRF token is present", () => {
81
+ detector.detectCSRF("https://example.com/form", '<form method="POST"><input name="csrf_token" /><input name="email" /></form>');
82
+ expect(detector.getVulnerabilities()).toHaveLength(0);
83
+ });
84
+ it("should recognize _token as a valid CSRF token", () => {
85
+ detector.detectCSRF("https://example.com", '<form><input name="_token" value="abc123" /></form>');
86
+ expect(detector.getVulnerabilities()).toHaveLength(0);
87
+ });
88
+ });
89
+ // ─── analyzeSecurityHeaders ────────────────────────────────────
90
+ describe("analyzeSecurityHeaders", () => {
91
+ it("should detect missing security headers", () => {
92
+ detector.analyzeSecurityHeaders("https://example.com", {});
93
+ const vulns = detector.getVulnerabilities();
94
+ expect(vulns.length).toBeGreaterThanOrEqual(3);
95
+ expect(vulns.every((v) => v.type === "header")).toBe(true);
96
+ });
97
+ it("should not report when all headers are present", () => {
98
+ detector.analyzeSecurityHeaders("https://example.com", {
99
+ "content-security-policy": "default-src 'self'",
100
+ "x-frame-options": "DENY",
101
+ "strict-transport-security": "max-age=31536000",
102
+ "x-content-type-options": "nosniff",
103
+ "referrer-policy": "strict-origin-when-cross-origin",
104
+ "permissions-policy": "camera=()",
105
+ });
106
+ expect(detector.getVulnerabilities()).toHaveLength(0);
107
+ });
108
+ it("should only check headers once per host", () => {
109
+ detector.analyzeSecurityHeaders("https://example.com/page1", {});
110
+ const count1 = detector.getVulnerabilities().length;
111
+ detector.analyzeSecurityHeaders("https://example.com/page2", {});
112
+ const count2 = detector.getVulnerabilities().length;
113
+ expect(count2).toBe(count1);
114
+ });
115
+ });
116
+ // ─── detectSensitiveData ──────────────────────────────────────
117
+ describe("detectSensitiveData", () => {
118
+ it("should detect exposed AWS access keys", () => {
119
+ detector.detectSensitiveData("https://example.com", 'config = { key: "AKIAIOSFODNN7EXAMPLE" }');
120
+ const vulns = detector.getVulnerabilities();
121
+ expect(vulns).toHaveLength(1);
122
+ expect(vulns[0].type).toBe("sensitive_data");
123
+ expect(vulns[0].severity).toBe("critical");
124
+ });
125
+ it("should detect exposed JWT tokens", () => {
126
+ detector.detectSensitiveData("https://example.com", 'let token = "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0"');
127
+ const vulns = detector.getVulnerabilities();
128
+ expect(vulns).toHaveLength(1);
129
+ expect(vulns[0].title).toContain("JWT");
130
+ });
131
+ it("should detect private keys", () => {
132
+ detector.detectSensitiveData("https://example.com", "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAK...");
133
+ const vulns = detector.getVulnerabilities();
134
+ expect(vulns).toHaveLength(1);
135
+ expect(vulns[0].severity).toBe("critical");
136
+ });
137
+ it("should not report on clean responses", () => {
138
+ detector.detectSensitiveData("https://example.com", "<html><body>Hello World</body></html>");
139
+ expect(detector.getVulnerabilities()).toHaveLength(0);
140
+ });
141
+ });
142
+ // ─── getSummary ────────────────────────────────────────────────
143
+ describe("getSummary", () => {
144
+ it("should return correct severity counts", () => {
145
+ // Add mixed severity vulns
146
+ detector.addVulnerability({
147
+ type: "xss", severity: "high", title: "XSS",
148
+ description: "test", url: "https://example.com",
149
+ });
150
+ detector.addVulnerability({
151
+ type: "sqli", severity: "critical", title: "SQLi",
152
+ description: "test", url: "https://example.com",
153
+ });
154
+ detector.addVulnerability({
155
+ type: "header", severity: "low", title: "Header",
156
+ description: "test", url: "https://example.com",
157
+ });
158
+ detector.addVulnerability({
159
+ type: "info", severity: "info", title: "Info",
160
+ description: "test", url: "https://example.com",
161
+ });
162
+ const summary = detector.getSummary();
163
+ expect(summary.total).toBe(4);
164
+ expect(summary.critical).toBe(1);
165
+ expect(summary.high).toBe(1);
166
+ expect(summary.low).toBe(1);
167
+ expect(summary.info).toBe(1);
168
+ expect(summary.medium).toBe(0);
169
+ });
170
+ it("should return zeros when no vulnerabilities", () => {
171
+ const summary = detector.getSummary();
172
+ expect(summary.total).toBe(0);
173
+ expect(summary.critical).toBe(0);
174
+ });
175
+ });
176
+ // ─── clear ─────────────────────────────────────────────────────
177
+ describe("clear", () => {
178
+ it("should remove all vulnerabilities and reset state", () => {
179
+ detector.addVulnerability({
180
+ type: "xss", severity: "high", title: "XSS",
181
+ description: "test", url: "https://example.com",
182
+ });
183
+ expect(detector.getVulnerabilities()).toHaveLength(1);
184
+ detector.clear();
185
+ expect(detector.getVulnerabilities()).toHaveLength(0);
186
+ expect(detector.getSummary().total).toBe(0);
187
+ });
188
+ it("should allow re-detecting after clear", () => {
189
+ detector.analyzeSecurityHeaders("https://example.com", {});
190
+ const count1 = detector.getVulnerabilities().length;
191
+ detector.clear();
192
+ detector.analyzeSecurityHeaders("https://example.com", {});
193
+ const count2 = detector.getVulnerabilities().length;
194
+ expect(count2).toBe(count1);
195
+ });
196
+ });
197
+ // ─── Callback ──────────────────────────────────────────────────
198
+ describe("onVulnerabilityFound callback", () => {
199
+ it("should call callback when vulnerability is added", () => {
200
+ const callback = jest.fn();
201
+ detector.setOnVulnerabilityFound(callback);
202
+ detector.addVulnerability({
203
+ type: "xss", severity: "high", title: "XSS",
204
+ description: "test", url: "https://example.com",
205
+ });
206
+ expect(callback).toHaveBeenCalledTimes(1);
207
+ expect(callback).toHaveBeenCalledWith(expect.objectContaining({ type: "xss", severity: "high" }));
208
+ });
209
+ });
210
+ });
package/dist/index.js CHANGED
@@ -1,6 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const cli_1 = require("./cli");
4
+ const errors_1 = require("./core/errors");
5
+ // Ensure uncaught exceptions and unhandled rejections produce useful output
6
+ (0, errors_1.setupGlobalErrorHandlers)();
4
7
  (0, cli_1.run)().catch((err) => {
5
8
  console.error("Fatal error:", err);
6
9
  process.exit(1);
@@ -0,0 +1,27 @@
1
+ import { VulnerabilityPlugin, PluginContext, FormData } from "./types";
2
+ import { Vulnerability } from "../core/vulnerability-detector";
3
+ export interface PluginExecutionResult {
4
+ plugin: string;
5
+ vulnerabilities: Vulnerability[];
6
+ errors: Array<{
7
+ url: string;
8
+ error: string;
9
+ }>;
10
+ duration: number;
11
+ }
12
+ export declare class PluginManager {
13
+ private plugins;
14
+ private enabledPlugins;
15
+ register(plugin: VulnerabilityPlugin): void;
16
+ unregister(pluginName: string): boolean;
17
+ enable(pluginName: string): boolean;
18
+ disable(pluginName: string): boolean;
19
+ getPlugin(name: string): VulnerabilityPlugin | undefined;
20
+ getAllPlugins(): VulnerabilityPlugin[];
21
+ getEnabledPlugins(): VulnerabilityPlugin[];
22
+ testParameter(context: PluginContext, param: string, value: string): Promise<PluginExecutionResult[]>;
23
+ testFormInput(context: PluginContext, formData: FormData): Promise<PluginExecutionResult[]>;
24
+ analyzeContent(context: PluginContext, content: string): Promise<PluginExecutionResult[]>;
25
+ analyzeHeaders(context: PluginContext, headers: Record<string, string>): Promise<PluginExecutionResult[]>;
26
+ }
27
+ export declare const pluginManager: PluginManager;
@@ -0,0 +1,166 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.pluginManager = exports.PluginManager = void 0;
4
+ class PluginManager {
5
+ plugins = new Map();
6
+ enabledPlugins = new Set();
7
+ register(plugin) {
8
+ this.plugins.set(plugin.name, plugin);
9
+ if (plugin.enabled) {
10
+ this.enabledPlugins.add(plugin.name);
11
+ }
12
+ }
13
+ unregister(pluginName) {
14
+ this.enabledPlugins.delete(pluginName);
15
+ return this.plugins.delete(pluginName);
16
+ }
17
+ enable(pluginName) {
18
+ if (this.plugins.has(pluginName)) {
19
+ this.enabledPlugins.add(pluginName);
20
+ return true;
21
+ }
22
+ return false;
23
+ }
24
+ disable(pluginName) {
25
+ return this.enabledPlugins.delete(pluginName);
26
+ }
27
+ getPlugin(name) {
28
+ return this.plugins.get(name);
29
+ }
30
+ getAllPlugins() {
31
+ return Array.from(this.plugins.values());
32
+ }
33
+ getEnabledPlugins() {
34
+ return Array.from(this.enabledPlugins)
35
+ .map(name => this.plugins.get(name))
36
+ .filter((p) => p !== undefined);
37
+ }
38
+ async testParameter(context, param, value) {
39
+ const results = [];
40
+ for (const plugin of this.getEnabledPlugins()) {
41
+ if (!plugin.testParameter)
42
+ continue;
43
+ const startTime = Date.now();
44
+ const vulnerabilities = [];
45
+ const errors = [];
46
+ try {
47
+ const result = await plugin.testParameter(context, param, value);
48
+ if (result.found && result.vulnerability) {
49
+ vulnerabilities.push(result.vulnerability);
50
+ }
51
+ if (result.error) {
52
+ errors.push({ url: context.url, error: result.error });
53
+ }
54
+ }
55
+ catch (error) {
56
+ errors.push({
57
+ url: context.url,
58
+ error: error.message
59
+ });
60
+ }
61
+ results.push({
62
+ plugin: plugin.name,
63
+ vulnerabilities,
64
+ errors,
65
+ duration: Date.now() - startTime,
66
+ });
67
+ }
68
+ return results;
69
+ }
70
+ async testFormInput(context, formData) {
71
+ const results = [];
72
+ for (const plugin of this.getEnabledPlugins()) {
73
+ if (!plugin.testFormInput)
74
+ continue;
75
+ const startTime = Date.now();
76
+ const vulnerabilities = [];
77
+ const errors = [];
78
+ try {
79
+ const result = await plugin.testFormInput(context, formData);
80
+ if (result.found && result.vulnerability) {
81
+ vulnerabilities.push(result.vulnerability);
82
+ }
83
+ if (result.error) {
84
+ errors.push({ url: context.url, error: result.error });
85
+ }
86
+ }
87
+ catch (error) {
88
+ errors.push({
89
+ url: context.url,
90
+ error: error.message
91
+ });
92
+ }
93
+ results.push({
94
+ plugin: plugin.name,
95
+ vulnerabilities,
96
+ errors,
97
+ duration: Date.now() - startTime,
98
+ });
99
+ }
100
+ return results;
101
+ }
102
+ async analyzeContent(context, content) {
103
+ const results = [];
104
+ for (const plugin of this.getEnabledPlugins()) {
105
+ if (!plugin.analyzeContent)
106
+ continue;
107
+ const startTime = Date.now();
108
+ const errors = [];
109
+ try {
110
+ const vulnerabilities = await plugin.analyzeContent(context, content);
111
+ results.push({
112
+ plugin: plugin.name,
113
+ vulnerabilities,
114
+ errors,
115
+ duration: Date.now() - startTime,
116
+ });
117
+ }
118
+ catch (error) {
119
+ errors.push({
120
+ url: context.url,
121
+ error: error.message
122
+ });
123
+ results.push({
124
+ plugin: plugin.name,
125
+ vulnerabilities: [],
126
+ errors,
127
+ duration: Date.now() - startTime,
128
+ });
129
+ }
130
+ }
131
+ return results;
132
+ }
133
+ async analyzeHeaders(context, headers) {
134
+ const results = [];
135
+ for (const plugin of this.getEnabledPlugins()) {
136
+ if (!plugin.analyzeHeaders)
137
+ continue;
138
+ const startTime = Date.now();
139
+ const errors = [];
140
+ try {
141
+ const vulnerabilities = await plugin.analyzeHeaders(context, headers);
142
+ results.push({
143
+ plugin: plugin.name,
144
+ vulnerabilities,
145
+ errors,
146
+ duration: Date.now() - startTime,
147
+ });
148
+ }
149
+ catch (error) {
150
+ errors.push({
151
+ url: context.url,
152
+ error: error.message
153
+ });
154
+ results.push({
155
+ plugin: plugin.name,
156
+ vulnerabilities: [],
157
+ errors,
158
+ duration: Date.now() - startTime,
159
+ });
160
+ }
161
+ }
162
+ return results;
163
+ }
164
+ }
165
+ exports.PluginManager = PluginManager;
166
+ exports.pluginManager = new PluginManager();
@@ -0,0 +1,7 @@
1
+ export { VulnerabilityPlugin, PluginContext, BaseVulnerabilityPlugin, VulnerabilityTestResult, FormData } from "./types";
2
+ export { PluginManager, PluginExecutionResult, pluginManager } from "./PluginManager";
3
+ export { XSSPlugin } from "./vulnerabilities/XSSPlugin";
4
+ export { SQLInjectionPlugin } from "./vulnerabilities/SQLInjectionPlugin";
5
+ export { SecurityHeadersPlugin } from "./vulnerabilities/SecurityHeadersPlugin";
6
+ export { SensitiveDataPlugin } from "./vulnerabilities/SensitiveDataPlugin";
7
+ export { CSRFPlugin } from "./vulnerabilities/CSRFPlugin";
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CSRFPlugin = exports.SensitiveDataPlugin = exports.SecurityHeadersPlugin = exports.SQLInjectionPlugin = exports.XSSPlugin = exports.pluginManager = exports.PluginManager = exports.BaseVulnerabilityPlugin = void 0;
4
+ var types_1 = require("./types");
5
+ Object.defineProperty(exports, "BaseVulnerabilityPlugin", { enumerable: true, get: function () { return types_1.BaseVulnerabilityPlugin; } });
6
+ var PluginManager_1 = require("./PluginManager");
7
+ Object.defineProperty(exports, "PluginManager", { enumerable: true, get: function () { return PluginManager_1.PluginManager; } });
8
+ Object.defineProperty(exports, "pluginManager", { enumerable: true, get: function () { return PluginManager_1.pluginManager; } });
9
+ // Vulnerability plugins
10
+ var XSSPlugin_1 = require("./vulnerabilities/XSSPlugin");
11
+ Object.defineProperty(exports, "XSSPlugin", { enumerable: true, get: function () { return XSSPlugin_1.XSSPlugin; } });
12
+ var SQLInjectionPlugin_1 = require("./vulnerabilities/SQLInjectionPlugin");
13
+ Object.defineProperty(exports, "SQLInjectionPlugin", { enumerable: true, get: function () { return SQLInjectionPlugin_1.SQLInjectionPlugin; } });
14
+ var SecurityHeadersPlugin_1 = require("./vulnerabilities/SecurityHeadersPlugin");
15
+ Object.defineProperty(exports, "SecurityHeadersPlugin", { enumerable: true, get: function () { return SecurityHeadersPlugin_1.SecurityHeadersPlugin; } });
16
+ var SensitiveDataPlugin_1 = require("./vulnerabilities/SensitiveDataPlugin");
17
+ Object.defineProperty(exports, "SensitiveDataPlugin", { enumerable: true, get: function () { return SensitiveDataPlugin_1.SensitiveDataPlugin; } });
18
+ var CSRFPlugin_1 = require("./vulnerabilities/CSRFPlugin");
19
+ Object.defineProperty(exports, "CSRFPlugin", { enumerable: true, get: function () { return CSRFPlugin_1.CSRFPlugin; } });
@@ -0,0 +1,55 @@
1
+ import { Page } from "puppeteer";
2
+ import { Vulnerability, VulnerabilityType, Severity } from "../core/vulnerability-detector";
3
+ export interface PluginContext {
4
+ page: Page;
5
+ url: string;
6
+ baseUrl: string;
7
+ timeout: number;
8
+ userAgent: string;
9
+ payloadGenerator?: any;
10
+ }
11
+ export interface VulnerabilityTestResult {
12
+ found: boolean;
13
+ vulnerability?: Vulnerability;
14
+ error?: string;
15
+ }
16
+ export interface VulnerabilityPlugin {
17
+ readonly name: string;
18
+ readonly type: VulnerabilityType;
19
+ readonly description: string;
20
+ readonly enabled: boolean;
21
+ /**
22
+ * Test a URL parameter for this vulnerability
23
+ */
24
+ testParameter?(context: PluginContext, param: string, value: string): Promise<VulnerabilityTestResult>;
25
+ /**
26
+ * Test a form input for this vulnerability
27
+ */
28
+ testFormInput?(context: PluginContext, formData: FormData): Promise<VulnerabilityTestResult>;
29
+ /**
30
+ * Analyze page content for this vulnerability
31
+ */
32
+ analyzeContent?(context: PluginContext, content: string): Promise<Vulnerability[]>;
33
+ /**
34
+ * Analyze HTTP headers for this vulnerability
35
+ */
36
+ analyzeHeaders?(context: PluginContext, headers: Record<string, string>): Promise<Vulnerability[]>;
37
+ }
38
+ export interface FormData {
39
+ action: string;
40
+ method: string;
41
+ inputs: Array<{
42
+ name: string;
43
+ type: string;
44
+ value?: string;
45
+ }>;
46
+ }
47
+ export declare abstract class BaseVulnerabilityPlugin implements VulnerabilityPlugin {
48
+ abstract readonly name: string;
49
+ abstract readonly type: VulnerabilityType;
50
+ abstract readonly description: string;
51
+ enabled: boolean;
52
+ protected createVulnerability(title: string, description: string, url: string, severity: Severity, evidence?: string, remediation?: string, cwe?: string): Vulnerability;
53
+ protected success(vulnerability: Vulnerability): VulnerabilityTestResult;
54
+ protected failure(error?: string): VulnerabilityTestResult;
55
+ }