kramscan 0.1.0 → 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 (105) hide show
  1. package/README.md +392 -87
  2. package/dist/agent/confirmation.d.ts +38 -0
  3. package/dist/agent/confirmation.js +210 -0
  4. package/dist/agent/context.d.ts +81 -0
  5. package/dist/agent/context.js +227 -0
  6. package/dist/agent/index.d.ts +10 -0
  7. package/dist/agent/index.js +32 -0
  8. package/dist/agent/orchestrator.d.ts +63 -0
  9. package/dist/agent/orchestrator.js +370 -0
  10. package/dist/agent/prompts/system.d.ts +6 -0
  11. package/dist/agent/prompts/system.js +116 -0
  12. package/dist/agent/skill-registry.d.ts +78 -0
  13. package/dist/agent/skill-registry.js +202 -0
  14. package/dist/agent/skills/analyze-findings.d.ts +22 -0
  15. package/dist/agent/skills/analyze-findings.js +191 -0
  16. package/dist/agent/skills/generate-report.d.ts +26 -0
  17. package/dist/agent/skills/generate-report.js +436 -0
  18. package/dist/agent/skills/health-check.d.ts +28 -0
  19. package/dist/agent/skills/health-check.js +344 -0
  20. package/dist/agent/skills/index.d.ts +9 -0
  21. package/dist/agent/skills/index.js +17 -0
  22. package/dist/agent/skills/verify-finding.d.ts +17 -0
  23. package/dist/agent/skills/verify-finding.js +91 -0
  24. package/dist/agent/skills/web-scan.d.ts +22 -0
  25. package/dist/agent/skills/web-scan.js +203 -0
  26. package/dist/agent/types.d.ts +141 -0
  27. package/dist/agent/types.js +16 -0
  28. package/dist/cli.d.ts +3 -0
  29. package/dist/cli.js +176 -139
  30. package/dist/commands/agent.d.ts +6 -0
  31. package/dist/commands/agent.js +250 -0
  32. package/dist/commands/ai.d.ts +2 -0
  33. package/dist/commands/ai.js +112 -0
  34. package/dist/commands/analyze.js +104 -55
  35. package/dist/commands/config.js +63 -37
  36. package/dist/commands/doctor.js +22 -17
  37. package/dist/commands/onboard.js +190 -125
  38. package/dist/commands/report.js +69 -77
  39. package/dist/commands/scan.js +261 -81
  40. package/dist/commands/scans.d.ts +2 -0
  41. package/dist/commands/scans.js +51 -0
  42. package/dist/core/ai-client.d.ts +7 -2
  43. package/dist/core/ai-client.js +231 -20
  44. package/dist/core/ai-payloads.d.ts +17 -0
  45. package/dist/core/ai-payloads.js +54 -0
  46. package/dist/core/config-schema.d.ts +197 -0
  47. package/dist/core/config-schema.js +68 -0
  48. package/dist/core/config-schema.test.d.ts +1 -0
  49. package/dist/core/config-schema.test.js +151 -0
  50. package/dist/core/config.d.ts +17 -36
  51. package/dist/core/config.js +261 -20
  52. package/dist/core/errors.d.ts +71 -0
  53. package/dist/core/errors.js +162 -0
  54. package/dist/core/scan-index.d.ts +19 -0
  55. package/dist/core/scan-index.js +52 -0
  56. package/dist/core/scan-storage.d.ts +11 -0
  57. package/dist/core/scan-storage.js +69 -0
  58. package/dist/core/scanner.d.ts +101 -4
  59. package/dist/core/scanner.js +432 -63
  60. package/dist/core/vulnerability-detector.d.ts +18 -2
  61. package/dist/core/vulnerability-detector.js +349 -38
  62. package/dist/core/vulnerability-detector.test.d.ts +1 -0
  63. package/dist/core/vulnerability-detector.test.js +210 -0
  64. package/dist/index.js +3 -0
  65. package/dist/plugins/PluginManager.d.ts +27 -0
  66. package/dist/plugins/PluginManager.js +166 -0
  67. package/dist/plugins/index.d.ts +7 -0
  68. package/dist/plugins/index.js +19 -0
  69. package/dist/plugins/types.d.ts +55 -0
  70. package/dist/plugins/types.js +25 -0
  71. package/dist/plugins/vulnerabilities/CSRFPlugin.d.ts +8 -0
  72. package/dist/plugins/vulnerabilities/CSRFPlugin.js +34 -0
  73. package/dist/plugins/vulnerabilities/SQLInjectionPlugin.d.ts +11 -0
  74. package/dist/plugins/vulnerabilities/SQLInjectionPlugin.js +109 -0
  75. package/dist/plugins/vulnerabilities/SecurityHeadersPlugin.d.ts +11 -0
  76. package/dist/plugins/vulnerabilities/SecurityHeadersPlugin.js +63 -0
  77. package/dist/plugins/vulnerabilities/SensitiveDataPlugin.d.ts +9 -0
  78. package/dist/plugins/vulnerabilities/SensitiveDataPlugin.js +32 -0
  79. package/dist/plugins/vulnerabilities/XSSPlugin.d.ts +15 -0
  80. package/dist/plugins/vulnerabilities/XSSPlugin.js +81 -0
  81. package/dist/reports/PdfGenerator.d.ts +36 -0
  82. package/dist/reports/PdfGenerator.js +379 -0
  83. package/dist/utils/logger.d.ts +33 -1
  84. package/dist/utils/logger.js +127 -8
  85. package/dist/utils/theme.d.ts +55 -0
  86. package/dist/utils/theme.js +195 -0
  87. package/package.json +27 -6
  88. package/dist/core/executor.d.ts +0 -2
  89. package/dist/core/executor.js +0 -74
  90. package/dist/core/logger.d.ts +0 -12
  91. package/dist/core/logger.js +0 -51
  92. package/dist/core/registry.d.ts +0 -3
  93. package/dist/core/registry.js +0 -35
  94. package/dist/core/storage.d.ts +0 -4
  95. package/dist/core/storage.js +0 -39
  96. package/dist/core/types.d.ts +0 -24
  97. package/dist/core/types.js +0 -2
  98. package/dist/skills/base.d.ts +0 -8
  99. package/dist/skills/base.js +0 -6
  100. package/dist/skills/builtin.d.ts +0 -4
  101. package/dist/skills/builtin.js +0 -71
  102. package/dist/skills/loader.d.ts +0 -2
  103. package/dist/skills/loader.js +0 -27
  104. package/dist/skills/types.d.ts +0 -46
  105. package/dist/skills/types.js +0 -2
@@ -3,23 +3,52 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VulnerabilityDetector = void 0;
4
4
  class VulnerabilityDetector {
5
5
  vulnerabilities = [];
6
- // XSS Detection
6
+ reportedHeaders = new Set();
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
+ }
7
18
  detectXSS(url, param, payload, response) {
8
- // Check if payload is reflected in response
9
19
  if (response.includes(payload)) {
10
- this.vulnerabilities.push({
20
+ const existing = this.vulnerabilities.find(v => v.type === "xss" && v.url === url && v.evidence?.includes(param));
21
+ if (existing)
22
+ return;
23
+ this.addVulnerability({
11
24
  type: "xss",
12
25
  severity: "high",
13
26
  title: "Reflected Cross-Site Scripting (XSS)",
14
- description: `The parameter '${param}' appears to be vulnerable to XSS. The payload was reflected in the response without proper encoding.`,
27
+ description: `The parameter '${param}' reflects user input without proper encoding, allowing script injection.`,
15
28
  url,
16
29
  evidence: `Payload: ${payload}`,
17
- remediation: "Implement proper output encoding/escaping for user-controlled data. Use Content Security Policy (CSP) headers.",
30
+ remediation: "Implement input validation, output encoding, and Content Security Policy (CSP) headers.",
31
+ cwe: "CWE-79",
32
+ });
33
+ }
34
+ }
35
+ detectStoredXSS(url, payload, response) {
36
+ if (response.includes(payload)) {
37
+ const existing = this.vulnerabilities.find(v => v.type === "xss" && v.url === url && v.title.includes("Stored"));
38
+ if (existing)
39
+ return;
40
+ this.addVulnerability({
41
+ type: "xss",
42
+ severity: "critical",
43
+ title: "Stored Cross-Site Scripting (XSS)",
44
+ description: `Malicious script is persisted on the server and executed when other users view the affected content.`,
45
+ url,
46
+ evidence: `Stored payload reflected in response`,
47
+ remediation: "Implement input validation, output encoding, and CSP. Sanitize HTML content.",
18
48
  cwe: "CWE-79",
19
49
  });
20
50
  }
21
51
  }
22
- // SQL Injection Detection
23
52
  detectSQLi(url, param, errorResponse) {
24
53
  const sqlErrors = [
25
54
  "SQL syntax",
@@ -30,97 +59,377 @@ class VulnerabilityDetector {
30
59
  "ODBC",
31
60
  "JET Database",
32
61
  "Microsoft Access Driver",
62
+ "unterminated",
63
+ "mysql_num_rows",
64
+ "mysql_query",
65
+ "Microsoft SQL Native Client error",
66
+ "SQLServer JDBC Driver",
67
+ "ORA-00933",
68
+ "PG::SyntaxError",
69
+ "Warning: pg_",
70
+ "Syntax error",
33
71
  ];
72
+ // Check if vulnerability already exists to avoid duplicates
73
+ const existing = this.vulnerabilities.find(v => v.type === "sqli" && v.url === url);
74
+ if (existing)
75
+ return;
34
76
  for (const error of sqlErrors) {
35
77
  if (errorResponse.includes(error)) {
36
- this.vulnerabilities.push({
78
+ this.addVulnerability({
37
79
  type: "sqli",
38
80
  severity: "critical",
39
81
  title: "SQL Injection",
40
- description: `The parameter '${param}' may be vulnerable to SQL injection. Database error messages were detected in the response.`,
82
+ description: `The parameter '${param}' is vulnerable to SQL injection. Database error messages were detected.`,
41
83
  url,
42
- evidence: `Error pattern: ${error}`,
43
- remediation: "Use parameterized queries or prepared statements. Never concatenate user input directly into SQL queries.",
84
+ evidence: `Error: ${error}`,
85
+ remediation: "Use parameterized queries (prepared statements). Never concatenate user input into SQL.",
44
86
  cwe: "CWE-89",
45
87
  });
46
88
  break;
47
89
  }
48
90
  }
49
91
  }
50
- // CSRF Detection
92
+ detectBlindSQLi(url, param, originalTime, testTime) {
93
+ if (testTime > originalTime + 3000) {
94
+ const existing = this.vulnerabilities.find(v => v.type === "sqli" && v.url === url && v.title.includes("Blind"));
95
+ if (existing)
96
+ return;
97
+ this.addVulnerability({
98
+ type: "sqli",
99
+ severity: "high",
100
+ title: "Blind SQL Injection",
101
+ description: `Time-based blind SQL injection detected on parameter '${param}'. Response time indicates successful payload execution.`,
102
+ url,
103
+ evidence: `Response time increased by ${testTime - originalTime}ms with sleep payload`,
104
+ remediation: "Use parameterized queries. Implement input validation and proper error handling.",
105
+ cwe: "CWE-89",
106
+ });
107
+ }
108
+ }
51
109
  detectCSRF(url, formHtml) {
52
110
  const hasCSRFToken = formHtml.includes('name="csrf') ||
53
111
  formHtml.includes('name="_token') ||
54
- formHtml.includes('name="authenticity_token');
112
+ formHtml.includes('name="authenticity_token') ||
113
+ formHtml.includes('name="_csrf');
55
114
  if (!hasCSRFToken) {
56
- this.vulnerabilities.push({
115
+ const existing = this.vulnerabilities.find(v => v.type === "csrf" && v.url === url);
116
+ if (existing)
117
+ return;
118
+ this.addVulnerability({
57
119
  type: "csrf",
58
120
  severity: "medium",
59
121
  title: "Missing CSRF Protection",
60
- description: "The form does not appear to have CSRF token protection. This could allow attackers to perform unauthorized actions on behalf of authenticated users.",
122
+ description: "Form lacks CSRF tokens. Attackers can forge requests to perform unauthorized actions.",
61
123
  url,
62
- remediation: "Implement CSRF tokens for all state-changing operations. Use SameSite cookie attribute.",
124
+ remediation: "Implement anti-CSRF tokens. Use SameSite cookies.",
63
125
  cwe: "CWE-352",
64
126
  });
65
127
  }
66
128
  }
67
- // Security Headers Analysis
68
129
  analyzeSecurityHeaders(url, headers) {
130
+ const host = new URL(url).host;
131
+ if (this.reportedHeaders.has(host)) {
132
+ return;
133
+ }
69
134
  const requiredHeaders = {
70
135
  "content-security-policy": {
71
136
  title: "Missing Content-Security-Policy",
72
- severity: "medium",
73
- remediation: "Implement a strict Content-Security-Policy to prevent XSS and data injection attacks.",
137
+ severity: "low",
138
+ remediation: "Implement a strict CSP to prevent XSS and data injection attacks.",
74
139
  },
75
140
  "x-frame-options": {
76
141
  title: "Missing X-Frame-Options",
77
- severity: "medium",
78
- remediation: "Set X-Frame-Options to DENY or SAMEORIGIN to prevent clickjacking attacks.",
142
+ severity: "low",
143
+ remediation: "Set X-Frame-Options to DENY or SAMEORIGIN to prevent clickjacking.",
79
144
  },
80
145
  "strict-transport-security": {
81
- title: "Missing Strict-Transport-Security",
82
- severity: "medium",
83
- remediation: "Enable HSTS to force HTTPS connections and prevent protocol downgrade attacks.",
146
+ title: "Missing Strict-Transport-Security (HSTS)",
147
+ severity: "low",
148
+ remediation: "Enable HSTS with max-age of at least 31536000 seconds.",
84
149
  },
85
150
  "x-content-type-options": {
86
151
  title: "Missing X-Content-Type-Options",
87
- severity: "low",
88
- remediation: "Set X-Content-Type-Options to 'nosniff' to prevent MIME-sniffing attacks.",
152
+ severity: "info",
153
+ remediation: "Set X-Content-Type-Options to 'nosniff'.",
154
+ },
155
+ "referrer-policy": {
156
+ title: "Missing Referrer-Policy",
157
+ severity: "info",
158
+ remediation: "Set Referrer-Policy to 'strict-origin-when-cross-origin'.",
159
+ },
160
+ "permissions-policy": {
161
+ title: "Missing Permissions-Policy",
162
+ severity: "info",
163
+ remediation: "Restrict browser features using Permissions-Policy header.",
89
164
  },
90
165
  };
166
+ let missingCount = 0;
91
167
  for (const [header, config] of Object.entries(requiredHeaders)) {
92
168
  if (!headers[header.toLowerCase()]) {
93
- this.vulnerabilities.push({
169
+ missingCount++;
170
+ this.addVulnerability({
94
171
  type: "header",
95
172
  severity: config.severity,
96
173
  title: config.title,
97
- description: `The ${header} security header is not set.`,
174
+ description: `The ${header} security header is not set on ${host}.`,
98
175
  url,
99
176
  remediation: config.remediation,
100
177
  });
101
178
  }
102
179
  }
180
+ if (missingCount > 0) {
181
+ this.reportedHeaders.add(host);
182
+ }
103
183
  }
104
- // Sensitive Data Detection
105
184
  detectSensitiveData(url, response) {
106
185
  const patterns = [
107
- { regex: /api[_-]?key["\s:=]+[\w-]{20,}/gi, name: "API Key" },
108
- { regex: /sk-[a-zA-Z0-9]{48}/g, name: "OpenAI API Key" },
109
- { regex: /ghp_[a-zA-Z0-9]{36}/g, name: "GitHub Token" },
110
- { regex: /AKIA[0-9A-Z]{16}/g, name: "AWS Access Key" },
111
- { regex: /password["\s:=]+[^\s"]{8,}/gi, name: "Password" },
186
+ { regex: /sk-[a-zA-Z0-9]{48}/g, name: "OpenAI API Key", severity: "critical" },
187
+ { regex: /ghp_[a-zA-Z0-9]{36}/g, name: "GitHub Token", severity: "critical" },
188
+ { regex: /AKIA[0-9A-Z]{16}/g, name: "AWS Access Key", severity: "critical" },
189
+ { regex: /xox[baprs]-[0-9a-zA-Z]{10,}/g, name: "Slack Token", severity: "high" },
190
+ { regex: /eyJ[a-zA-Z0-9_-]*\.eyJ[a-zA-Z0-9_-]*/g, name: "JWT Token", severity: "high" },
191
+ { regex: /AIza[0-9A-Za-z_-]{35}/g, name: "Google API Key", severity: "high" },
192
+ { regex: /password["\s:=]+[^\s"]{6,}/gi, name: "Hardcoded Password", severity: "high" },
193
+ { regex: /api[_-]?key["\s:=]+[\w-]{20,}/gi, name: "Generic API Key", severity: "medium" },
194
+ { regex: /-----BEGIN (RSA |EC )?PRIVATE KEY-----/g, name: "Private Key", severity: "critical" },
195
+ { regex: /database[_-]?url["\s:=]+.*(?:mysql|postgres|mongodb):\/\//gi, name: "Database Connection String", severity: "high" },
112
196
  ];
113
197
  for (const pattern of patterns) {
114
198
  const matches = response.match(pattern.regex);
115
199
  if (matches && matches.length > 0) {
116
- this.vulnerabilities.push({
200
+ const existing = this.vulnerabilities.find(v => v.type === "sensitive_data" && v.url === url && v.title.includes(pattern.name));
201
+ if (existing)
202
+ continue;
203
+ this.addVulnerability({
117
204
  type: "sensitive_data",
118
- severity: "high",
205
+ severity: pattern.severity,
119
206
  title: `Exposed ${pattern.name}`,
120
- description: `Potential ${pattern.name} found in the response. Sensitive data should never be exposed in client-side code.`,
207
+ description: `Sensitive ${pattern.name} found in response. This could lead to account compromise or data breach.`,
208
+ url,
209
+ evidence: `Found: ${matches[0].substring(0, 30)}...`,
210
+ remediation: "Remove sensitive data from client-side code. Use environment variables and secure secret management.",
211
+ cwe: "CWE-200",
212
+ });
213
+ }
214
+ }
215
+ }
216
+ detectIDOR(url, paramName, paramValue, testResponse, originalResponse) {
217
+ if (testResponse.length < originalResponse.length * 0.5 ||
218
+ testResponse.length > originalResponse.length * 1.5 ||
219
+ testResponse !== originalResponse) {
220
+ const existing = this.vulnerabilities.find(v => v.type === "idor" && v.url === url && v.evidence?.includes(paramName));
221
+ if (existing)
222
+ return;
223
+ this.addVulnerability({
224
+ type: "idor",
225
+ severity: "high",
226
+ title: "Insecure Direct Object Reference (IDOR)",
227
+ description: `Changing the parameter '${paramName}' from '${paramValue}' reveals different content without authorization. This could allow unauthorized access to other users' data.`,
228
+ url,
229
+ evidence: `Parameter: ${paramName}, Original: ${paramValue}, Response changed significantly`,
230
+ remediation: "Implement proper authorization checks. Validate user permissions before returning data.",
231
+ cwe: "CWE-639",
232
+ });
233
+ }
234
+ }
235
+ detectLFI(url, param, payload, response) {
236
+ const lfiIndicators = [
237
+ "root:x:0:0:",
238
+ "/bin/bash",
239
+ "/bin/sh",
240
+ "[boot loader]",
241
+ "Windows",
242
+ "C:\\Windows",
243
+ "Volume Serial Number",
244
+ "<!DOCTYPE html>",
245
+ "<html",
246
+ ];
247
+ for (const indicator of lfiIndicators) {
248
+ if (response.includes(indicator)) {
249
+ const existing = this.vulnerabilities.find(v => v.type === "lfi" && v.url === url);
250
+ if (existing)
251
+ return;
252
+ this.addVulnerability({
253
+ type: "lfi",
254
+ severity: "critical",
255
+ title: "Local File Inclusion (LFI)",
256
+ description: `The parameter '${param}' allows reading arbitrary files from the server.`,
257
+ url,
258
+ evidence: `Payload: ${payload}, Response contains system file content`,
259
+ remediation: "Validate and sanitize file paths. Use whitelisting. Never allow direct user input in file paths.",
260
+ cwe: "CWE-22",
261
+ });
262
+ break;
263
+ }
264
+ }
265
+ }
266
+ detectPathTraversal(url, param, payload, response) {
267
+ const traversalIndicators = [
268
+ "root:x:0:0:",
269
+ "[boot loader]",
270
+ "<!DOCTYPE html>",
271
+ "<html",
272
+ "<!DOCTYPE",
273
+ "<?xml",
274
+ ];
275
+ const isLikelyTraversalPayload = payload.includes("../") || payload.includes("..\\");
276
+ if (isLikelyTraversalPayload) {
277
+ for (const indicator of traversalIndicators) {
278
+ if (response.includes(indicator) && !response.includes("<script>")) {
279
+ const pathKey = `${url}:${param}`;
280
+ if (this.reportedPaths.has(pathKey))
281
+ return;
282
+ this.reportedPaths.add(pathKey);
283
+ this.addVulnerability({
284
+ type: "lfi",
285
+ severity: "high",
286
+ title: "Path Traversal",
287
+ description: `The parameter '${param}' allows directory traversal to access files outside the web root.`,
288
+ url,
289
+ evidence: `Payload: ${payload}`,
290
+ remediation: "Validate file paths. Use basename(). Implement whitelist approach.",
291
+ cwe: "CWE-22",
292
+ });
293
+ break;
294
+ }
295
+ }
296
+ }
297
+ }
298
+ detectCMDI(url, param, payload, response) {
299
+ const cmdiIndicators = [
300
+ "uid=",
301
+ "gid=",
302
+ "root",
303
+ "/usr/bin/",
304
+ "Microsoft Windows",
305
+ "Volume Serial Number",
306
+ "C:\\",
307
+ "DIR",
308
+ "Volume in drive",
309
+ "The system cannot find",
310
+ "command not found",
311
+ "Syntax error",
312
+ ];
313
+ for (const indicator of cmdiIndicators) {
314
+ if (response.toLowerCase().includes(indicator.toLowerCase())) {
315
+ const existing = this.vulnerabilities.find(v => v.type === "cmdi" && v.url === url);
316
+ if (existing)
317
+ return;
318
+ this.addVulnerability({
319
+ type: "cmdi",
320
+ severity: "critical",
321
+ title: "OS Command Injection",
322
+ description: `The parameter '${param}' executes system commands on the server.`,
323
+ url,
324
+ evidence: `Payload: ${payload}, Response contains system output`,
325
+ remediation: "Avoid system calls. Use built-in APIs. If needed, use strict allowlists for input.",
326
+ cwe: "CWE-78",
327
+ });
328
+ break;
329
+ }
330
+ }
331
+ }
332
+ detectSSRF(url, param, payload, response) {
333
+ const ssrfIndicators = [
334
+ "169.254.169.254",
335
+ "metadata.google.internal",
336
+ "instance-data",
337
+ "internal ip",
338
+ "localhost",
339
+ "127.0.0.1",
340
+ "aws credentials",
341
+ "security credentials",
342
+ "iam",
343
+ ];
344
+ for (const indicator of ssrfIndicators) {
345
+ if (response.toLowerCase().includes(indicator.toLowerCase())) {
346
+ const existing = this.vulnerabilities.find(v => v.type === "ssrf" && v.url === url);
347
+ if (existing)
348
+ return;
349
+ this.addVulnerability({
350
+ type: "ssrf",
351
+ severity: "high",
352
+ title: "Server-Side Request Forgery (SSRF)",
353
+ description: `The parameter '${param}' allows fetching arbitrary URLs, potentially accessing internal services.`,
354
+ url,
355
+ evidence: `Payload: ${payload}, Response contains internal service data`,
356
+ remediation: "Validate URLs against allowlists. Disable unused URL schemas. Restrict redirects.",
357
+ cwe: "CWE-918",
358
+ });
359
+ break;
360
+ }
361
+ }
362
+ }
363
+ detectOpenRedirect(url, param, payload, finalUrl) {
364
+ try {
365
+ const payloadUrl = new URL(payload);
366
+ const finalParsed = new URL(finalUrl);
367
+ if (payloadUrl.host &&
368
+ payloadUrl.host !== finalParsed.host &&
369
+ !payload.startsWith("/") &&
370
+ !payload.startsWith(".")) {
371
+ const existing = this.vulnerabilities.find(v => v.type === "redirect" && v.url === url);
372
+ if (existing)
373
+ return;
374
+ this.addVulnerability({
375
+ type: "redirect",
376
+ severity: "medium",
377
+ title: "Open Redirect",
378
+ description: `The parameter '${param}' redirects users to an external site.`,
379
+ url,
380
+ evidence: `Payload: ${payload}, Redirects to: ${finalUrl}`,
381
+ remediation: "Validate redirect URLs. Use allowlists for permitted destinations.",
382
+ cwe: "CWE-601",
383
+ });
384
+ }
385
+ }
386
+ catch {
387
+ if (payload.startsWith("http://") || payload.startsWith("https://")) {
388
+ const existing = this.vulnerabilities.find(v => v.type === "redirect" && v.url === url);
389
+ if (existing)
390
+ return;
391
+ this.addVulnerability({
392
+ type: "redirect",
393
+ severity: "medium",
394
+ title: "Open Redirect",
395
+ description: `The parameter '${param}' allows redirects to arbitrary external URLs.`,
396
+ url,
397
+ evidence: `Payload: ${payload}`,
398
+ remediation: "Validate redirect URLs against allowlists.",
399
+ cwe: "CWE-601",
400
+ });
401
+ }
402
+ }
403
+ }
404
+ detectInfoDisclosure(url, response) {
405
+ const infoPatterns = [
406
+ { regex: /(?:stack trace|StackTrace|exception|Error) in \//gi, name: "Stack Trace", severity: "low" },
407
+ { regex: /<\?php\s+\w+\(/gi, name: "PHP Code Exposure", severity: "medium" },
408
+ { regex: /\.git\/[^\s<>]+/gi, name: "Git Directory Exposed", severity: "medium" },
409
+ { regex: /\.env[^\s<>]*/gi, name: "Environment File Exposed", severity: "high" },
410
+ { regex: /\.gitignore[^\s<>]*/gi, name: "Gitignore Exposed", severity: "low" },
411
+ { regex: /\.DS_Store[^\s<>]*/gi, name: "DS_Store Exposed", severity: "low" },
412
+ { regex: /wp-config\.php/gi, name: "WordPress Config Exposed", severity: "high" },
413
+ { regex: /phpinfo\(\)/gi, name: "PHPInfo Exposure", severity: "medium" },
414
+ { regex: /debug[\s:=]*(true|1|on|yes)/gi, name: "Debug Mode Enabled", severity: "medium" },
415
+ { regex: /"version":\s*"[\d.]+"/gi, name: "Version Information", severity: "info" },
416
+ { regex: /Server:\s*\w+/gi, name: "Server Header", severity: "info" },
417
+ { regex: /X-Powered-By:[^\r\n]+/gi, name: "X-Powered-By Header", severity: "info" },
418
+ ];
419
+ for (const pattern of infoPatterns) {
420
+ const matches = response.match(pattern.regex);
421
+ if (matches && matches.length > 0) {
422
+ const existing = this.vulnerabilities.find(v => v.type === "info" && v.url === url && v.title === pattern.name);
423
+ if (existing)
424
+ continue;
425
+ this.addVulnerability({
426
+ type: "info",
427
+ severity: pattern.severity,
428
+ title: pattern.name,
429
+ description: `Sensitive information exposed: ${pattern.name}. This could aid attackers in further exploitation.`,
121
430
  url,
122
- evidence: `Pattern matched: ${matches[0].substring(0, 20)}...`,
123
- remediation: "Remove sensitive data from responses. Use environment variables and secure secret management.",
431
+ evidence: `Found: ${matches[0].substring(0, 50)}`,
432
+ remediation: "Disable debug mode. Remove exposed files. Configure server to hide sensitive headers.",
124
433
  cwe: "CWE-200",
125
434
  });
126
435
  }
@@ -145,6 +454,8 @@ class VulnerabilityDetector {
145
454
  }
146
455
  clear() {
147
456
  this.vulnerabilities = [];
457
+ this.reportedHeaders.clear();
458
+ this.reportedPaths.clear();
148
459
  }
149
460
  }
150
461
  exports.VulnerabilityDetector = VulnerabilityDetector;
@@ -0,0 +1 @@
1
+ export {};