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 +65 -0
- package/dist/index.js +51 -34
- package/dist/index.js.map +1 -1
- package/package.json +41 -27
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 {
|
|
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
|
|
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
|
|
42
|
-
const yaml =
|
|
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 ${
|
|
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
|
-
|
|
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
|
|
190
|
-
|
|
191
|
-
{
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
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/
|
|
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://
|
|
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://
|
|
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.
|
|
4
|
-
"description": "
|
|
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
|
-
"
|
|
37
|
-
"
|
|
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
|
-
"
|
|
40
|
-
"
|
|
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://
|
|
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
|
+
}
|