kramscan 0.1.1 → 0.3.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 (91) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +419 -236
  3. package/dist/agent/confirmation.d.ts +5 -1
  4. package/dist/agent/confirmation.js +29 -9
  5. package/dist/agent/context.js +2 -3
  6. package/dist/agent/orchestrator.d.ts +2 -0
  7. package/dist/agent/orchestrator.js +50 -8
  8. package/dist/agent/prompts/system.d.ts +1 -1
  9. package/dist/agent/prompts/system.js +5 -7
  10. package/dist/agent/skills/health-check.js +22 -2
  11. package/dist/agent/skills/index.d.ts +1 -0
  12. package/dist/agent/skills/index.js +3 -1
  13. package/dist/agent/skills/verify-finding.d.ts +17 -0
  14. package/dist/agent/skills/verify-finding.js +91 -0
  15. package/dist/agent/skills/web-scan.js +46 -0
  16. package/dist/cli.js +156 -149
  17. package/dist/commands/agent.js +38 -38
  18. package/dist/commands/ai.d.ts +2 -0
  19. package/dist/commands/ai.js +112 -0
  20. package/dist/commands/analyze.js +103 -54
  21. package/dist/commands/config.js +55 -29
  22. package/dist/commands/dev.d.ts +2 -0
  23. package/dist/commands/dev.js +236 -0
  24. package/dist/commands/doctor.js +20 -15
  25. package/dist/commands/gate.d.ts +2 -0
  26. package/dist/commands/gate.js +109 -0
  27. package/dist/commands/onboard.js +188 -141
  28. package/dist/commands/report.js +68 -76
  29. package/dist/commands/scan.js +262 -81
  30. package/dist/commands/scans.d.ts +2 -0
  31. package/dist/commands/scans.js +55 -0
  32. package/dist/core/ai-client.d.ts +6 -1
  33. package/dist/core/ai-client.js +80 -12
  34. package/dist/core/ai-payloads.d.ts +17 -0
  35. package/dist/core/ai-payloads.js +54 -0
  36. package/dist/core/config-schema.d.ts +197 -0
  37. package/dist/core/config-schema.js +68 -0
  38. package/dist/core/config-schema.test.d.ts +1 -0
  39. package/dist/core/config-schema.test.js +151 -0
  40. package/dist/core/config.d.ts +8 -31
  41. package/dist/core/config.js +71 -14
  42. package/dist/core/diff-engine.d.ts +12 -0
  43. package/dist/core/diff-engine.js +47 -0
  44. package/dist/core/errors.d.ts +71 -0
  45. package/dist/core/errors.js +162 -0
  46. package/dist/core/scan-index.d.ts +20 -0
  47. package/dist/core/scan-index.js +52 -0
  48. package/dist/core/scan-storage.d.ts +11 -0
  49. package/dist/core/scan-storage.js +69 -0
  50. package/dist/core/scanner.d.ts +95 -13
  51. package/dist/core/scanner.js +342 -248
  52. package/dist/core/server-probe.d.ts +20 -0
  53. package/dist/core/server-probe.js +109 -0
  54. package/dist/core/vulnerability-detector.d.ts +9 -0
  55. package/dist/core/vulnerability-detector.js +46 -15
  56. package/dist/core/vulnerability-detector.test.d.ts +1 -0
  57. package/dist/core/vulnerability-detector.test.js +210 -0
  58. package/dist/index.js +3 -0
  59. package/dist/plugins/PluginManager.d.ts +27 -0
  60. package/dist/plugins/PluginManager.js +166 -0
  61. package/dist/plugins/index.d.ts +12 -0
  62. package/dist/plugins/index.js +29 -0
  63. package/dist/plugins/types.d.ts +55 -0
  64. package/dist/plugins/types.js +25 -0
  65. package/dist/plugins/vulnerabilities/CORSAnalyzerPlugin.d.ts +10 -0
  66. package/dist/plugins/vulnerabilities/CORSAnalyzerPlugin.js +67 -0
  67. package/dist/plugins/vulnerabilities/CSRFPlugin.d.ts +8 -0
  68. package/dist/plugins/vulnerabilities/CSRFPlugin.js +34 -0
  69. package/dist/plugins/vulnerabilities/CookieSecurityPlugin.d.ts +10 -0
  70. package/dist/plugins/vulnerabilities/CookieSecurityPlugin.js +91 -0
  71. package/dist/plugins/vulnerabilities/DebugEndpointPlugin.d.ts +15 -0
  72. package/dist/plugins/vulnerabilities/DebugEndpointPlugin.js +222 -0
  73. package/dist/plugins/vulnerabilities/DirectoryTraversalPlugin.d.ts +13 -0
  74. package/dist/plugins/vulnerabilities/DirectoryTraversalPlugin.js +110 -0
  75. package/dist/plugins/vulnerabilities/OpenRedirectPlugin.d.ts +10 -0
  76. package/dist/plugins/vulnerabilities/OpenRedirectPlugin.js +69 -0
  77. package/dist/plugins/vulnerabilities/SQLInjectionPlugin.d.ts +11 -0
  78. package/dist/plugins/vulnerabilities/SQLInjectionPlugin.js +109 -0
  79. package/dist/plugins/vulnerabilities/SecurityHeadersPlugin.d.ts +11 -0
  80. package/dist/plugins/vulnerabilities/SecurityHeadersPlugin.js +63 -0
  81. package/dist/plugins/vulnerabilities/SensitiveDataPlugin.d.ts +9 -0
  82. package/dist/plugins/vulnerabilities/SensitiveDataPlugin.js +32 -0
  83. package/dist/plugins/vulnerabilities/XSSPlugin.d.ts +15 -0
  84. package/dist/plugins/vulnerabilities/XSSPlugin.js +81 -0
  85. package/dist/reports/PdfGenerator.d.ts +36 -0
  86. package/dist/reports/PdfGenerator.js +404 -0
  87. package/dist/utils/logger.d.ts +33 -1
  88. package/dist/utils/logger.js +127 -8
  89. package/dist/utils/theme.d.ts +56 -0
  90. package/dist/utils/theme.js +201 -0
  91. package/package.json +6 -3
@@ -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,12 @@
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";
8
+ export { CORSAnalyzerPlugin } from "./vulnerabilities/CORSAnalyzerPlugin";
9
+ export { DebugEndpointPlugin } from "./vulnerabilities/DebugEndpointPlugin";
10
+ export { DirectoryTraversalPlugin } from "./vulnerabilities/DirectoryTraversalPlugin";
11
+ export { CookieSecurityPlugin } from "./vulnerabilities/CookieSecurityPlugin";
12
+ export { OpenRedirectPlugin } from "./vulnerabilities/OpenRedirectPlugin";
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OpenRedirectPlugin = exports.CookieSecurityPlugin = exports.DirectoryTraversalPlugin = exports.DebugEndpointPlugin = exports.CORSAnalyzerPlugin = 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; } });
20
+ var CORSAnalyzerPlugin_1 = require("./vulnerabilities/CORSAnalyzerPlugin");
21
+ Object.defineProperty(exports, "CORSAnalyzerPlugin", { enumerable: true, get: function () { return CORSAnalyzerPlugin_1.CORSAnalyzerPlugin; } });
22
+ var DebugEndpointPlugin_1 = require("./vulnerabilities/DebugEndpointPlugin");
23
+ Object.defineProperty(exports, "DebugEndpointPlugin", { enumerable: true, get: function () { return DebugEndpointPlugin_1.DebugEndpointPlugin; } });
24
+ var DirectoryTraversalPlugin_1 = require("./vulnerabilities/DirectoryTraversalPlugin");
25
+ Object.defineProperty(exports, "DirectoryTraversalPlugin", { enumerable: true, get: function () { return DirectoryTraversalPlugin_1.DirectoryTraversalPlugin; } });
26
+ var CookieSecurityPlugin_1 = require("./vulnerabilities/CookieSecurityPlugin");
27
+ Object.defineProperty(exports, "CookieSecurityPlugin", { enumerable: true, get: function () { return CookieSecurityPlugin_1.CookieSecurityPlugin; } });
28
+ var OpenRedirectPlugin_1 = require("./vulnerabilities/OpenRedirectPlugin");
29
+ Object.defineProperty(exports, "OpenRedirectPlugin", { enumerable: true, get: function () { return OpenRedirectPlugin_1.OpenRedirectPlugin; } });
@@ -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
+ }
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BaseVulnerabilityPlugin = void 0;
4
+ class BaseVulnerabilityPlugin {
5
+ enabled = true;
6
+ createVulnerability(title, description, url, severity, evidence, remediation, cwe) {
7
+ return {
8
+ type: this.type,
9
+ severity,
10
+ title,
11
+ description,
12
+ url,
13
+ evidence,
14
+ remediation,
15
+ cwe,
16
+ };
17
+ }
18
+ success(vulnerability) {
19
+ return { found: true, vulnerability };
20
+ }
21
+ failure(error) {
22
+ return { found: false, error };
23
+ }
24
+ }
25
+ exports.BaseVulnerabilityPlugin = BaseVulnerabilityPlugin;
@@ -0,0 +1,10 @@
1
+ import { BaseVulnerabilityPlugin, PluginContext } from "../types";
2
+ import { Vulnerability } from "../../core/vulnerability-detector";
3
+ export declare class CORSAnalyzerPlugin extends BaseVulnerabilityPlugin {
4
+ readonly name = "CORS Analyzer";
5
+ readonly type: "header";
6
+ readonly description = "Detects overly permissive Cross-Origin Resource Sharing configurations";
7
+ private readonly reportedHosts;
8
+ analyzeHeaders(context: PluginContext, headers: Record<string, string>): Promise<Vulnerability[]>;
9
+ reset(): void;
10
+ }
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CORSAnalyzerPlugin = void 0;
4
+ const types_1 = require("../types");
5
+ class CORSAnalyzerPlugin extends types_1.BaseVulnerabilityPlugin {
6
+ name = "CORS Analyzer";
7
+ type = "header";
8
+ description = "Detects overly permissive Cross-Origin Resource Sharing configurations";
9
+ reportedHosts = new Set();
10
+ async analyzeHeaders(context, headers) {
11
+ const host = new URL(context.url).host;
12
+ // Only report once per host
13
+ if (this.reportedHosts.has(host)) {
14
+ return [];
15
+ }
16
+ const vulnerabilities = [];
17
+ const acao = headers["access-control-allow-origin"];
18
+ const acac = headers["access-control-allow-credentials"];
19
+ const acam = headers["access-control-allow-methods"];
20
+ const acah = headers["access-control-allow-headers"];
21
+ // Check for wildcard origin
22
+ if (acao === "*") {
23
+ vulnerabilities.push(this.createVulnerability("CORS: Wildcard Origin Allowed", `The server at ${host} allows requests from any origin (Access-Control-Allow-Origin: *). ` +
24
+ `This can expose sensitive data to malicious third-party websites.`, context.url, "medium", `Access-Control-Allow-Origin: *`, "Restrict Access-Control-Allow-Origin to trusted domains only. " +
25
+ "Use a whitelist of allowed origins instead of the wildcard *.", "CWE-942"));
26
+ }
27
+ // Check for wildcard with credentials (very dangerous)
28
+ if (acao === "*" && acac?.toLowerCase() === "true") {
29
+ vulnerabilities.push(this.createVulnerability("CORS: Wildcard Origin with Credentials", `The server at ${host} allows any origin AND sends credentials. ` +
30
+ `This is a critical misconfiguration that can lead to complete session hijacking.`, context.url, "critical", `Access-Control-Allow-Origin: * with Access-Control-Allow-Credentials: true`, "Never combine wildcard origin with credentials. " +
31
+ "Validate the Origin header against a strict whitelist and reflect only trusted origins.", "CWE-942"));
32
+ }
33
+ // Check if origin is reflected without validation (test with a probe)
34
+ if (acao && acao !== "*" && acao !== "null") {
35
+ // If the ACAO reflects back what looks like an origin, it might be reflecting without validation
36
+ const isLikelyReflecting = acao.includes("://") && !acao.includes(host);
37
+ if (isLikelyReflecting && acac?.toLowerCase() === "true") {
38
+ vulnerabilities.push(this.createVulnerability("CORS: Origin Reflection with Credentials", `The server at ${host} appears to reflect the Origin header value while also allowing credentials. ` +
39
+ `An attacker can make authenticated requests from any origin.`, context.url, "high", `Access-Control-Allow-Origin: ${acao}, Access-Control-Allow-Credentials: true`, "Validate the Origin header against a strict whitelist of trusted domains. " +
40
+ "Never blindly reflect the Origin header.", "CWE-942"));
41
+ }
42
+ }
43
+ // Check for null origin allowed (can be exploited via sandboxed iframes)
44
+ if (acao === "null") {
45
+ vulnerabilities.push(this.createVulnerability("CORS: Null Origin Allowed", `The server at ${host} accepts the 'null' origin. ` +
46
+ `Attackers can exploit this using sandboxed iframes or data URIs.`, context.url, "medium", `Access-Control-Allow-Origin: null`, "Do not allow the 'null' origin. Sandboxed iframes and redirects can send Origin: null.", "CWE-942"));
47
+ }
48
+ // Check for dangerous methods
49
+ if (acam) {
50
+ const dangerousMethods = ["PUT", "DELETE", "PATCH"];
51
+ const allowedMethods = acam.toUpperCase().split(",").map(m => m.trim());
52
+ const exposed = dangerousMethods.filter(m => allowedMethods.includes(m));
53
+ if (exposed.length > 0 && acao === "*") {
54
+ vulnerabilities.push(this.createVulnerability("CORS: Dangerous Methods with Wildcard Origin", `The server at ${host} allows ${exposed.join(", ")} methods from any origin. ` +
55
+ `This could allow unauthorized data modification from third-party sites.`, context.url, "high", `Access-Control-Allow-Methods: ${acam}; Access-Control-Allow-Origin: *`, "Restrict allowed methods to those actually needed, and never combine with wildcard origin.", "CWE-942"));
56
+ }
57
+ }
58
+ if (vulnerabilities.length > 0) {
59
+ this.reportedHosts.add(host);
60
+ }
61
+ return vulnerabilities;
62
+ }
63
+ reset() {
64
+ this.reportedHosts.clear();
65
+ }
66
+ }
67
+ exports.CORSAnalyzerPlugin = CORSAnalyzerPlugin;
@@ -0,0 +1,8 @@
1
+ import { BaseVulnerabilityPlugin, PluginContext } from "../types";
2
+ export declare class CSRFPlugin extends BaseVulnerabilityPlugin {
3
+ readonly name = "CSRF Detector";
4
+ readonly type: "csrf";
5
+ readonly description = "Detects missing CSRF protection in forms";
6
+ private readonly csrfTokenPatterns;
7
+ analyzeContent(context: PluginContext, content: string): Promise<import("../../core/vulnerability-detector").Vulnerability[]>;
8
+ }
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CSRFPlugin = void 0;
4
+ const types_1 = require("../types");
5
+ class CSRFPlugin extends types_1.BaseVulnerabilityPlugin {
6
+ name = "CSRF Detector";
7
+ type = "csrf";
8
+ description = "Detects missing CSRF protection in forms";
9
+ csrfTokenPatterns = [
10
+ 'name="csrf',
11
+ 'name="_token',
12
+ 'name="authenticity_token',
13
+ 'name="_csrf',
14
+ ];
15
+ async analyzeContent(context, content) {
16
+ // Look for forms in the content
17
+ const formRegex = /<form[^>]*>([\s\S]*?)<\/form>/gi;
18
+ const forms = content.match(formRegex);
19
+ if (!forms)
20
+ return [];
21
+ const vulnerabilities = [];
22
+ for (const form of forms) {
23
+ const hasCSRFToken = this.csrfTokenPatterns.some(pattern => form.toLowerCase().includes(pattern.toLowerCase()));
24
+ if (!hasCSRFToken) {
25
+ // Extract form action for better reporting
26
+ const actionMatch = form.match(/action=["']([^"']*)["']/i);
27
+ const action = actionMatch ? actionMatch[1] : context.url;
28
+ vulnerabilities.push(this.createVulnerability("Missing CSRF Protection", "Form lacks CSRF tokens. Attackers can forge requests to perform unauthorized actions.", new URL(action, context.url).toString(), "medium", "Form HTML does not contain CSRF token", "Implement anti-CSRF tokens. Use SameSite cookies.", "CWE-352"));
29
+ }
30
+ }
31
+ return vulnerabilities;
32
+ }
33
+ }
34
+ exports.CSRFPlugin = CSRFPlugin;
@@ -0,0 +1,10 @@
1
+ import { BaseVulnerabilityPlugin, PluginContext } from "../types";
2
+ import { Vulnerability } from "../../core/vulnerability-detector";
3
+ export declare class CookieSecurityPlugin extends BaseVulnerabilityPlugin {
4
+ readonly name = "Cookie Security Auditor";
5
+ readonly type: "header";
6
+ readonly description = "Audits cookies for missing security flags (HttpOnly, Secure, SameSite)";
7
+ private readonly reportedCookies;
8
+ analyzeHeaders(context: PluginContext, headers: Record<string, string>): Promise<Vulnerability[]>;
9
+ reset(): void;
10
+ }
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CookieSecurityPlugin = void 0;
4
+ const types_1 = require("../types");
5
+ class CookieSecurityPlugin extends types_1.BaseVulnerabilityPlugin {
6
+ name = "Cookie Security Auditor";
7
+ type = "header";
8
+ description = "Audits cookies for missing security flags (HttpOnly, Secure, SameSite)";
9
+ reportedCookies = new Set();
10
+ async analyzeHeaders(context, headers) {
11
+ const vulnerabilities = [];
12
+ const host = new URL(context.url).host;
13
+ // Collect all set-cookie headers
14
+ const setCookieHeader = headers["set-cookie"];
15
+ if (!setCookieHeader)
16
+ return [];
17
+ // set-cookie headers might be combined with newlines in some scenarios
18
+ const cookies = setCookieHeader.split(/,(?=[^;]*=)/g).map(c => c.trim());
19
+ for (const cookie of cookies) {
20
+ const cookieName = cookie.split("=")[0]?.trim();
21
+ if (!cookieName)
22
+ continue;
23
+ const cookieKey = `${host}:${cookieName}`;
24
+ if (this.reportedCookies.has(cookieKey))
25
+ continue;
26
+ const cookieLower = cookie.toLowerCase();
27
+ const issues = [];
28
+ // Check HttpOnly flag
29
+ if (!cookieLower.includes("httponly")) {
30
+ issues.push("Missing HttpOnly flag (vulnerable to XSS cookie theft)");
31
+ }
32
+ // Check Secure flag
33
+ if (!cookieLower.includes("secure")) {
34
+ issues.push("Missing Secure flag (cookie sent over HTTP)");
35
+ }
36
+ // Check SameSite attribute
37
+ if (!cookieLower.includes("samesite")) {
38
+ issues.push("Missing SameSite attribute (vulnerable to CSRF)");
39
+ }
40
+ else if (cookieLower.includes("samesite=none")) {
41
+ if (!cookieLower.includes("secure")) {
42
+ issues.push("SameSite=None without Secure flag (browser will reject)");
43
+ }
44
+ issues.push("SameSite=None allows cross-site requests (verify this is intentional)");
45
+ }
46
+ // Check for session-like cookies with missing flags
47
+ const isSessionCookie = /^(sess|session|sid|token|auth|jwt|csrf|xsrf|connect\.sid|phpsessid|jsessionid|asp\.net_sessionid)/i.test(cookieName);
48
+ if (issues.length > 0) {
49
+ const severity = isSessionCookie
50
+ ? (issues.some(i => i.includes("HttpOnly")) ? "high" : "medium")
51
+ : "low";
52
+ this.reportedCookies.add(cookieKey);
53
+ vulnerabilities.push(this.createVulnerability(`Insecure Cookie: ${cookieName}`, `The cookie '${cookieName}' on ${host} has security issues:\n` +
54
+ issues.map(i => ` • ${i}`).join("\n"), context.url, severity, `Set-Cookie: ${cookie.substring(0, 200)}`, "Set all cookies with: HttpOnly (prevents JS access), " +
55
+ "Secure (HTTPS only), SameSite=Lax or Strict (CSRF protection). " +
56
+ "Example: Set-Cookie: session=abc; HttpOnly; Secure; SameSite=Lax; Path=/", "CWE-614"));
57
+ }
58
+ // Check for overly broad domain
59
+ const domainMatch = cookie.match(/domain=([^;]+)/i);
60
+ if (domainMatch) {
61
+ const domain = domainMatch[1].trim();
62
+ if (domain.startsWith(".") && domain.split(".").length <= 2) {
63
+ this.reportedCookies.add(cookieKey + ":domain");
64
+ vulnerabilities.push(this.createVulnerability(`Cookie Domain Too Broad: ${cookieName}`, `The cookie '${cookieName}' has domain set to '${domain}', which allows ` +
65
+ `any subdomain to read this cookie. This increases the attack surface.`, context.url, "low", `Domain=${domain}`, "Set the cookie domain to the most specific subdomain possible.", "CWE-1275"));
66
+ }
67
+ }
68
+ // Check for missing expiry on session cookies (persistent session)
69
+ if (isSessionCookie && !cookieLower.includes("expires") && !cookieLower.includes("max-age")) {
70
+ // This is actually good practice (session cookie dies with browser close)
71
+ // But if there's _no_ expiry and it's NOT a session cookie, flag it
72
+ }
73
+ else if (isSessionCookie && cookieLower.includes("max-age")) {
74
+ const maxAgeMatch = cookie.match(/max-age=(\d+)/i);
75
+ if (maxAgeMatch) {
76
+ const maxAge = parseInt(maxAgeMatch[1], 10);
77
+ const thirtyDays = 30 * 24 * 60 * 60;
78
+ if (maxAge > thirtyDays) {
79
+ vulnerabilities.push(this.createVulnerability(`Long-Lived Session Cookie: ${cookieName}`, `The session cookie '${cookieName}' has a very long lifetime (${Math.round(maxAge / 86400)} days). ` +
80
+ `Long-lived session tokens increase the window for token theft.`, context.url, "low", `Max-Age=${maxAge} (${Math.round(maxAge / 86400)} days)`, "Set session cookie lifetime to the minimum needed (e.g., 24 hours for most apps).", "CWE-613"));
81
+ }
82
+ }
83
+ }
84
+ }
85
+ return vulnerabilities;
86
+ }
87
+ reset() {
88
+ this.reportedCookies.clear();
89
+ }
90
+ }
91
+ exports.CookieSecurityPlugin = CookieSecurityPlugin;
@@ -0,0 +1,15 @@
1
+ import { BaseVulnerabilityPlugin, PluginContext } from "../types";
2
+ import { Vulnerability } from "../../core/vulnerability-detector";
3
+ export declare class DebugEndpointPlugin extends BaseVulnerabilityPlugin {
4
+ readonly name = "Debug Endpoint Detector";
5
+ readonly type: "info";
6
+ readonly description = "Probes for common debug, admin, and development endpoints left exposed";
7
+ private readonly reportedPaths;
8
+ /**
9
+ * Common debug/dev endpoints that developers forget to disable before deployment.
10
+ * Each entry has a path, a human-readable name, and expected severity.
11
+ */
12
+ private readonly debugEndpoints;
13
+ analyzeContent(context: PluginContext, content: string): Promise<Vulnerability[]>;
14
+ reset(): void;
15
+ }