vulcn 0.3.0 → 0.3.2

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,70 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 51d69b7: ### Auto-Crawl: Automated Form Discovery & Session Generation
8
+
9
+ Adds a new **auto-crawl** capability to the browser driver — automatically discovers injectable forms, inputs, and submit buttons on a target URL, then generates ready-to-run `Session[]` objects. This replaces the need to manually record sessions for basic form testing.
10
+
11
+ #### `@vulcn/engine`
12
+ - **`CrawlOptions` type** — new interface for crawl configuration (`maxDepth`, `maxPages`, `pageTimeout`, `sameOrigin`, `onPageCrawled` callback)
13
+ - **`RecorderDriver.crawl()`** — optional method on the recorder interface, so only drivers that support auto-discovery need to implement it
14
+ - **`DriverManager.crawl()`** — new top-level method that dispatches to the driver's crawl implementation, with clear errors when a driver doesn't support it
15
+ - **Test coverage** — 4 new tests for the crawl flow (success, arg passthrough, missing driver, unsupported driver), coverage at 62.88%
16
+
17
+ #### `@vulcn/driver-browser`
18
+ - **`BrowserCrawler`** — new module (`crawler.ts`) that performs BFS-based crawling using Playwright:
19
+ - Discovers explicit `<form>` elements with their inputs and submit buttons
20
+ - Discovers standalone inputs not inside a `<form>` (common in SPAs)
21
+ - Identifies injectable text-like input types (text, search, url, email, tel, password, textarea)
22
+ - Finds submit triggers (submit buttons, untyped buttons, or falls back to Enter keypress)
23
+ - Follows same-origin links with configurable depth control
24
+ - Generates proper `navigate → input → submit` step sequences per form
25
+ - **`recorder.crawl()`** — wired into the browser driver's recorder interface
26
+ - **Exported** — `crawlAndBuildSessions` available for direct programmatic use
27
+
28
+ #### Architecture
29
+ - Removed standalone `@vulcn/crawler` package — crawler is now a core part of `@vulcn/driver-browser`, consistent with the driver-based architecture
30
+ - Cleaned up `pnpm-workspace.yaml` to remove the deleted crawler entry
31
+
32
+ ## 0.3.1
33
+
34
+ ### Patch Changes
35
+
36
+ - c62a3dc: ### `@vulcn/plugin-report` — New Package
37
+
38
+ Introducing the **Report Generation Plugin** — generate professional security reports at the end of every `vulcn run`.
39
+ - **HTML**: Modern dark-themed dashboard with risk gauge, severity breakdown bars, expandable finding cards, Vulcn branding, Inter + JetBrains Mono typography, and print-friendly CSS
40
+ - **JSON**: Machine-readable structured output for CI/CD pipelines — includes severity counts, risk score, vuln types, affected URLs
41
+ - **YAML**: Human-readable YAML with descriptive header comment — same data model as JSON
42
+ - Uses the `onRunEnd` plugin hook to intercept results after execution completes
43
+ - Exports `generateHtml`, `generateJson`, `generateYaml` for programmatic use
44
+
45
+ ### `@vulcn/engine`
46
+ - **Plugin lifecycle hooks**: `DriverManager.execute()` now invokes `onRunStart` and `onRunEnd` plugin hooks around the driver runner, enabling plugins like the report generator to intercept and process results
47
+ - Removed legacy `Runner` and `Recorder` exports — all execution now goes through `DriverManager`
48
+ - Updated package description and SEO keywords for npm discoverability
49
+
50
+ ### `vulcn` (CLI)
51
+ - Added `--report <format>` flag (`html`, `json`, `yaml`, `all`) to generate security reports after test runs
52
+ - Added `--report-output <dir>` flag to specify output directory for generated reports
53
+ - Report plugin is auto-loaded when `--report` flag is used
54
+ - Updated package description and SEO keywords — positioned as a modern, fast alternative to legacy security scanners
55
+
56
+ ### `@vulcn/driver-browser`
57
+ - Updated package description, keywords, homepage, and bugs URL for npm discoverability
58
+
59
+ ### `@vulcn/plugin-payloads`
60
+ - Updated package description, keywords, homepage, and bugs URL for npm discoverability
61
+
62
+ ### `@vulcn/plugin-detect-xss`
63
+ - Updated package description, keywords, homepage, and bugs URL for npm discoverability
64
+
65
+ ### `@vulcn/plugin-detect-reflection`
66
+ - Updated package description, keywords, homepage, and bugs URL for npm discoverability
67
+
3
68
  ## 0.3.0
4
69
 
5
70
  ### Minor Changes
package/dist/index.js CHANGED
@@ -5,13 +5,18 @@ import { Command } from "commander";
5
5
 
6
6
  // src/record.ts
7
7
  import { writeFile } from "fs/promises";
8
- import { Recorder, serializeSession } from "@vulcn/engine";
8
+ import { DriverManager } from "@vulcn/engine";
9
+ import browserDriver from "@vulcn/driver-browser";
9
10
  import chalk from "chalk";
10
11
  import ora from "ora";
12
+ import { stringify } from "yaml";
11
13
  async function recordCommand(url, options) {
12
14
  const spinner = ora("Starting browser...").start();
15
+ const drivers = new DriverManager();
16
+ drivers.register(browserDriver);
13
17
  try {
14
- const session = await Recorder.start(url, {
18
+ const handle = await drivers.startRecording("browser", {
19
+ startUrl: url,
15
20
  browser: options.browser,
16
21
  headless: options.headless
17
22
  });
@@ -38,12 +43,12 @@ async function recordCommand(url, options) {
38
43
  console.log();
39
44
  const saveSpinner = ora("Stopping recording...").start();
40
45
  try {
41
- const result = await session.stop();
42
- const yaml = serializeSession(result);
46
+ const session = await handle.stop();
47
+ const yaml = stringify(session);
43
48
  await writeFile(options.output, yaml, "utf-8");
44
49
  saveSpinner.succeed(`Session saved to ${chalk.green(options.output)}`);
45
50
  console.log();
46
- console.log(chalk.cyan(`\u{1F4DD} Recorded ${result.steps.length} steps`));
51
+ console.log(chalk.cyan(`\u{1F4DD} Recorded ${session.steps.length} steps`));
47
52
  console.log();
48
53
  console.log(chalk.gray("To run with payloads:"));
49
54
  console.log(
@@ -84,17 +89,16 @@ async function recordCommand(url, options) {
84
89
 
85
90
  // src/run.ts
86
91
  import { readFile } from "fs/promises";
87
- import {
88
- Runner,
89
- parseSession,
90
- PluginManager
91
- } from "@vulcn/engine";
92
+ import { DriverManager as DriverManager2, PluginManager } from "@vulcn/engine";
93
+ import browserDriver2 from "@vulcn/driver-browser";
92
94
  import chalk2 from "chalk";
93
95
  import ora2 from "ora";
94
96
  async function runCommand(sessionFile, options) {
95
97
  const manager = new PluginManager();
96
98
  await manager.loadConfig(options.config);
97
99
  await manager.loadPlugins();
100
+ const drivers = new DriverManager2();
101
+ drivers.register(browserDriver2);
98
102
  const loadSpinner = ora2("Loading session...").start();
99
103
  let sessionYaml;
100
104
  try {
@@ -105,7 +109,7 @@ async function runCommand(sessionFile, options) {
105
109
  }
106
110
  let session;
107
111
  try {
108
- session = parseSession(sessionYaml);
112
+ session = drivers.parseSession(sessionYaml, "browser");
109
113
  loadSpinner.succeed(`Loaded session: ${chalk2.cyan(session.name)}`);
110
114
  } catch (err) {
111
115
  loadSpinner.fail("Invalid session file");
@@ -169,6 +173,24 @@ async function runCommand(sessionFile, options) {
169
173
  detectSpinner.fail(`Failed to load detect-xss plugin: ${err}`);
170
174
  }
171
175
  }
176
+ if (options.report) {
177
+ const reportSpinner = ora2("Loading report plugin...").start();
178
+ try {
179
+ const reportPlugin = await import("@vulcn/plugin-report");
180
+ const outputDir = options.reportOutput || ".";
181
+ manager.addPlugin(reportPlugin.default, {
182
+ format: options.report,
183
+ outputDir,
184
+ filename: "vulcn-report",
185
+ open: options.report === "html" || options.report === "all"
186
+ });
187
+ reportSpinner.succeed(
188
+ `Report plugin loaded (format: ${chalk2.cyan(options.report)})`
189
+ );
190
+ } catch (err) {
191
+ reportSpinner.fail(`Failed to load report plugin: ${err}`);
192
+ }
193
+ }
172
194
  const payloads = manager.getPayloads();
173
195
  console.log();
174
196
  console.log(chalk2.cyan("\u{1F50D} Running security tests"));
@@ -186,25 +208,20 @@ async function runCommand(sessionFile, options) {
186
208
  console.log();
187
209
  const runSpinner = ora2("Executing tests...").start();
188
210
  try {
189
- const result = await Runner.execute(
190
- session,
191
- {
192
- browser: options.browser,
193
- headless: options.headless,
194
- onFinding: (finding) => {
195
- runSpinner.stop();
196
- console.log(chalk2.red(`\u26A0\uFE0F FINDING: ${finding.title}`));
197
- console.log(chalk2.gray(` Step: ${finding.stepId}`));
198
- console.log(
199
- chalk2.gray(` Payload: ${finding.payload.slice(0, 50)}...`)
200
- );
201
- console.log(chalk2.gray(` URL: ${finding.url}`));
202
- console.log();
203
- runSpinner.start("Continuing tests...");
204
- }
205
- },
206
- { pluginManager: manager }
207
- );
211
+ const result = await drivers.execute(session, manager, {
212
+ headless: options.headless,
213
+ onFinding: (finding) => {
214
+ runSpinner.stop();
215
+ console.log(chalk2.red(`\u26A0\uFE0F FINDING: ${finding.title}`));
216
+ console.log(chalk2.gray(` Step: ${finding.stepId}`));
217
+ console.log(
218
+ chalk2.gray(` Payload: ${finding.payload.slice(0, 50)}...`)
219
+ );
220
+ console.log(chalk2.gray(` URL: ${finding.url}`));
221
+ console.log();
222
+ runSpinner.start("Continuing tests...");
223
+ }
224
+ });
208
225
  runSpinner.succeed("Tests completed");
209
226
  console.log();
210
227
  console.log(chalk2.cyan("\u{1F4CA} Results"));
@@ -340,7 +357,7 @@ async function payloadsCommand(options) {
340
357
  }
341
358
 
342
359
  // src/install.ts
343
- import { installBrowsers, checkBrowsers } from "@vulcn/engine";
360
+ import { installBrowsers, checkBrowsers } from "@vulcn/driver-browser";
344
361
  import chalk4 from "chalk";
345
362
  import ora3 from "ora";
346
363
  async function installCommand(browsers, options) {
@@ -460,7 +477,7 @@ async function initCommand(options) {
460
477
  lineWidth: 120
461
478
  });
462
479
  const content = `# Vulcn Configuration
463
- # Docs: https://rawlab.dev/vulcn/config
480
+ # Docs: https://docs.vulcn.dev/config
464
481
 
465
482
  ${yamlContent}`;
466
483
  await writeFile2(configFile, content, "utf-8");
@@ -520,7 +537,7 @@ async function loadConfigFile() {
520
537
  async function saveConfigFile(path, config) {
521
538
  const isJson = path.endsWith(".json");
522
539
  const content = isJson ? JSON.stringify(config, null, 2) : `# Vulcn Configuration
523
- # Docs: https://rawlab.dev/vulcn/config
540
+ # Docs: https://docs.vulcn.dev/config
524
541
 
525
542
  ${YAML2.stringify(config, { indent: 2 })}`;
526
543
  await writeFile3(path, content, "utf-8");
@@ -671,7 +688,7 @@ program.command("run").description("Run a recorded session with payloads").argum
671
688
  ).option(
672
689
  "-f, --payload-file <file>",
673
690
  "Load custom payloads from YAML/JSON file"
674
- ).option("-b, --browser <browser>", "Browser to use", "chromium").option("--headless", "Run in headless mode", true).option("--no-headless", "Run with visible browser").action(runCommand);
691
+ ).option("-b, --browser <browser>", "Browser to use", "chromium").option("--headless", "Run in headless mode", true).option("--no-headless", "Run with visible browser").option("-r, --report <format>", "Generate report (html, json, yaml, all)").option("--report-output <dir>", "Output directory for reports", ".").action(runCommand);
675
692
  program.command("payloads").description("List available payloads").option("-c, --category <category>", "Filter by category").option("-f, --file <file>", "Also show payloads from custom file").action(payloadsCommand);
676
693
  program.command("install").description("Install Playwright browsers").argument("[browsers...]", "Browsers to install (chromium, firefox, webkit)").option("--all", "Install all browsers").action(installCommand);
677
694
  program.command("doctor").description("Check available browsers").action(doctorCommand);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/record.ts","../src/run.ts","../src/payloads.ts","../src/install.ts","../src/init.ts","../src/plugin.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { recordCommand } from \"./record\";\nimport { runCommand } from \"./run\";\nimport { payloadsCommand } from \"./payloads\";\nimport { installCommand, doctorCommand } from \"./install\";\nimport { initCommand } from \"./init\";\nimport {\n pluginListCommand,\n pluginAddCommand,\n pluginRemoveCommand,\n pluginEnableCommand,\n pluginDisableCommand,\n} from \"./plugin\";\n\nconst program = new Command();\n\nprogram\n .name(\"vulcn\")\n .description(\"Security testing recorder & runner\")\n .version(\"0.2.0\");\n\n// vulcn record\nprogram\n .command(\"record\")\n .description(\"Record browser interactions\")\n .argument(\"<url>\", \"Starting URL to record from\")\n .option(\"-o, --output <file>\", \"Output file path\", \"session.vulcn.yml\")\n .option(\n \"-b, --browser <browser>\",\n \"Browser to use (chromium, firefox, webkit)\",\n \"chromium\",\n )\n .option(\"--headless\", \"Run in headless mode\", false)\n .action(recordCommand);\n\n// vulcn run\nprogram\n .command(\"run\")\n .description(\"Run a recorded session with payloads\")\n .argument(\"<session>\", \"Session file to run (.vulcn.yml)\")\n .option(\n \"-p, --payload <names...>\",\n \"Payloads to use (e.g., xss-basic, sqli-basic)\",\n )\n .option(\n \"-f, --payload-file <file>\",\n \"Load custom payloads from YAML/JSON file\",\n )\n .option(\"-b, --browser <browser>\", \"Browser to use\", \"chromium\")\n .option(\"--headless\", \"Run in headless mode\", true)\n .option(\"--no-headless\", \"Run with visible browser\")\n .action(runCommand);\n\n// vulcn payloads\nprogram\n .command(\"payloads\")\n .description(\"List available payloads\")\n .option(\"-c, --category <category>\", \"Filter by category\")\n .option(\"-f, --file <file>\", \"Also show payloads from custom file\")\n .action(payloadsCommand);\n\n// vulcn install\nprogram\n .command(\"install\")\n .description(\"Install Playwright browsers\")\n .argument(\"[browsers...]\", \"Browsers to install (chromium, firefox, webkit)\")\n .option(\"--all\", \"Install all browsers\")\n .action(installCommand);\n\n// vulcn doctor\nprogram\n .command(\"doctor\")\n .description(\"Check available browsers\")\n .action(doctorCommand);\n\n// vulcn init\nprogram\n .command(\"init\")\n .description(\"Create vulcn.config.yml with default configuration\")\n .option(\"-f, --force\", \"Overwrite existing config file\")\n .action(initCommand);\n\n// vulcn plugin (subcommands)\nconst pluginCmd = program.command(\"plugin\").description(\"Manage plugins\");\n\npluginCmd\n .command(\"list\")\n .description(\"List configured plugins\")\n .action(pluginListCommand);\n\npluginCmd\n .command(\"add\")\n .description(\"Add a plugin to configuration\")\n .argument(\"<name>\", \"Plugin name (e.g., @vulcn/plugin-detect-sqli)\")\n .option(\"-c, --config <json>\", \"Plugin configuration as JSON\")\n .action(pluginAddCommand);\n\npluginCmd\n .command(\"remove\")\n .description(\"Remove a plugin from configuration\")\n .argument(\"<name>\", \"Plugin name to remove\")\n .action(pluginRemoveCommand);\n\npluginCmd\n .command(\"enable\")\n .description(\"Enable a disabled plugin\")\n .argument(\"<name>\", \"Plugin name to enable\")\n .action(pluginEnableCommand);\n\npluginCmd\n .command(\"disable\")\n .description(\"Disable a plugin without removing it\")\n .argument(\"<name>\", \"Plugin name to disable\")\n .action(pluginDisableCommand);\n\nprogram.parse();\n","import { writeFile } from \"node:fs/promises\";\nimport { Recorder, serializeSession, type BrowserType } from \"@vulcn/engine\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\n\ninterface RecordOptions {\n output: string;\n browser: string;\n headless: boolean;\n}\n\nexport async function recordCommand(url: string, options: RecordOptions) {\n const spinner = ora(\"Starting browser...\").start();\n\n try {\n const session = await Recorder.start(url, {\n browser: options.browser as BrowserType,\n headless: options.headless,\n });\n\n spinner.succeed(\"Browser started\");\n console.log();\n console.log(chalk.cyan(\"🎬 Recording started\"));\n console.log(chalk.gray(` URL: ${url}`));\n console.log(chalk.gray(` Browser: ${options.browser}`));\n console.log();\n console.log(\n chalk.yellow(\" Interact with the browser to record actions.\"),\n );\n console.log(chalk.yellow(\" Press Ctrl+C to stop recording.\"));\n console.log();\n\n // Enable raw mode to intercept Ctrl+C before it becomes SIGINT\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(true);\n }\n process.stdin.resume();\n process.stdin.setEncoding(\"utf8\");\n\n // Handle Ctrl+C gracefully\n let stopped = false;\n const stopRecording = async (): Promise<void> => {\n if (stopped) return;\n stopped = true;\n\n console.log();\n const saveSpinner = ora(\"Stopping recording...\").start();\n\n try {\n const result = await session.stop();\n const yaml = serializeSession(result);\n await writeFile(options.output, yaml, \"utf-8\");\n\n saveSpinner.succeed(`Session saved to ${chalk.green(options.output)}`);\n console.log();\n console.log(chalk.cyan(`📝 Recorded ${result.steps.length} steps`));\n console.log();\n console.log(chalk.gray(\"To run with payloads:\"));\n console.log(\n chalk.white(` vulcn run ${options.output} --payload xss-basic`),\n );\n } catch (err) {\n saveSpinner.fail(\"Failed to save session\");\n console.error(chalk.red(String(err)));\n process.exit(1);\n }\n };\n\n // Use a promise-based approach to handle signals properly\n await new Promise<void>((resolve) => {\n const handleStop = () => {\n // Remove all handlers to prevent double-handling\n process.stdin.removeAllListeners(\"data\");\n process.off(\"SIGINT\", handleStop);\n process.off(\"SIGTERM\", handleStop);\n\n stopRecording()\n .then(() => {\n resolve();\n })\n .catch((err) => {\n console.error(chalk.red(String(err)));\n process.exit(1);\n });\n };\n\n // Listen for Ctrl+C keypress (char code 0x03) in raw mode\n process.stdin.on(\"data\", (key: string) => {\n if (key === \"\\u0003\") {\n handleStop();\n }\n });\n\n // Also handle SIGINT/SIGTERM for non-TTY or external signals\n process.on(\"SIGINT\", handleStop);\n process.on(\"SIGTERM\", handleStop);\n });\n } catch (err) {\n spinner.fail(\"Failed to start recording\");\n console.error(chalk.red(String(err)));\n process.exit(1);\n }\n}\n","import { readFile, access } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport {\n Runner,\n parseSession,\n PluginManager,\n type BrowserType,\n} from \"@vulcn/engine\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\n\ninterface RunOptions {\n payload?: string[];\n payloadFile?: string;\n browser: string;\n headless: boolean;\n config?: string;\n}\n\nexport async function runCommand(sessionFile: string, options: RunOptions) {\n // Create plugin manager for this run\n const manager = new PluginManager();\n\n // Load config from file if present\n await manager.loadConfig(options.config);\n\n // Load plugins from config\n await manager.loadPlugins();\n\n // Load session\n const loadSpinner = ora(\"Loading session...\").start();\n\n let sessionYaml: string;\n try {\n sessionYaml = await readFile(sessionFile, \"utf-8\");\n } catch {\n loadSpinner.fail(`Cannot read file: ${sessionFile}`);\n process.exit(1);\n }\n\n let session;\n try {\n session = parseSession(sessionYaml);\n loadSpinner.succeed(`Loaded session: ${chalk.cyan(session.name)}`);\n } catch (err) {\n loadSpinner.fail(\"Invalid session file\");\n console.error(chalk.red(String(err)));\n process.exit(1);\n }\n\n // Add payloads from CLI options (legacy support)\n if (options.payloadFile) {\n const customSpinner = ora(\"Loading custom payloads...\").start();\n try {\n // Dynamically import the payloads plugin file loader\n const { loadFromFile } = await import(\"@vulcn/plugin-payloads\");\n const loaded = await loadFromFile(options.payloadFile);\n manager.addPayloads(loaded);\n customSpinner.succeed(\n `Loaded ${chalk.cyan(loaded.length)} custom payload(s) from ${options.payloadFile}`,\n );\n } catch (err) {\n customSpinner.fail(`Failed to load custom payloads: ${err}`);\n process.exit(1);\n }\n }\n\n // If specific payloads requested via CLI, add them\n if (options.payload && options.payload.length > 0) {\n const payloadSpinner = ora(\"Loading specified payloads...\").start();\n try {\n const { BUILTIN_PAYLOADS, loadPayloadBox } =\n await import(\"@vulcn/plugin-payloads\");\n\n for (const spec of options.payload) {\n if (spec.startsWith(\"payloadbox:\")) {\n // PayloadBox spec\n const type = spec.slice(\"payloadbox:\".length);\n const payload = await loadPayloadBox(type);\n manager.addPayloads([payload]);\n payloadSpinner.text = `Loaded payloadbox:${type}`;\n } else if (spec in BUILTIN_PAYLOADS) {\n // Built-in payload\n manager.addPayloads([BUILTIN_PAYLOADS[spec]]);\n } else {\n payloadSpinner.warn(`Unknown payload: ${spec}`);\n }\n }\n payloadSpinner.succeed(`Loaded ${options.payload.length} payload set(s)`);\n } catch (err) {\n payloadSpinner.fail(`Failed to load payloads: ${err}`);\n process.exit(1);\n }\n }\n\n // If no payloads loaded yet, load defaults\n if (manager.getPayloads().length === 0) {\n const defaultSpinner = ora(\"Loading default payloads...\").start();\n try {\n const { BUILTIN_PAYLOADS } = await import(\"@vulcn/plugin-payloads\");\n // Add xss-basic as default\n manager.addPayloads([BUILTIN_PAYLOADS[\"xss-basic\"]]);\n defaultSpinner.succeed(\"Using default payload: xss-basic\");\n } catch (err) {\n defaultSpinner.fail(`Failed to load default payloads: ${err}`);\n process.exit(1);\n }\n }\n\n // Auto-load default detection plugin if not already configured\n if (!manager.hasPlugin(\"@vulcn/plugin-detect-xss\")) {\n const detectSpinner = ora(\"Loading XSS detection plugin...\").start();\n try {\n const detectXssPlugin = await import(\"@vulcn/plugin-detect-xss\");\n manager.addPlugin(detectXssPlugin.default);\n detectSpinner.succeed(\"Loaded XSS detection plugin\");\n } catch (err) {\n detectSpinner.fail(`Failed to load detect-xss plugin: ${err}`);\n // Non-fatal: continue without detection\n }\n }\n\n const payloads = manager.getPayloads();\n\n console.log();\n console.log(chalk.cyan(\"🔍 Running security tests\"));\n console.log(chalk.gray(` Session: ${session.name}`));\n console.log(\n chalk.gray(` Payloads: ${payloads.map((p) => p.name).join(\", \")}`),\n );\n console.log(\n chalk.gray(\n ` Payload count: ${payloads.reduce((sum, p) => sum + p.payloads.length, 0)}`,\n ),\n );\n console.log(chalk.gray(` Browser: ${options.browser}`));\n console.log(chalk.gray(` Headless: ${options.headless}`));\n console.log();\n\n const runSpinner = ora(\"Executing tests...\").start();\n\n try {\n const result = await Runner.execute(\n session,\n {\n browser: options.browser as BrowserType,\n headless: options.headless,\n onFinding: (finding) => {\n runSpinner.stop();\n console.log(chalk.red(`⚠️ FINDING: ${finding.title}`));\n console.log(chalk.gray(` Step: ${finding.stepId}`));\n console.log(\n chalk.gray(` Payload: ${finding.payload.slice(0, 50)}...`),\n );\n console.log(chalk.gray(` URL: ${finding.url}`));\n console.log();\n runSpinner.start(\"Continuing tests...\");\n },\n },\n { pluginManager: manager },\n );\n\n runSpinner.succeed(\"Tests completed\");\n console.log();\n\n // Summary\n console.log(chalk.cyan(\"📊 Results\"));\n console.log(chalk.gray(` Steps executed: ${result.stepsExecuted}`));\n console.log(chalk.gray(` Payloads tested: ${result.payloadsTested}`));\n console.log(\n chalk.gray(` Duration: ${(result.duration / 1000).toFixed(1)}s`),\n );\n console.log();\n\n if (result.findings.length > 0) {\n console.log(chalk.red(`🚨 ${result.findings.length} findings detected!`));\n console.log();\n for (const finding of result.findings) {\n const severityColor =\n finding.severity === \"critical\" || finding.severity === \"high\"\n ? chalk.red\n : finding.severity === \"medium\"\n ? chalk.yellow\n : chalk.gray;\n\n console.log(\n severityColor(`[${finding.severity.toUpperCase()}] ${finding.title}`),\n );\n console.log(chalk.gray(` Type: ${finding.type}`));\n console.log(chalk.gray(` Step: ${finding.stepId}`));\n console.log(chalk.gray(` URL: ${finding.url}`));\n console.log(chalk.gray(` Payload: ${finding.payload}`));\n console.log();\n }\n process.exit(1); // Non-zero exit for CI/CD\n } else {\n console.log(chalk.green(\"✅ No vulnerabilities detected\"));\n }\n\n if (result.errors.length > 0) {\n console.log();\n console.log(\n chalk.yellow(`⚠️ ${result.errors.length} errors during execution:`),\n );\n for (const err of result.errors.slice(0, 5)) {\n console.log(chalk.gray(` - ${err}`));\n }\n if (result.errors.length > 5) {\n console.log(chalk.gray(` ... and ${result.errors.length - 5} more`));\n }\n }\n } catch (err) {\n runSpinner.fail(\"Test execution failed\");\n console.error(chalk.red(String(err)));\n process.exit(1);\n }\n}\n","import type { PayloadCategory } from \"@vulcn/engine\";\nimport chalk from \"chalk\";\n\ninterface PayloadsOptions {\n category?: string;\n file?: string;\n}\n\nexport async function payloadsCommand(options: PayloadsOptions) {\n // Dynamically import the payloads plugin\n const { BUILTIN_PAYLOADS, loadFromFile, getPayloadBoxTypes } =\n await import(\"@vulcn/plugin-payloads\");\n\n // All payloads to display\n const allPayloads = { ...BUILTIN_PAYLOADS };\n\n // Load custom payloads if specified\n if (options.file) {\n try {\n const customPayloads = await loadFromFile(options.file);\n for (const p of customPayloads) {\n allPayloads[p.name] = p;\n }\n console.log(\n chalk.green(`✓ Loaded ${customPayloads.length} custom payload(s)\\n`),\n );\n } catch (err) {\n console.error(chalk.red(`Failed to load custom payloads: ${err}\\n`));\n }\n }\n\n console.log(chalk.cyan.bold(\"📦 Available Payloads\\n\"));\n\n // Get unique categories\n const categories = new Set<PayloadCategory>();\n for (const p of Object.values(allPayloads)) {\n categories.add(p.category);\n }\n\n // Filter by category if specified\n const filteredCategories = options.category\n ? [...categories].filter((c) => c === options.category)\n : [...categories];\n\n if (options.category && filteredCategories.length === 0) {\n console.log(chalk.yellow(`No payloads in category: ${options.category}`));\n console.log(\n chalk.gray(`Available categories: ${[...categories].join(\", \")}`),\n );\n return;\n }\n\n // Category colors\n const categoryColors: Record<string, (text: string) => string> = {\n xss: chalk.red,\n sqli: chalk.magenta,\n ssrf: chalk.blue,\n xxe: chalk.cyan,\n \"command-injection\": chalk.yellow,\n \"path-traversal\": chalk.green,\n \"open-redirect\": chalk.white,\n custom: chalk.gray,\n };\n\n for (const category of filteredCategories) {\n const payloads = Object.values(allPayloads).filter(\n (p) => p.category === category,\n );\n const color = categoryColors[category] || chalk.white;\n\n console.log(chalk.bold(color(`[${category.toUpperCase()}]`)));\n\n for (const payload of payloads) {\n const sourceTag =\n payload.source === \"custom\"\n ? chalk.gray(\" (custom)\")\n : payload.source === \"payloadbox\"\n ? chalk.blue(\" (payloadbox)\")\n : \"\";\n\n console.log(` ${chalk.white(payload.name)}${sourceTag}`);\n console.log(chalk.gray(` ${payload.description}`));\n console.log(chalk.gray(` ${payload.payloads.length} payloads`));\n }\n console.log();\n }\n\n // Show summary\n const totalBuiltin = Object.keys(BUILTIN_PAYLOADS).length;\n const totalPayloadStrings = Object.values(BUILTIN_PAYLOADS).reduce(\n (sum, p) => sum + p.payloads.length,\n 0,\n );\n\n console.log(chalk.cyan(\"─\".repeat(40)));\n console.log(\n chalk.gray(\n `${totalBuiltin} payload sets | ${totalPayloadStrings} individual payloads`,\n ),\n );\n\n // Show PayloadBox\n console.log();\n console.log(chalk.blue.bold(\"🌐 PayloadBox (Remote)\"));\n console.log(chalk.gray(\" Fetch curated payloads from PayloadsAllTheThings\"));\n const pbTypes = getPayloadBoxTypes();\n for (const type of pbTypes) {\n console.log(chalk.blue(` payloadbox:${type}`));\n }\n\n console.log();\n console.log(chalk.gray(\"Usage:\"));\n console.log(\n chalk.gray(\" vulcn run session.yml --payload xss-basic sqli-basic\"),\n );\n console.log(chalk.gray(\" vulcn run session.yml --payload-file custom.yml\"));\n console.log(\n chalk.blue(\n \" vulcn run session.yml --payload payloadbox:xss payloadbox:sql-injection\",\n ),\n );\n}\n","import { installBrowsers, checkBrowsers, type BrowserType } from \"@vulcn/engine\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\n\nexport async function installCommand(\n browsers?: string[],\n options?: { all?: boolean },\n) {\n // Determine which browsers to install\n let browsersToInstall: BrowserType[];\n\n if (options?.all) {\n browsersToInstall = [\"chromium\", \"firefox\", \"webkit\"];\n } else if (browsers && browsers.length > 0) {\n browsersToInstall = browsers as BrowserType[];\n } else {\n browsersToInstall = [\"chromium\"];\n }\n\n console.log();\n console.log(chalk.cyan(\"🔧 Installing browsers for Vulcn\"));\n console.log();\n\n try {\n await installBrowsers(browsersToInstall);\n console.log();\n console.log(chalk.green(\"✅ Browsers installed successfully\"));\n } catch (err) {\n console.error(chalk.red(\"Failed to install browsers:\"), err);\n process.exit(1);\n }\n}\n\nexport async function doctorCommand() {\n console.log();\n console.log(chalk.cyan(\"🩺 Vulcn Browser Check\"));\n console.log();\n\n const spinner = ora(\"Checking available browsers...\").start();\n\n try {\n const status = await checkBrowsers();\n spinner.stop();\n\n console.log(chalk.white(\"System Browsers:\"));\n console.log(\n ` Chrome: ${status.systemChrome ? chalk.green(\"✓ Available\") : chalk.gray(\"✗ Not found\")}`,\n );\n console.log(\n ` Edge: ${status.systemEdge ? chalk.green(\"✓ Available\") : chalk.gray(\"✗ Not found\")}`,\n );\n console.log();\n\n console.log(chalk.white(\"Playwright Browsers:\"));\n console.log(\n ` Chromium: ${status.playwrightChromium ? chalk.green(\"✓ Installed\") : chalk.gray(\"✗ Not installed\")}`,\n );\n console.log(\n ` Firefox: ${status.playwrightFirefox ? chalk.green(\"✓ Installed\") : chalk.gray(\"✗ Not installed\")}`,\n );\n console.log(\n ` WebKit: ${status.playwrightWebkit ? chalk.green(\"✓ Installed\") : chalk.gray(\"✗ Not installed\")}`,\n );\n console.log();\n\n // Recommendation\n if (status.systemChrome || status.systemEdge) {\n console.log(\n chalk.green(\"✅ Ready to use! Vulcn will use your system browser.\"),\n );\n } else if (status.playwrightChromium) {\n console.log(\n chalk.green(\"✅ Ready to use! Vulcn will use Playwright Chromium.\"),\n );\n } else {\n console.log(chalk.yellow(\"⚠️ No browsers found.\"));\n console.log();\n console.log(chalk.white(\"Options:\"));\n console.log(chalk.gray(\" 1. Install Google Chrome (recommended)\"));\n console.log(chalk.gray(\" 2. Run: vulcn install\"));\n }\n } catch (err) {\n spinner.fail(\"Failed to check browsers\");\n console.error(chalk.red(String(err)));\n process.exit(1);\n }\n}\n","/**\n * vulcn init - Create vulcn.config.yml\n */\n\nimport { existsSync } from \"node:fs\";\nimport { writeFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport YAML from \"yaml\";\n\ninterface InitOptions {\n force?: boolean;\n}\n\nconst DEFAULT_CONFIG = {\n version: \"1\",\n plugins: [\n {\n name: \"@vulcn/plugin-payloads\",\n config: {\n builtin: true,\n },\n },\n {\n name: \"@vulcn/plugin-detect-xss\",\n config: {\n detectDialogs: true,\n detectConsole: true,\n severity: \"high\",\n },\n },\n ],\n settings: {\n browser: \"chromium\",\n headless: true,\n },\n};\n\nexport async function initCommand(options: InitOptions) {\n const configFile = resolve(process.cwd(), \"vulcn.config.yml\");\n\n // Check if config already exists\n if (existsSync(configFile) && !options.force) {\n console.log(\n chalk.yellow(\n \"⚠️ vulcn.config.yml already exists. Use --force to overwrite.\",\n ),\n );\n process.exit(1);\n }\n\n const spinner = ora(\"Creating vulcn.config.yml...\").start();\n\n try {\n const yamlContent = YAML.stringify(DEFAULT_CONFIG, {\n indent: 2,\n lineWidth: 120,\n });\n\n // Add helpful comments\n const content = `# Vulcn Configuration\n# Docs: https://rawlab.dev/vulcn/config\n\n${yamlContent}`;\n\n await writeFile(configFile, content, \"utf-8\");\n spinner.succeed(\"Created vulcn.config.yml\");\n\n console.log();\n console.log(chalk.cyan(\"📁 Configuration created\"));\n console.log();\n console.log(chalk.gray(\"Next steps:\"));\n console.log(chalk.gray(\" 1. Record a session:\"));\n console.log(\n chalk.white(\" vulcn record https://example.com -o session.vulcn.yml\"),\n );\n console.log();\n console.log(chalk.gray(\" 2. Run security tests:\"));\n console.log(chalk.white(\" vulcn run session.vulcn.yml\"));\n console.log();\n console.log(chalk.gray(\" 3. Customize payloads:\"));\n console.log(\n chalk.white(\n \" vulcn run session.vulcn.yml --payload xss-basic sqli-basic\",\n ),\n );\n console.log();\n } catch (err) {\n spinner.fail(\"Failed to create config\");\n console.error(chalk.red(String(err)));\n process.exit(1);\n }\n}\n","/**\n * vulcn plugin - Plugin management commands\n */\n\nimport { existsSync } from \"node:fs\";\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport YAML from \"yaml\";\n\ninterface PluginConfig {\n name: string;\n config?: Record<string, unknown>;\n enabled?: boolean;\n}\n\ninterface VulcnConfig {\n version: string;\n plugins?: PluginConfig[];\n settings?: Record<string, unknown>;\n}\n\nconst CONFIG_FILES = [\n \"vulcn.config.yml\",\n \"vulcn.config.yaml\",\n \"vulcn.config.json\",\n \".vulcnrc.yml\",\n \".vulcnrc.yaml\",\n \".vulcnrc.json\",\n];\n\n/**\n * Find and load the config file\n */\nasync function loadConfigFile(): Promise<{\n path: string;\n config: VulcnConfig;\n} | null> {\n for (const file of CONFIG_FILES) {\n const configPath = resolve(process.cwd(), file);\n if (existsSync(configPath)) {\n const content = await readFile(configPath, \"utf-8\");\n const config = file.endsWith(\".json\")\n ? JSON.parse(content)\n : YAML.parse(content);\n return { path: configPath, config };\n }\n }\n return null;\n}\n\n/**\n * Save config back to file\n */\nasync function saveConfigFile(\n path: string,\n config: VulcnConfig,\n): Promise<void> {\n const isJson = path.endsWith(\".json\");\n const content = isJson\n ? JSON.stringify(config, null, 2)\n : `# Vulcn Configuration\\n# Docs: https://rawlab.dev/vulcn/config\\n\\n${YAML.stringify(config, { indent: 2 })}`;\n await writeFile(path, content, \"utf-8\");\n}\n\n/**\n * vulcn plugin list - Show loaded plugins\n */\nexport async function pluginListCommand() {\n const result = await loadConfigFile();\n\n if (!result) {\n console.log(chalk.yellow(\"No vulcn.config.yml found.\"));\n console.log(chalk.gray(\"Run 'vulcn init' to create one.\"));\n return;\n }\n\n const { config } = result;\n const plugins = config.plugins || [];\n\n if (plugins.length === 0) {\n console.log(chalk.yellow(\"No plugins configured.\"));\n console.log(chalk.gray(\"Run 'vulcn plugin add <name>' to add a plugin.\"));\n return;\n }\n\n console.log(chalk.cyan(\"📦 Configured Plugins\\n\"));\n\n for (const plugin of plugins) {\n const status =\n plugin.enabled === false ? chalk.gray(\"(disabled)\") : chalk.green(\"✓\");\n const name =\n plugin.enabled === false\n ? chalk.gray(plugin.name)\n : chalk.white(plugin.name);\n console.log(` ${status} ${name}`);\n\n if (plugin.config && Object.keys(plugin.config).length > 0) {\n for (const [key, value] of Object.entries(plugin.config)) {\n console.log(chalk.gray(` ${key}: ${JSON.stringify(value)}`));\n }\n }\n }\n\n console.log();\n}\n\ninterface AddOptions {\n config?: string;\n}\n\n/**\n * vulcn plugin add <name> - Add a plugin to config\n */\nexport async function pluginAddCommand(name: string, options: AddOptions) {\n const spinner = ora(`Adding plugin ${name}...`).start();\n\n // Load existing config\n let result = await loadConfigFile();\n\n if (!result) {\n spinner.fail(\"No vulcn.config.yml found. Run 'vulcn init' first.\");\n process.exit(1);\n }\n\n const { path: configPath, config } = result;\n\n // Check if plugin already exists\n const plugins = config.plugins || [];\n const existing = plugins.find((p) => p.name === name);\n\n if (existing) {\n if (existing.enabled === false) {\n // Re-enable the plugin\n existing.enabled = true;\n await saveConfigFile(configPath, config);\n spinner.succeed(`Re-enabled plugin: ${chalk.cyan(name)}`);\n } else {\n spinner.warn(`Plugin ${chalk.cyan(name)} is already configured.`);\n }\n return;\n }\n\n // Add the new plugin\n const newPlugin: PluginConfig = { name };\n\n // Parse config option if provided\n if (options.config) {\n try {\n newPlugin.config = JSON.parse(options.config);\n } catch {\n spinner.fail(`Invalid config JSON: ${options.config}`);\n process.exit(1);\n }\n }\n\n config.plugins = [...plugins, newPlugin];\n await saveConfigFile(configPath, config);\n\n spinner.succeed(`Added plugin: ${chalk.cyan(name)}`);\n console.log(\n chalk.gray(\n `\\nPlugin will be loaded on next 'vulcn run' or 'vulcn record'.`,\n ),\n );\n}\n\n/**\n * vulcn plugin remove <name> - Remove a plugin from config\n */\nexport async function pluginRemoveCommand(name: string) {\n const spinner = ora(`Removing plugin ${name}...`).start();\n\n const result = await loadConfigFile();\n\n if (!result) {\n spinner.fail(\"No vulcn.config.yml found.\");\n process.exit(1);\n }\n\n const { path: configPath, config } = result;\n const plugins = config.plugins || [];\n\n const index = plugins.findIndex((p) => p.name === name);\n\n if (index === -1) {\n spinner.warn(`Plugin ${chalk.cyan(name)} is not configured.`);\n return;\n }\n\n // Remove the plugin\n plugins.splice(index, 1);\n config.plugins = plugins;\n await saveConfigFile(configPath, config);\n\n spinner.succeed(`Removed plugin: ${chalk.cyan(name)}`);\n}\n\ninterface EnableDisableOptions {\n // Future: could add options here\n}\n\n/**\n * vulcn plugin enable <name> - Enable a disabled plugin\n */\nexport async function pluginEnableCommand(\n name: string,\n _options: EnableDisableOptions,\n) {\n const spinner = ora(`Enabling plugin ${name}...`).start();\n\n const result = await loadConfigFile();\n\n if (!result) {\n spinner.fail(\"No vulcn.config.yml found.\");\n process.exit(1);\n }\n\n const { path: configPath, config } = result;\n const plugins = config.plugins || [];\n\n const plugin = plugins.find((p) => p.name === name);\n\n if (!plugin) {\n spinner.fail(\n `Plugin ${chalk.cyan(name)} is not configured. Use 'vulcn plugin add ${name}' first.`,\n );\n process.exit(1);\n }\n\n if (plugin.enabled !== false) {\n spinner.info(`Plugin ${chalk.cyan(name)} is already enabled.`);\n return;\n }\n\n plugin.enabled = true;\n await saveConfigFile(configPath, config);\n\n spinner.succeed(`Enabled plugin: ${chalk.cyan(name)}`);\n}\n\n/**\n * vulcn plugin disable <name> - Disable a plugin without removing it\n */\nexport async function pluginDisableCommand(\n name: string,\n _options: EnableDisableOptions,\n) {\n const spinner = ora(`Disabling plugin ${name}...`).start();\n\n const result = await loadConfigFile();\n\n if (!result) {\n spinner.fail(\"No vulcn.config.yml found.\");\n process.exit(1);\n }\n\n const { path: configPath, config } = result;\n const plugins = config.plugins || [];\n\n const plugin = plugins.find((p) => p.name === name);\n\n if (!plugin) {\n spinner.fail(`Plugin ${chalk.cyan(name)} is not configured.`);\n process.exit(1);\n }\n\n if (plugin.enabled === false) {\n spinner.info(`Plugin ${chalk.cyan(name)} is already disabled.`);\n return;\n }\n\n plugin.enabled = false;\n await saveConfigFile(configPath, config);\n\n spinner.succeed(`Disabled plugin: ${chalk.cyan(name)}`);\n}\n"],"mappings":"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","names":["resolve","chalk","ora","chalk","chalk","ora","writeFile","chalk","ora","existsSync","readFile","writeFile","resolve","chalk","ora","YAML"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/record.ts","../src/run.ts","../src/payloads.ts","../src/install.ts","../src/init.ts","../src/plugin.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { recordCommand } from \"./record\";\nimport { runCommand } from \"./run\";\nimport { payloadsCommand } from \"./payloads\";\nimport { installCommand, doctorCommand } from \"./install\";\nimport { initCommand } from \"./init\";\nimport {\n pluginListCommand,\n pluginAddCommand,\n pluginRemoveCommand,\n pluginEnableCommand,\n pluginDisableCommand,\n} from \"./plugin\";\n\nconst program = new Command();\n\nprogram\n .name(\"vulcn\")\n .description(\"Security testing recorder & runner\")\n .version(\"0.2.0\");\n\n// vulcn record\nprogram\n .command(\"record\")\n .description(\"Record browser interactions\")\n .argument(\"<url>\", \"Starting URL to record from\")\n .option(\"-o, --output <file>\", \"Output file path\", \"session.vulcn.yml\")\n .option(\n \"-b, --browser <browser>\",\n \"Browser to use (chromium, firefox, webkit)\",\n \"chromium\",\n )\n .option(\"--headless\", \"Run in headless mode\", false)\n .action(recordCommand);\n\n// vulcn run\nprogram\n .command(\"run\")\n .description(\"Run a recorded session with payloads\")\n .argument(\"<session>\", \"Session file to run (.vulcn.yml)\")\n .option(\n \"-p, --payload <names...>\",\n \"Payloads to use (e.g., xss-basic, sqli-basic)\",\n )\n .option(\n \"-f, --payload-file <file>\",\n \"Load custom payloads from YAML/JSON file\",\n )\n .option(\"-b, --browser <browser>\", \"Browser to use\", \"chromium\")\n .option(\"--headless\", \"Run in headless mode\", true)\n .option(\"--no-headless\", \"Run with visible browser\")\n .option(\"-r, --report <format>\", \"Generate report (html, json, yaml, all)\")\n .option(\"--report-output <dir>\", \"Output directory for reports\", \".\")\n .action(runCommand);\n\n// vulcn payloads\nprogram\n .command(\"payloads\")\n .description(\"List available payloads\")\n .option(\"-c, --category <category>\", \"Filter by category\")\n .option(\"-f, --file <file>\", \"Also show payloads from custom file\")\n .action(payloadsCommand);\n\n// vulcn install\nprogram\n .command(\"install\")\n .description(\"Install Playwright browsers\")\n .argument(\"[browsers...]\", \"Browsers to install (chromium, firefox, webkit)\")\n .option(\"--all\", \"Install all browsers\")\n .action(installCommand);\n\n// vulcn doctor\nprogram\n .command(\"doctor\")\n .description(\"Check available browsers\")\n .action(doctorCommand);\n\n// vulcn init\nprogram\n .command(\"init\")\n .description(\"Create vulcn.config.yml with default configuration\")\n .option(\"-f, --force\", \"Overwrite existing config file\")\n .action(initCommand);\n\n// vulcn plugin (subcommands)\nconst pluginCmd = program.command(\"plugin\").description(\"Manage plugins\");\n\npluginCmd\n .command(\"list\")\n .description(\"List configured plugins\")\n .action(pluginListCommand);\n\npluginCmd\n .command(\"add\")\n .description(\"Add a plugin to configuration\")\n .argument(\"<name>\", \"Plugin name (e.g., @vulcn/plugin-detect-sqli)\")\n .option(\"-c, --config <json>\", \"Plugin configuration as JSON\")\n .action(pluginAddCommand);\n\npluginCmd\n .command(\"remove\")\n .description(\"Remove a plugin from configuration\")\n .argument(\"<name>\", \"Plugin name to remove\")\n .action(pluginRemoveCommand);\n\npluginCmd\n .command(\"enable\")\n .description(\"Enable a disabled plugin\")\n .argument(\"<name>\", \"Plugin name to enable\")\n .action(pluginEnableCommand);\n\npluginCmd\n .command(\"disable\")\n .description(\"Disable a plugin without removing it\")\n .argument(\"<name>\", \"Plugin name to disable\")\n .action(pluginDisableCommand);\n\nprogram.parse();\n","import { writeFile } from \"node:fs/promises\";\nimport { DriverManager } from \"@vulcn/engine\";\nimport browserDriver from \"@vulcn/driver-browser\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { stringify } from \"yaml\";\n\ninterface RecordOptions {\n output: string;\n browser: string;\n headless: boolean;\n}\n\nexport async function recordCommand(url: string, options: RecordOptions) {\n const spinner = ora(\"Starting browser...\").start();\n\n // Set up driver manager with browser driver\n const drivers = new DriverManager();\n drivers.register(browserDriver);\n\n try {\n const handle = await drivers.startRecording(\"browser\", {\n startUrl: url,\n browser: options.browser,\n headless: options.headless,\n });\n\n spinner.succeed(\"Browser started\");\n console.log();\n console.log(chalk.cyan(\"🎬 Recording started\"));\n console.log(chalk.gray(` URL: ${url}`));\n console.log(chalk.gray(` Browser: ${options.browser}`));\n console.log();\n console.log(\n chalk.yellow(\" Interact with the browser to record actions.\"),\n );\n console.log(chalk.yellow(\" Press Ctrl+C to stop recording.\"));\n console.log();\n\n // Enable raw mode to intercept Ctrl+C before it becomes SIGINT\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(true);\n }\n process.stdin.resume();\n process.stdin.setEncoding(\"utf8\");\n\n // Handle Ctrl+C gracefully\n let stopped = false;\n const stopRecording = async (): Promise<void> => {\n if (stopped) return;\n stopped = true;\n\n console.log();\n const saveSpinner = ora(\"Stopping recording...\").start();\n\n try {\n const session = await handle.stop();\n const yaml = stringify(session);\n await writeFile(options.output, yaml, \"utf-8\");\n\n saveSpinner.succeed(`Session saved to ${chalk.green(options.output)}`);\n console.log();\n console.log(chalk.cyan(`📝 Recorded ${session.steps.length} steps`));\n console.log();\n console.log(chalk.gray(\"To run with payloads:\"));\n console.log(\n chalk.white(` vulcn run ${options.output} --payload xss-basic`),\n );\n } catch (err) {\n saveSpinner.fail(\"Failed to save session\");\n console.error(chalk.red(String(err)));\n process.exit(1);\n }\n };\n\n // Use a promise-based approach to handle signals properly\n await new Promise<void>((resolve) => {\n const handleStop = () => {\n // Remove all handlers to prevent double-handling\n process.stdin.removeAllListeners(\"data\");\n process.off(\"SIGINT\", handleStop);\n process.off(\"SIGTERM\", handleStop);\n\n stopRecording()\n .then(() => {\n resolve();\n })\n .catch((err) => {\n console.error(chalk.red(String(err)));\n process.exit(1);\n });\n };\n\n // Listen for Ctrl+C keypress (char code 0x03) in raw mode\n process.stdin.on(\"data\", (key: string) => {\n if (key === \"\\u0003\") {\n handleStop();\n }\n });\n\n // Also handle SIGINT/SIGTERM for non-TTY or external signals\n process.on(\"SIGINT\", handleStop);\n process.on(\"SIGTERM\", handleStop);\n });\n } catch (err) {\n spinner.fail(\"Failed to start recording\");\n console.error(chalk.red(String(err)));\n process.exit(1);\n }\n}\n","import { readFile } from \"node:fs/promises\";\nimport { DriverManager, PluginManager } from \"@vulcn/engine\";\nimport browserDriver from \"@vulcn/driver-browser\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\n\ninterface RunOptions {\n payload?: string[];\n payloadFile?: string;\n browser: string;\n headless: boolean;\n config?: string;\n report?: string;\n reportOutput?: string;\n}\n\nexport async function runCommand(sessionFile: string, options: RunOptions) {\n // Create plugin manager for this run\n const manager = new PluginManager();\n\n // Load config from file if present\n await manager.loadConfig(options.config);\n\n // Load plugins from config\n await manager.loadPlugins();\n\n // Set up driver manager with browser driver\n const drivers = new DriverManager();\n drivers.register(browserDriver);\n\n // Load session\n const loadSpinner = ora(\"Loading session...\").start();\n\n let sessionYaml: string;\n try {\n sessionYaml = await readFile(sessionFile, \"utf-8\");\n } catch {\n loadSpinner.fail(`Cannot read file: ${sessionFile}`);\n process.exit(1);\n }\n\n // Parse session — supports both legacy and driver-based formats\n let session;\n try {\n session = drivers.parseSession(sessionYaml, \"browser\");\n loadSpinner.succeed(`Loaded session: ${chalk.cyan(session.name)}`);\n } catch (err) {\n loadSpinner.fail(\"Invalid session file\");\n console.error(chalk.red(String(err)));\n process.exit(1);\n }\n\n // Add payloads from CLI options\n if (options.payloadFile) {\n const customSpinner = ora(\"Loading custom payloads...\").start();\n try {\n const { loadFromFile } = await import(\"@vulcn/plugin-payloads\");\n const loaded = await loadFromFile(options.payloadFile);\n manager.addPayloads(loaded);\n customSpinner.succeed(\n `Loaded ${chalk.cyan(loaded.length)} custom payload(s) from ${options.payloadFile}`,\n );\n } catch (err) {\n customSpinner.fail(`Failed to load custom payloads: ${err}`);\n process.exit(1);\n }\n }\n\n // If specific payloads requested via CLI, add them\n if (options.payload && options.payload.length > 0) {\n const payloadSpinner = ora(\"Loading specified payloads...\").start();\n try {\n const { BUILTIN_PAYLOADS, loadPayloadBox } =\n await import(\"@vulcn/plugin-payloads\");\n\n for (const spec of options.payload) {\n if (spec.startsWith(\"payloadbox:\")) {\n // PayloadBox spec\n const type = spec.slice(\"payloadbox:\".length);\n const payload = await loadPayloadBox(type);\n manager.addPayloads([payload]);\n payloadSpinner.text = `Loaded payloadbox:${type}`;\n } else if (spec in BUILTIN_PAYLOADS) {\n // Built-in payload\n manager.addPayloads([BUILTIN_PAYLOADS[spec]]);\n } else {\n payloadSpinner.warn(`Unknown payload: ${spec}`);\n }\n }\n payloadSpinner.succeed(`Loaded ${options.payload.length} payload set(s)`);\n } catch (err) {\n payloadSpinner.fail(`Failed to load payloads: ${err}`);\n process.exit(1);\n }\n }\n\n // If no payloads loaded yet, load defaults\n if (manager.getPayloads().length === 0) {\n const defaultSpinner = ora(\"Loading default payloads...\").start();\n try {\n const { BUILTIN_PAYLOADS } = await import(\"@vulcn/plugin-payloads\");\n // Add xss-basic as default\n manager.addPayloads([BUILTIN_PAYLOADS[\"xss-basic\"]]);\n defaultSpinner.succeed(\"Using default payload: xss-basic\");\n } catch (err) {\n defaultSpinner.fail(`Failed to load default payloads: ${err}`);\n process.exit(1);\n }\n }\n\n // Auto-load default detection plugin if not already configured\n if (!manager.hasPlugin(\"@vulcn/plugin-detect-xss\")) {\n const detectSpinner = ora(\"Loading XSS detection plugin...\").start();\n try {\n const detectXssPlugin = await import(\"@vulcn/plugin-detect-xss\");\n manager.addPlugin(detectXssPlugin.default);\n detectSpinner.succeed(\"Loaded XSS detection plugin\");\n } catch (err) {\n detectSpinner.fail(`Failed to load detect-xss plugin: ${err}`);\n // Non-fatal: continue without detection\n }\n }\n\n // Load report plugin if --report is specified\n if (options.report) {\n const reportSpinner = ora(\"Loading report plugin...\").start();\n try {\n const reportPlugin = await import(\"@vulcn/plugin-report\");\n\n // Determine output path from --report-output or default\n const outputDir = options.reportOutput || \".\";\n\n manager.addPlugin(reportPlugin.default, {\n format: options.report,\n outputDir,\n filename: \"vulcn-report\",\n open: options.report === \"html\" || options.report === \"all\",\n });\n reportSpinner.succeed(\n `Report plugin loaded (format: ${chalk.cyan(options.report)})`,\n );\n } catch (err) {\n reportSpinner.fail(`Failed to load report plugin: ${err}`);\n // Non-fatal: continue without report\n }\n }\n\n const payloads = manager.getPayloads();\n\n console.log();\n console.log(chalk.cyan(\"🔍 Running security tests\"));\n console.log(chalk.gray(` Session: ${session.name}`));\n console.log(\n chalk.gray(` Payloads: ${payloads.map((p) => p.name).join(\", \")}`),\n );\n console.log(\n chalk.gray(\n ` Payload count: ${payloads.reduce((sum, p) => sum + p.payloads.length, 0)}`,\n ),\n );\n console.log(chalk.gray(` Browser: ${options.browser}`));\n console.log(chalk.gray(` Headless: ${options.headless}`));\n console.log();\n\n const runSpinner = ora(\"Executing tests...\").start();\n\n try {\n const result = await drivers.execute(session, manager, {\n headless: options.headless,\n onFinding: (finding) => {\n runSpinner.stop();\n console.log(chalk.red(`⚠️ FINDING: ${finding.title}`));\n console.log(chalk.gray(` Step: ${finding.stepId}`));\n console.log(\n chalk.gray(` Payload: ${finding.payload.slice(0, 50)}...`),\n );\n console.log(chalk.gray(` URL: ${finding.url}`));\n console.log();\n runSpinner.start(\"Continuing tests...\");\n },\n });\n\n runSpinner.succeed(\"Tests completed\");\n console.log();\n\n // Summary\n console.log(chalk.cyan(\"📊 Results\"));\n console.log(chalk.gray(` Steps executed: ${result.stepsExecuted}`));\n console.log(chalk.gray(` Payloads tested: ${result.payloadsTested}`));\n console.log(\n chalk.gray(` Duration: ${(result.duration / 1000).toFixed(1)}s`),\n );\n console.log();\n\n if (result.findings.length > 0) {\n console.log(chalk.red(`🚨 ${result.findings.length} findings detected!`));\n console.log();\n for (const finding of result.findings) {\n const severityColor =\n finding.severity === \"critical\" || finding.severity === \"high\"\n ? chalk.red\n : finding.severity === \"medium\"\n ? chalk.yellow\n : chalk.gray;\n\n console.log(\n severityColor(`[${finding.severity.toUpperCase()}] ${finding.title}`),\n );\n console.log(chalk.gray(` Type: ${finding.type}`));\n console.log(chalk.gray(` Step: ${finding.stepId}`));\n console.log(chalk.gray(` URL: ${finding.url}`));\n console.log(chalk.gray(` Payload: ${finding.payload}`));\n console.log();\n }\n process.exit(1); // Non-zero exit for CI/CD\n } else {\n console.log(chalk.green(\"✅ No vulnerabilities detected\"));\n }\n\n if (result.errors.length > 0) {\n console.log();\n console.log(\n chalk.yellow(`⚠️ ${result.errors.length} errors during execution:`),\n );\n for (const err of result.errors.slice(0, 5)) {\n console.log(chalk.gray(` - ${err}`));\n }\n if (result.errors.length > 5) {\n console.log(chalk.gray(` ... and ${result.errors.length - 5} more`));\n }\n }\n } catch (err) {\n runSpinner.fail(\"Test execution failed\");\n console.error(chalk.red(String(err)));\n process.exit(1);\n }\n}\n","import type { PayloadCategory } from \"@vulcn/engine\";\nimport chalk from \"chalk\";\n\ninterface PayloadsOptions {\n category?: string;\n file?: string;\n}\n\nexport async function payloadsCommand(options: PayloadsOptions) {\n // Dynamically import the payloads plugin\n const { BUILTIN_PAYLOADS, loadFromFile, getPayloadBoxTypes } =\n await import(\"@vulcn/plugin-payloads\");\n\n // All payloads to display\n const allPayloads = { ...BUILTIN_PAYLOADS };\n\n // Load custom payloads if specified\n if (options.file) {\n try {\n const customPayloads = await loadFromFile(options.file);\n for (const p of customPayloads) {\n allPayloads[p.name] = p;\n }\n console.log(\n chalk.green(`✓ Loaded ${customPayloads.length} custom payload(s)\\n`),\n );\n } catch (err) {\n console.error(chalk.red(`Failed to load custom payloads: ${err}\\n`));\n }\n }\n\n console.log(chalk.cyan.bold(\"📦 Available Payloads\\n\"));\n\n // Get unique categories\n const categories = new Set<PayloadCategory>();\n for (const p of Object.values(allPayloads)) {\n categories.add(p.category);\n }\n\n // Filter by category if specified\n const filteredCategories = options.category\n ? [...categories].filter((c) => c === options.category)\n : [...categories];\n\n if (options.category && filteredCategories.length === 0) {\n console.log(chalk.yellow(`No payloads in category: ${options.category}`));\n console.log(\n chalk.gray(`Available categories: ${[...categories].join(\", \")}`),\n );\n return;\n }\n\n // Category colors\n const categoryColors: Record<string, (text: string) => string> = {\n xss: chalk.red,\n sqli: chalk.magenta,\n ssrf: chalk.blue,\n xxe: chalk.cyan,\n \"command-injection\": chalk.yellow,\n \"path-traversal\": chalk.green,\n \"open-redirect\": chalk.white,\n custom: chalk.gray,\n };\n\n for (const category of filteredCategories) {\n const payloads = Object.values(allPayloads).filter(\n (p) => p.category === category,\n );\n const color = categoryColors[category] || chalk.white;\n\n console.log(chalk.bold(color(`[${category.toUpperCase()}]`)));\n\n for (const payload of payloads) {\n const sourceTag =\n payload.source === \"custom\"\n ? chalk.gray(\" (custom)\")\n : payload.source === \"payloadbox\"\n ? chalk.blue(\" (payloadbox)\")\n : \"\";\n\n console.log(` ${chalk.white(payload.name)}${sourceTag}`);\n console.log(chalk.gray(` ${payload.description}`));\n console.log(chalk.gray(` ${payload.payloads.length} payloads`));\n }\n console.log();\n }\n\n // Show summary\n const totalBuiltin = Object.keys(BUILTIN_PAYLOADS).length;\n const totalPayloadStrings = Object.values(BUILTIN_PAYLOADS).reduce(\n (sum, p) => sum + p.payloads.length,\n 0,\n );\n\n console.log(chalk.cyan(\"─\".repeat(40)));\n console.log(\n chalk.gray(\n `${totalBuiltin} payload sets | ${totalPayloadStrings} individual payloads`,\n ),\n );\n\n // Show PayloadBox\n console.log();\n console.log(chalk.blue.bold(\"🌐 PayloadBox (Remote)\"));\n console.log(chalk.gray(\" Fetch curated payloads from PayloadsAllTheThings\"));\n const pbTypes = getPayloadBoxTypes();\n for (const type of pbTypes) {\n console.log(chalk.blue(` payloadbox:${type}`));\n }\n\n console.log();\n console.log(chalk.gray(\"Usage:\"));\n console.log(\n chalk.gray(\" vulcn run session.yml --payload xss-basic sqli-basic\"),\n );\n console.log(chalk.gray(\" vulcn run session.yml --payload-file custom.yml\"));\n console.log(\n chalk.blue(\n \" vulcn run session.yml --payload payloadbox:xss payloadbox:sql-injection\",\n ),\n );\n}\n","import { installBrowsers, checkBrowsers } from \"@vulcn/driver-browser\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\n\ntype BrowserType = \"chromium\" | \"firefox\" | \"webkit\";\n\nexport async function installCommand(\n browsers?: string[],\n options?: { all?: boolean },\n) {\n // Determine which browsers to install\n let browsersToInstall: BrowserType[];\n\n if (options?.all) {\n browsersToInstall = [\"chromium\", \"firefox\", \"webkit\"];\n } else if (browsers && browsers.length > 0) {\n browsersToInstall = browsers as BrowserType[];\n } else {\n browsersToInstall = [\"chromium\"];\n }\n\n console.log();\n console.log(chalk.cyan(\"🔧 Installing browsers for Vulcn\"));\n console.log();\n\n try {\n await installBrowsers(browsersToInstall);\n console.log();\n console.log(chalk.green(\"✅ Browsers installed successfully\"));\n } catch (err) {\n console.error(chalk.red(\"Failed to install browsers:\"), err);\n process.exit(1);\n }\n}\n\nexport async function doctorCommand() {\n console.log();\n console.log(chalk.cyan(\"🩺 Vulcn Browser Check\"));\n console.log();\n\n const spinner = ora(\"Checking available browsers...\").start();\n\n try {\n const status = await checkBrowsers();\n spinner.stop();\n\n console.log(chalk.white(\"System Browsers:\"));\n console.log(\n ` Chrome: ${status.systemChrome ? chalk.green(\"✓ Available\") : chalk.gray(\"✗ Not found\")}`,\n );\n console.log(\n ` Edge: ${status.systemEdge ? chalk.green(\"✓ Available\") : chalk.gray(\"✗ Not found\")}`,\n );\n console.log();\n\n console.log(chalk.white(\"Playwright Browsers:\"));\n console.log(\n ` Chromium: ${status.playwrightChromium ? chalk.green(\"✓ Installed\") : chalk.gray(\"✗ Not installed\")}`,\n );\n console.log(\n ` Firefox: ${status.playwrightFirefox ? chalk.green(\"✓ Installed\") : chalk.gray(\"✗ Not installed\")}`,\n );\n console.log(\n ` WebKit: ${status.playwrightWebkit ? chalk.green(\"✓ Installed\") : chalk.gray(\"✗ Not installed\")}`,\n );\n console.log();\n\n // Recommendation\n if (status.systemChrome || status.systemEdge) {\n console.log(\n chalk.green(\"✅ Ready to use! Vulcn will use your system browser.\"),\n );\n } else if (status.playwrightChromium) {\n console.log(\n chalk.green(\"✅ Ready to use! Vulcn will use Playwright Chromium.\"),\n );\n } else {\n console.log(chalk.yellow(\"⚠️ No browsers found.\"));\n console.log();\n console.log(chalk.white(\"Options:\"));\n console.log(chalk.gray(\" 1. Install Google Chrome (recommended)\"));\n console.log(chalk.gray(\" 2. Run: vulcn install\"));\n }\n } catch (err) {\n spinner.fail(\"Failed to check browsers\");\n console.error(chalk.red(String(err)));\n process.exit(1);\n }\n}\n","/**\n * vulcn init - Create vulcn.config.yml\n */\n\nimport { existsSync } from \"node:fs\";\nimport { writeFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport YAML from \"yaml\";\n\ninterface InitOptions {\n force?: boolean;\n}\n\nconst DEFAULT_CONFIG = {\n version: \"1\",\n plugins: [\n {\n name: \"@vulcn/plugin-payloads\",\n config: {\n builtin: true,\n },\n },\n {\n name: \"@vulcn/plugin-detect-xss\",\n config: {\n detectDialogs: true,\n detectConsole: true,\n severity: \"high\",\n },\n },\n ],\n settings: {\n browser: \"chromium\",\n headless: true,\n },\n};\n\nexport async function initCommand(options: InitOptions) {\n const configFile = resolve(process.cwd(), \"vulcn.config.yml\");\n\n // Check if config already exists\n if (existsSync(configFile) && !options.force) {\n console.log(\n chalk.yellow(\n \"⚠️ vulcn.config.yml already exists. Use --force to overwrite.\",\n ),\n );\n process.exit(1);\n }\n\n const spinner = ora(\"Creating vulcn.config.yml...\").start();\n\n try {\n const yamlContent = YAML.stringify(DEFAULT_CONFIG, {\n indent: 2,\n lineWidth: 120,\n });\n\n // Add helpful comments\n const content = `# Vulcn Configuration\n# Docs: https://docs.vulcn.dev/config\n\n${yamlContent}`;\n\n await writeFile(configFile, content, \"utf-8\");\n spinner.succeed(\"Created vulcn.config.yml\");\n\n console.log();\n console.log(chalk.cyan(\"📁 Configuration created\"));\n console.log();\n console.log(chalk.gray(\"Next steps:\"));\n console.log(chalk.gray(\" 1. Record a session:\"));\n console.log(\n chalk.white(\" vulcn record https://example.com -o session.vulcn.yml\"),\n );\n console.log();\n console.log(chalk.gray(\" 2. Run security tests:\"));\n console.log(chalk.white(\" vulcn run session.vulcn.yml\"));\n console.log();\n console.log(chalk.gray(\" 3. Customize payloads:\"));\n console.log(\n chalk.white(\n \" vulcn run session.vulcn.yml --payload xss-basic sqli-basic\",\n ),\n );\n console.log();\n } catch (err) {\n spinner.fail(\"Failed to create config\");\n console.error(chalk.red(String(err)));\n process.exit(1);\n }\n}\n","/**\n * vulcn plugin - Plugin management commands\n */\n\nimport { existsSync } from \"node:fs\";\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport YAML from \"yaml\";\n\ninterface PluginConfig {\n name: string;\n config?: Record<string, unknown>;\n enabled?: boolean;\n}\n\ninterface VulcnConfig {\n version: string;\n plugins?: PluginConfig[];\n settings?: Record<string, unknown>;\n}\n\nconst CONFIG_FILES = [\n \"vulcn.config.yml\",\n \"vulcn.config.yaml\",\n \"vulcn.config.json\",\n \".vulcnrc.yml\",\n \".vulcnrc.yaml\",\n \".vulcnrc.json\",\n];\n\n/**\n * Find and load the config file\n */\nasync function loadConfigFile(): Promise<{\n path: string;\n config: VulcnConfig;\n} | null> {\n for (const file of CONFIG_FILES) {\n const configPath = resolve(process.cwd(), file);\n if (existsSync(configPath)) {\n const content = await readFile(configPath, \"utf-8\");\n const config = file.endsWith(\".json\")\n ? JSON.parse(content)\n : YAML.parse(content);\n return { path: configPath, config };\n }\n }\n return null;\n}\n\n/**\n * Save config back to file\n */\nasync function saveConfigFile(\n path: string,\n config: VulcnConfig,\n): Promise<void> {\n const isJson = path.endsWith(\".json\");\n const content = isJson\n ? JSON.stringify(config, null, 2)\n : `# Vulcn Configuration\\n# Docs: https://docs.vulcn.dev/config\\n\\n${YAML.stringify(config, { indent: 2 })}`;\n await writeFile(path, content, \"utf-8\");\n}\n\n/**\n * vulcn plugin list - Show loaded plugins\n */\nexport async function pluginListCommand() {\n const result = await loadConfigFile();\n\n if (!result) {\n console.log(chalk.yellow(\"No vulcn.config.yml found.\"));\n console.log(chalk.gray(\"Run 'vulcn init' to create one.\"));\n return;\n }\n\n const { config } = result;\n const plugins = config.plugins || [];\n\n if (plugins.length === 0) {\n console.log(chalk.yellow(\"No plugins configured.\"));\n console.log(chalk.gray(\"Run 'vulcn plugin add <name>' to add a plugin.\"));\n return;\n }\n\n console.log(chalk.cyan(\"📦 Configured Plugins\\n\"));\n\n for (const plugin of plugins) {\n const status =\n plugin.enabled === false ? chalk.gray(\"(disabled)\") : chalk.green(\"✓\");\n const name =\n plugin.enabled === false\n ? chalk.gray(plugin.name)\n : chalk.white(plugin.name);\n console.log(` ${status} ${name}`);\n\n if (plugin.config && Object.keys(plugin.config).length > 0) {\n for (const [key, value] of Object.entries(plugin.config)) {\n console.log(chalk.gray(` ${key}: ${JSON.stringify(value)}`));\n }\n }\n }\n\n console.log();\n}\n\ninterface AddOptions {\n config?: string;\n}\n\n/**\n * vulcn plugin add <name> - Add a plugin to config\n */\nexport async function pluginAddCommand(name: string, options: AddOptions) {\n const spinner = ora(`Adding plugin ${name}...`).start();\n\n // Load existing config\n let result = await loadConfigFile();\n\n if (!result) {\n spinner.fail(\"No vulcn.config.yml found. Run 'vulcn init' first.\");\n process.exit(1);\n }\n\n const { path: configPath, config } = result;\n\n // Check if plugin already exists\n const plugins = config.plugins || [];\n const existing = plugins.find((p) => p.name === name);\n\n if (existing) {\n if (existing.enabled === false) {\n // Re-enable the plugin\n existing.enabled = true;\n await saveConfigFile(configPath, config);\n spinner.succeed(`Re-enabled plugin: ${chalk.cyan(name)}`);\n } else {\n spinner.warn(`Plugin ${chalk.cyan(name)} is already configured.`);\n }\n return;\n }\n\n // Add the new plugin\n const newPlugin: PluginConfig = { name };\n\n // Parse config option if provided\n if (options.config) {\n try {\n newPlugin.config = JSON.parse(options.config);\n } catch {\n spinner.fail(`Invalid config JSON: ${options.config}`);\n process.exit(1);\n }\n }\n\n config.plugins = [...plugins, newPlugin];\n await saveConfigFile(configPath, config);\n\n spinner.succeed(`Added plugin: ${chalk.cyan(name)}`);\n console.log(\n chalk.gray(\n `\\nPlugin will be loaded on next 'vulcn run' or 'vulcn record'.`,\n ),\n );\n}\n\n/**\n * vulcn plugin remove <name> - Remove a plugin from config\n */\nexport async function pluginRemoveCommand(name: string) {\n const spinner = ora(`Removing plugin ${name}...`).start();\n\n const result = await loadConfigFile();\n\n if (!result) {\n spinner.fail(\"No vulcn.config.yml found.\");\n process.exit(1);\n }\n\n const { path: configPath, config } = result;\n const plugins = config.plugins || [];\n\n const index = plugins.findIndex((p) => p.name === name);\n\n if (index === -1) {\n spinner.warn(`Plugin ${chalk.cyan(name)} is not configured.`);\n return;\n }\n\n // Remove the plugin\n plugins.splice(index, 1);\n config.plugins = plugins;\n await saveConfigFile(configPath, config);\n\n spinner.succeed(`Removed plugin: ${chalk.cyan(name)}`);\n}\n\ninterface EnableDisableOptions {\n // Future: could add options here\n}\n\n/**\n * vulcn plugin enable <name> - Enable a disabled plugin\n */\nexport async function pluginEnableCommand(\n name: string,\n _options: EnableDisableOptions,\n) {\n const spinner = ora(`Enabling plugin ${name}...`).start();\n\n const result = await loadConfigFile();\n\n if (!result) {\n spinner.fail(\"No vulcn.config.yml found.\");\n process.exit(1);\n }\n\n const { path: configPath, config } = result;\n const plugins = config.plugins || [];\n\n const plugin = plugins.find((p) => p.name === name);\n\n if (!plugin) {\n spinner.fail(\n `Plugin ${chalk.cyan(name)} is not configured. Use 'vulcn plugin add ${name}' first.`,\n );\n process.exit(1);\n }\n\n if (plugin.enabled !== false) {\n spinner.info(`Plugin ${chalk.cyan(name)} is already enabled.`);\n return;\n }\n\n plugin.enabled = true;\n await saveConfigFile(configPath, config);\n\n spinner.succeed(`Enabled plugin: ${chalk.cyan(name)}`);\n}\n\n/**\n * vulcn plugin disable <name> - Disable a plugin without removing it\n */\nexport async function pluginDisableCommand(\n name: string,\n _options: EnableDisableOptions,\n) {\n const spinner = ora(`Disabling plugin ${name}...`).start();\n\n const result = await loadConfigFile();\n\n if (!result) {\n spinner.fail(\"No vulcn.config.yml found.\");\n process.exit(1);\n }\n\n const { path: configPath, config } = result;\n const plugins = config.plugins || [];\n\n const plugin = plugins.find((p) => p.name === name);\n\n if (!plugin) {\n spinner.fail(`Plugin ${chalk.cyan(name)} is not configured.`);\n process.exit(1);\n }\n\n if (plugin.enabled === false) {\n spinner.info(`Plugin ${chalk.cyan(name)} is already disabled.`);\n return;\n }\n\n plugin.enabled = false;\n await saveConfigFile(configPath, config);\n\n spinner.succeed(`Disabled plugin: ${chalk.cyan(name)}`);\n}\n"],"mappings":"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","names":["resolve","DriverManager","browserDriver","chalk","ora","chalk","chalk","ora","writeFile","chalk","ora","existsSync","readFile","writeFile","resolve","chalk","ora","YAML"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "vulcn",
3
- "version": "0.3.0",
4
- "description": "Security testing CLI - Record once, test with payloads, find vulnerabilities",
3
+ "version": "0.3.2",
4
+ "description": "Modern, fast penetration testing CLI record browser interactions once, replay with security payloads, and find vulnerabilities like XSS and SQLi automatically. A lightweight, pluggable alternative to legacy security scanners.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "vulcn": "./vulcn.mjs"
@@ -14,30 +14,36 @@
14
14
  "LICENSE",
15
15
  "README.md"
16
16
  ],
17
- "scripts": {
18
- "build": "tsup",
19
- "dev": "tsup --watch",
20
- "clean": "rm -rf dist vulcn.mjs LICENSE README.md CHANGELOG.md",
21
- "typecheck": "tsc --noEmit",
22
- "prepack": "cp ../vulcn.mjs ../LICENSE ../README.md ../CHANGELOG.md .",
23
- "postpack": "rm -f vulcn.mjs LICENSE README.md CHANGELOG.md",
24
- "prepublishOnly": "npm run build"
25
- },
26
17
  "keywords": [
27
18
  "vulcn",
28
- "security",
29
- "testing",
30
- "cli",
31
- "recorder",
32
- "xss",
33
- "sql-injection",
19
+ "security-testing",
34
20
  "penetration-testing",
35
21
  "pentest",
36
- "vulnerability",
37
- "scanner",
22
+ "dast",
23
+ "web-security",
24
+ "vulnerability-scanner",
25
+ "security-scanner",
26
+ "xss",
27
+ "xss-detection",
28
+ "sql-injection",
29
+ "sqli",
30
+ "owasp",
31
+ "owasp-top-10",
32
+ "web-application-security",
33
+ "appsec",
34
+ "application-security",
35
+ "security-automation",
36
+ "browser-automation",
38
37
  "playwright",
39
- "browser",
40
- "automation"
38
+ "security-cli",
39
+ "pentest-tool",
40
+ "pentest-framework",
41
+ "vulnerability-detection",
42
+ "dynamic-analysis",
43
+ "payload-testing",
44
+ "security-audit",
45
+ "web-scanner",
46
+ "bug-bounty"
41
47
  ],
42
48
  "author": "rawlab",
43
49
  "license": "AGPL-3.0",
@@ -46,7 +52,7 @@
46
52
  "url": "git+https://github.com/vulcnize/vulcn.git",
47
53
  "directory": "cli"
48
54
  },
49
- "homepage": "https://rawlab.dev/vulcn",
55
+ "homepage": "https://docs.vulcn.dev",
50
56
  "bugs": {
51
57
  "url": "https://github.com/vulcnize/vulcn/issues"
52
58
  },
@@ -62,17 +68,25 @@
62
68
  "access": "public"
63
69
  },
64
70
  "dependencies": {
65
- "@vulcn/engine": "workspace:*",
66
- "@vulcn/plugin-payloads": "workspace:*",
67
- "@vulcn/plugin-detect-xss": "workspace:*",
68
71
  "commander": "^13.1.0",
69
72
  "chalk": "^5.4.0",
70
73
  "ora": "^8.2.0",
71
- "yaml": "^2.7.0"
74
+ "yaml": "^2.7.0",
75
+ "@vulcn/engine": "0.3.2",
76
+ "@vulcn/driver-browser": "0.1.2",
77
+ "@vulcn/plugin-detect-xss": "0.2.1",
78
+ "@vulcn/plugin-payloads": "0.2.1",
79
+ "@vulcn/plugin-report": "0.1.1"
72
80
  },
73
81
  "devDependencies": {
74
82
  "typescript": "^5.7.0",
75
83
  "tsup": "^8.4.0",
76
84
  "@types/node": "^22.0.0"
85
+ },
86
+ "scripts": {
87
+ "build": "tsup",
88
+ "dev": "tsup --watch",
89
+ "clean": "rm -rf dist vulcn.mjs LICENSE README.md CHANGELOG.md",
90
+ "typecheck": "tsc --noEmit"
77
91
  }
78
- }
92
+ }