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
@@ -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,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,11 @@
1
+ import { BaseVulnerabilityPlugin, PluginContext } from "../types";
2
+ export declare class SQLInjectionPlugin extends BaseVulnerabilityPlugin {
3
+ readonly name = "SQL Injection Detector";
4
+ readonly type: "sqli";
5
+ readonly description = "Detects SQL Injection vulnerabilities";
6
+ private readonly errorBasedPayloads;
7
+ private readonly timeBasedPayloads;
8
+ private getErrorPayloads;
9
+ private readonly sqlErrors;
10
+ testParameter(context: PluginContext, param: string, _value: string): Promise<import("../types").VulnerabilityTestResult>;
11
+ }
@@ -0,0 +1,109 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SQLInjectionPlugin = void 0;
4
+ const types_1 = require("../types");
5
+ class SQLInjectionPlugin extends types_1.BaseVulnerabilityPlugin {
6
+ name = "SQL Injection Detector";
7
+ type = "sqli";
8
+ description = "Detects SQL Injection vulnerabilities";
9
+ errorBasedPayloads = [
10
+ "'",
11
+ "1' OR '1'='1",
12
+ "1; DROP TABLE users--",
13
+ "' OR 1=1--",
14
+ "' UNION SELECT 1--",
15
+ "1' AND '1'='1",
16
+ ];
17
+ timeBasedPayloads = [
18
+ "' AND SLEEP(5)--",
19
+ "1' AND SLEEP(5)--",
20
+ "'; WAITFOR DELAY '00:00:05'--",
21
+ ];
22
+ async getErrorPayloads(context, param) {
23
+ if (context.payloadGenerator) {
24
+ const aiPayloads = await context.payloadGenerator.generatePayloads("sqli", {
25
+ parameterName: param,
26
+ url: context.url,
27
+ });
28
+ if (aiPayloads.length > 0) {
29
+ return [...aiPayloads, ...this.errorBasedPayloads];
30
+ }
31
+ }
32
+ return this.errorBasedPayloads;
33
+ }
34
+ sqlErrors = [
35
+ "SQL syntax",
36
+ "mysql_fetch",
37
+ "ORA-",
38
+ "PostgreSQL",
39
+ "SQLite",
40
+ "ODBC",
41
+ "JET Database",
42
+ "Microsoft Access Driver",
43
+ "unterminated",
44
+ "mysql_num_rows",
45
+ "mysql_query",
46
+ "Microsoft SQL Native Client error",
47
+ "SQLServer JDBC Driver",
48
+ "ORA-00933",
49
+ "PG::SyntaxError",
50
+ "Warning: pg_",
51
+ "Syntax error",
52
+ ];
53
+ async testParameter(context, param, _value) {
54
+ // Test for error-based SQL injection
55
+ const errorPayloads = await this.getErrorPayloads(context, param);
56
+ for (const payload of errorPayloads) {
57
+ try {
58
+ const url = new URL(context.url);
59
+ url.searchParams.set(param, payload);
60
+ await context.page.goto(url.toString(), {
61
+ waitUntil: "networkidle2",
62
+ timeout: context.timeout
63
+ });
64
+ const content = await context.page.content();
65
+ for (const error of this.sqlErrors) {
66
+ if (content.includes(error)) {
67
+ return this.success(this.createVulnerability("SQL Injection", `The parameter '${param}' is vulnerable to SQL injection. Database error messages were detected.`, context.url, "critical", `Error: ${error}`, "Use parameterized queries (prepared statements). Never concatenate user input into SQL.", "CWE-89"));
68
+ }
69
+ }
70
+ }
71
+ catch (error) {
72
+ return this.failure(error.message);
73
+ }
74
+ }
75
+ // Test for time-based blind SQL injection
76
+ let baselineTime = 0;
77
+ try {
78
+ const baselineStart = Date.now();
79
+ await context.page.goto(context.url, {
80
+ waitUntil: "networkidle2",
81
+ timeout: context.timeout
82
+ });
83
+ baselineTime = Date.now() - baselineStart;
84
+ }
85
+ catch (error) {
86
+ return this.failure(error.message);
87
+ }
88
+ for (const payload of this.timeBasedPayloads) {
89
+ try {
90
+ const url = new URL(context.url);
91
+ url.searchParams.set(param, payload);
92
+ const startTime = Date.now();
93
+ await context.page.goto(url.toString(), {
94
+ waitUntil: "networkidle2",
95
+ timeout: context.timeout
96
+ });
97
+ const testTime = Date.now() - startTime;
98
+ if (testTime > baselineTime + 3000) {
99
+ return this.success(this.createVulnerability("Blind SQL Injection", `Time-based blind SQL injection detected on parameter '${param}'. Response time indicates successful payload execution.`, context.url, "high", `Response time increased by ${testTime - baselineTime}ms with sleep payload`, "Use parameterized queries. Implement input validation and proper error handling.", "CWE-89"));
100
+ }
101
+ }
102
+ catch (error) {
103
+ return this.failure(error.message);
104
+ }
105
+ }
106
+ return this.failure();
107
+ }
108
+ }
109
+ exports.SQLInjectionPlugin = SQLInjectionPlugin;
@@ -0,0 +1,11 @@
1
+ import { BaseVulnerabilityPlugin, PluginContext } from "../types";
2
+ import { Vulnerability } from "../../core/vulnerability-detector";
3
+ export declare class SecurityHeadersPlugin extends BaseVulnerabilityPlugin {
4
+ readonly name = "Security Headers Analyzer";
5
+ readonly type: "header";
6
+ readonly description = "Analyzes HTTP security headers";
7
+ private readonly reportedHosts;
8
+ private readonly requiredHeaders;
9
+ analyzeHeaders(context: PluginContext, headers: Record<string, string>): Promise<Vulnerability[]>;
10
+ reset(): void;
11
+ }
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SecurityHeadersPlugin = void 0;
4
+ const types_1 = require("../types");
5
+ class SecurityHeadersPlugin extends types_1.BaseVulnerabilityPlugin {
6
+ name = "Security Headers Analyzer";
7
+ type = "header";
8
+ description = "Analyzes HTTP security headers";
9
+ reportedHosts = new Set();
10
+ requiredHeaders = {
11
+ "content-security-policy": {
12
+ title: "Missing Content-Security-Policy",
13
+ severity: "low",
14
+ remediation: "Implement a strict CSP to prevent XSS and data injection attacks.",
15
+ },
16
+ "x-frame-options": {
17
+ title: "Missing X-Frame-Options",
18
+ severity: "low",
19
+ remediation: "Set X-Frame-Options to DENY or SAMEORIGIN to prevent clickjacking.",
20
+ },
21
+ "strict-transport-security": {
22
+ title: "Missing Strict-Transport-Security (HSTS)",
23
+ severity: "low",
24
+ remediation: "Enable HSTS with max-age of at least 31536000 seconds.",
25
+ },
26
+ "x-content-type-options": {
27
+ title: "Missing X-Content-Type-Options",
28
+ severity: "info",
29
+ remediation: "Set X-Content-Type-Options to 'nosniff'.",
30
+ },
31
+ "referrer-policy": {
32
+ title: "Missing Referrer-Policy",
33
+ severity: "info",
34
+ remediation: "Set Referrer-Policy to 'strict-origin-when-cross-origin'.",
35
+ },
36
+ "permissions-policy": {
37
+ title: "Missing Permissions-Policy",
38
+ severity: "info",
39
+ remediation: "Restrict browser features using Permissions-Policy header.",
40
+ },
41
+ };
42
+ async analyzeHeaders(context, headers) {
43
+ const host = new URL(context.url).host;
44
+ // Only report once per host
45
+ if (this.reportedHosts.has(host)) {
46
+ return [];
47
+ }
48
+ const vulnerabilities = [];
49
+ for (const [header, config] of Object.entries(this.requiredHeaders)) {
50
+ if (!headers[header.toLowerCase()]) {
51
+ vulnerabilities.push(this.createVulnerability(config.title, `The ${header} security header is not set on ${host}.`, context.url, config.severity, undefined, config.remediation));
52
+ }
53
+ }
54
+ if (vulnerabilities.length > 0) {
55
+ this.reportedHosts.add(host);
56
+ }
57
+ return vulnerabilities;
58
+ }
59
+ reset() {
60
+ this.reportedHosts.clear();
61
+ }
62
+ }
63
+ exports.SecurityHeadersPlugin = SecurityHeadersPlugin;
@@ -0,0 +1,9 @@
1
+ import { BaseVulnerabilityPlugin, PluginContext } from "../types";
2
+ import { Vulnerability } from "../../core/vulnerability-detector";
3
+ export declare class SensitiveDataPlugin extends BaseVulnerabilityPlugin {
4
+ readonly name = "Sensitive Data Detector";
5
+ readonly type: "sensitive_data";
6
+ readonly description = "Detects exposed sensitive data in responses";
7
+ private readonly patterns;
8
+ analyzeContent(context: PluginContext, content: string): Promise<Vulnerability[]>;
9
+ }
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SensitiveDataPlugin = void 0;
4
+ const types_1 = require("../types");
5
+ class SensitiveDataPlugin extends types_1.BaseVulnerabilityPlugin {
6
+ name = "Sensitive Data Detector";
7
+ type = "sensitive_data";
8
+ description = "Detects exposed sensitive data in responses";
9
+ patterns = [
10
+ { regex: /sk-[a-zA-Z0-9]{48}/g, name: "OpenAI API Key", severity: "critical" },
11
+ { regex: /ghp_[a-zA-Z0-9]{36}/g, name: "GitHub Token", severity: "critical" },
12
+ { regex: /AKIA[0-9A-Z]{16}/g, name: "AWS Access Key", severity: "critical" },
13
+ { regex: /xox[baprs]-[0-9a-zA-Z]{10,}/g, name: "Slack Token", severity: "high" },
14
+ { regex: /eyJ[a-zA-Z0-9_-]*\.eyJ[a-zA-Z0-9_-]*/g, name: "JWT Token", severity: "high" },
15
+ { regex: /AIza[0-9A-Za-z_-]{35}/g, name: "Google API Key", severity: "high" },
16
+ { regex: /password["\s:=]+[^\s"]{6,}/gi, name: "Hardcoded Password", severity: "high" },
17
+ { regex: /api[_-]?key["\s:=]+[\w-]{20,}/gi, name: "Generic API Key", severity: "medium" },
18
+ { regex: /-----BEGIN (RSA |EC )?PRIVATE KEY-----/g, name: "Private Key", severity: "critical" },
19
+ { regex: /database[_-]?url["\s:=]+.*(?:mysql|postgres|mongodb):\/\//gi, name: "Database Connection String", severity: "high" },
20
+ ];
21
+ async analyzeContent(context, content) {
22
+ const vulnerabilities = [];
23
+ for (const pattern of this.patterns) {
24
+ const matches = content.match(pattern.regex);
25
+ if (matches && matches.length > 0) {
26
+ vulnerabilities.push(this.createVulnerability(`Exposed ${pattern.name}`, `Sensitive ${pattern.name} found in response. This could lead to account compromise or data breach.`, context.url, pattern.severity, `Found: ${matches[0].substring(0, 30)}...`, "Remove sensitive data from client-side code. Use environment variables and secure secret management.", "CWE-200"));
27
+ }
28
+ }
29
+ return vulnerabilities;
30
+ }
31
+ }
32
+ exports.SensitiveDataPlugin = SensitiveDataPlugin;
@@ -0,0 +1,15 @@
1
+ import { BaseVulnerabilityPlugin, PluginContext } from "../types";
2
+ export declare class XSSPlugin extends BaseVulnerabilityPlugin {
3
+ readonly name = "XSS Detector";
4
+ readonly type: "xss";
5
+ readonly description = "Detects Cross-Site Scripting vulnerabilities";
6
+ private readonly payloads;
7
+ private getPayloads;
8
+ testParameter(context: PluginContext, param: string, _value: string): Promise<import("../types").VulnerabilityTestResult>;
9
+ testFormInput(context: PluginContext, formData: {
10
+ inputs: Array<{
11
+ name: string;
12
+ type: string;
13
+ }>;
14
+ }): Promise<import("../types").VulnerabilityTestResult>;
15
+ }
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.XSSPlugin = void 0;
4
+ const types_1 = require("../types");
5
+ class XSSPlugin extends types_1.BaseVulnerabilityPlugin {
6
+ name = "XSS Detector";
7
+ type = "xss";
8
+ description = "Detects Cross-Site Scripting vulnerabilities";
9
+ payloads = [
10
+ "<script>alert('XSS')</script>",
11
+ '"><script>alert(1)</script>',
12
+ "<img src=x onerror=alert(1)>",
13
+ "'-alert(1)-'",
14
+ "<svg/onload=alert(1)>",
15
+ ];
16
+ async getPayloads(context, param) {
17
+ if (context.payloadGenerator) {
18
+ const aiPayloads = await context.payloadGenerator.generatePayloads("xss", {
19
+ parameterName: param,
20
+ url: context.url,
21
+ // We could extract more context from the page here if needed
22
+ });
23
+ if (aiPayloads.length > 0) {
24
+ return [...aiPayloads, ...this.payloads];
25
+ }
26
+ }
27
+ return this.payloads;
28
+ }
29
+ async testParameter(context, param, _value) {
30
+ const payloads = await this.getPayloads(context, param);
31
+ for (const payload of payloads) {
32
+ try {
33
+ const url = new URL(context.url);
34
+ url.searchParams.set(param, payload);
35
+ await context.page.goto(url.toString(), {
36
+ waitUntil: "networkidle2",
37
+ timeout: context.timeout
38
+ });
39
+ const content = await context.page.content();
40
+ if (content.includes(payload)) {
41
+ return this.success(this.createVulnerability("Reflected Cross-Site Scripting (XSS)", `The parameter '${param}' reflects user input without proper encoding, allowing script injection.`, context.url, "high", `Payload: ${payload}`, "Implement input validation, output encoding, and Content Security Policy (CSP) headers.", "CWE-79"));
42
+ }
43
+ }
44
+ catch (error) {
45
+ return this.failure(error.message);
46
+ }
47
+ }
48
+ return this.failure();
49
+ }
50
+ async testFormInput(context, formData) {
51
+ for (const input of formData.inputs) {
52
+ if (input.type === "hidden" || input.type === "submit")
53
+ continue;
54
+ const payloads = await this.getPayloads(context, input.name);
55
+ for (const payload of payloads) {
56
+ try {
57
+ await context.page.goto(context.url, {
58
+ waitUntil: "networkidle2",
59
+ timeout: context.timeout
60
+ });
61
+ const inputSelector = `input[name="${input.name}"], textarea[name="${input.name}"]`;
62
+ await context.page.type(inputSelector, payload);
63
+ const submitButton = await context.page.$("input[type=submit], button[type=submit]");
64
+ if (submitButton) {
65
+ await submitButton.click();
66
+ await context.page.waitForNavigation({ timeout: context.timeout }).catch(() => { });
67
+ }
68
+ const content = await context.page.content();
69
+ if (content.includes(payload)) {
70
+ return this.success(this.createVulnerability("Reflected Cross-Site Scripting (XSS)", `The form input '${input.name}' reflects user input without proper encoding.`, context.url, "high", `Payload: ${payload}`, "Implement input validation, output encoding, and Content Security Policy (CSP) headers.", "CWE-79"));
71
+ }
72
+ }
73
+ catch (error) {
74
+ return this.failure(error.message);
75
+ }
76
+ }
77
+ }
78
+ return this.failure();
79
+ }
80
+ }
81
+ exports.XSSPlugin = XSSPlugin;
@@ -0,0 +1,36 @@
1
+ import { ScanResult } from "../core/vulnerability-detector";
2
+ import type { ScanError } from "../core/scanner";
3
+ export interface PdfGenerationOptions {
4
+ filename?: string;
5
+ format?: "A4" | "Letter" | "Legal";
6
+ margin?: {
7
+ top: string;
8
+ bottom: string;
9
+ left: string;
10
+ right: string;
11
+ };
12
+ }
13
+ export interface PdfReportData {
14
+ scanResult: ScanResult;
15
+ scanErrors?: ScanError[];
16
+ pluginErrors?: Map<string, Array<{
17
+ url: string;
18
+ error: string;
19
+ }>>;
20
+ }
21
+ export interface HtmlReportOptions {
22
+ filename?: string;
23
+ includeStyles?: boolean;
24
+ minify?: boolean;
25
+ }
26
+ export declare class PdfGenerator {
27
+ generate(data: PdfReportData, options?: PdfGenerationOptions): Promise<string>;
28
+ /**
29
+ * Generate a standalone HTML report
30
+ * @param data - The scan result data
31
+ * @param options - Options for HTML generation
32
+ * @returns Path to the generated HTML file
33
+ */
34
+ generateHtml(data: PdfReportData, options?: HtmlReportOptions): Promise<string>;
35
+ }
36
+ export declare const pdfGenerator: PdfGenerator;