vulcn 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,28 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.1.0] - 2026-02-05
9
+
10
+ ### Added
11
+
12
+ - Initial release of Vulcn - Security testing recorder & runner
13
+ - **Session Recording** - Record browser interactions (clicks, form fills, navigation)
14
+ - **Session Replay** - Replay sessions with security payloads injected
15
+ - **Smart Browser Detection** - Uses system Chrome/Edge first, Playwright fallback
16
+ - **Built-in Payloads** - XSS and SQL injection payload sets
17
+ - **YAML Sessions** - Human-readable session format with Zod validation
18
+ - **Cross-Platform** - macOS, Linux, and Windows support
19
+
20
+ ### CLI Commands
21
+
22
+ - `vulcn record` - Record browser interactions
23
+ - `vulcn run` - Replay session with payloads
24
+ - `vulcn payloads` - List available payloads
25
+ - `vulcn doctor` - Check browser availability
26
+ - `vulcn install` - Install Playwright browsers
27
+
28
+ [0.1.0]: https://github.com/rawlab-dev/vulcn/releases/tag/v0.1.0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 rawlab
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,227 @@
1
+ # 🔐 Vulcn
2
+
3
+ **Security testing made simple.** Record once, test with payloads, find vulnerabilities.
4
+
5
+ [![CI](https://github.com/rawlab-dev/vulcn/actions/workflows/ci.yml/badge.svg)](https://github.com/rawlab-dev/vulcn/actions/workflows/ci.yml)
6
+ [![npm version](https://img.shields.io/npm/v/vulcn.svg)](https://www.npmjs.com/package/vulcn)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
8
+
9
+ ---
10
+
11
+ ## ⚡ Quick Start
12
+
13
+ ```bash
14
+ # Install globally
15
+ npm install -g vulcn
16
+
17
+ # Record a session
18
+ vulcn record --url https://example.com/login
19
+
20
+ # Run with XSS payloads
21
+ vulcn run session.vulcn.yml --payload xss-basic
22
+ ```
23
+
24
+ **Zero-config browser support** — Vulcn uses your existing Chrome or Edge. No browser downloads needed.
25
+
26
+ ---
27
+
28
+ ## 🎯 What is Vulcn?
29
+
30
+ Vulcn is a security testing tool that:
31
+
32
+ 1. **Records** your browser interactions (clicks, form inputs, navigation)
33
+ 2. **Replays** them with security payloads injected into input fields
34
+ 3. **Detects** vulnerabilities like XSS and SQL injection
35
+
36
+ Think of it as **Playwright + Burp Suite**, but simpler and focused on automated payload testing.
37
+
38
+ ---
39
+
40
+ ## 🚀 Features
41
+
42
+ | Feature | Description |
43
+ | --------------------- | --------------------------------------------------- |
44
+ | 🎬 **Record** | Capture browser sessions as replayable YAML files |
45
+ | 🔍 **Test** | Inject XSS, SQLi, and custom payloads automatically |
46
+ | 🌐 **Cross-platform** | Works on macOS, Linux, and Windows |
47
+ | 🚫 **Zero-config** | Uses system Chrome/Edge by default |
48
+ | 📊 **CI/CD Ready** | Exit codes for pipeline integration |
49
+ | 🔧 **Extensible** | Add custom payloads and detection patterns |
50
+
51
+ ---
52
+
53
+ ## 📦 Installation
54
+
55
+ ### CLI
56
+
57
+ ```bash
58
+ npm install -g vulcn
59
+ ```
60
+
61
+ ### Programmatic API
62
+
63
+ ```bash
64
+ npm install @vulcn/engine
65
+ ```
66
+
67
+ ```typescript
68
+ import { Recorder, Runner, parseSession } from "@vulcn/engine";
69
+
70
+ // Record programmatically
71
+ const session = await Recorder.start("https://example.com");
72
+ // ... user interacts ...
73
+ const recorded = await session.stop();
74
+
75
+ // Run with payloads
76
+ const result = await Runner.execute(recorded, ["xss-basic"]);
77
+ console.log(result.findings);
78
+ ```
79
+
80
+ ---
81
+
82
+ ## 🎬 Recording
83
+
84
+ Start recording a session:
85
+
86
+ ```bash
87
+ vulcn record --url https://target.com/login
88
+ ```
89
+
90
+ Options:
91
+
92
+ - `--url, -u` — Start URL (required)
93
+ - `--output, -o` — Output file (default: `session.vulcn.yml`)
94
+ - `--browser, -b` — Browser (`chromium`, `firefox`, `webkit`)
95
+ - `--headless` — Run headless
96
+
97
+ When recording:
98
+
99
+ 1. Browser opens to your start URL
100
+ 2. Interact normally (fill forms, click buttons)
101
+ 3. Press `Ctrl+C` to stop and save
102
+
103
+ ---
104
+
105
+ ## 🔍 Running Tests
106
+
107
+ Run a recorded session with payloads:
108
+
109
+ ```bash
110
+ vulcn run session.vulcn.yml --payload xss-basic --payload sqli-basic
111
+ ```
112
+
113
+ Options:
114
+
115
+ - `--payload, -p` — Payload to use (can specify multiple)
116
+ - `--headless` — Run headless (default: true)
117
+ - `--browser, -b` — Browser to use
118
+
119
+ ### Built-in Payloads
120
+
121
+ | Payload | Category | Description |
122
+ | ------------ | -------- | ------------------------------ |
123
+ | `xss-basic` | XSS | Script tags and event handlers |
124
+ | `xss-event` | XSS | Event handler injection |
125
+ | `xss-svg` | XSS | SVG-based XSS |
126
+ | `sqli-basic` | SQLi | Basic SQL injection |
127
+ | `sqli-error` | SQLi | Error-based SQLi detection |
128
+ | `sqli-blind` | SQLi | Blind SQLi payloads |
129
+
130
+ List all payloads:
131
+
132
+ ```bash
133
+ vulcn payloads
134
+ ```
135
+
136
+ ---
137
+
138
+ ## 📄 Session Format
139
+
140
+ Sessions are stored as YAML:
141
+
142
+ ```yaml
143
+ version: "1"
144
+ name: Login Test
145
+ recordedAt: "2026-02-05T12:00:00Z"
146
+ browser: chromium
147
+ viewport:
148
+ width: 1280
149
+ height: 720
150
+ startUrl: https://example.com/login
151
+ steps:
152
+ - id: step_001
153
+ type: navigate
154
+ url: https://example.com/login
155
+ timestamp: 0
156
+ - id: step_002
157
+ type: input
158
+ selector: input[name="username"]
159
+ value: testuser
160
+ injectable: true
161
+ timestamp: 1500
162
+ - id: step_003
163
+ type: click
164
+ selector: button[type="submit"]
165
+ timestamp: 3000
166
+ ```
167
+
168
+ ---
169
+
170
+ ## 🩺 Browser Management
171
+
172
+ Check available browsers:
173
+
174
+ ```bash
175
+ vulcn doctor
176
+ ```
177
+
178
+ Install Playwright browsers (if needed):
179
+
180
+ ```bash
181
+ vulcn install chromium
182
+ vulcn install --all # Install all browsers
183
+ ```
184
+
185
+ ---
186
+
187
+ ## 🔧 CI/CD Integration
188
+
189
+ Vulcn returns exit code `1` when vulnerabilities are found:
190
+
191
+ ```yaml
192
+ # GitHub Actions example
193
+ - name: Security Test
194
+ run: |
195
+ npm install -g vulcn
196
+ vulcn run tests/login.vulcn.yml --payload xss-basic --headless
197
+ ```
198
+
199
+ ---
200
+
201
+ ## 📚 Documentation
202
+
203
+ - [Contributing Guide](./CONTRIBUTING.md)
204
+ - [Security Policy](./SECURITY.md)
205
+
206
+ ---
207
+
208
+ ## 🛣️ Roadmap
209
+
210
+ - [ ] HTML/JSON reports
211
+ - [ ] Custom payload definitions
212
+ - [ ] SSRF and path traversal payloads
213
+ - [ ] Authenticated session support
214
+ - [ ] API endpoint testing
215
+ - [ ] Vulnerability severity scoring
216
+
217
+ ---
218
+
219
+ ## 📝 License
220
+
221
+ [MIT](./LICENSE) © [rawlab](https://rawlab.dev)
222
+
223
+ ---
224
+
225
+ <p align="center">
226
+ Made with ❤️ by <a href="https://rawlab.dev">rawlab</a>
227
+ </p>
package/dist/index.js ADDED
@@ -0,0 +1,291 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import { Command } from "commander";
5
+
6
+ // src/record.ts
7
+ import { writeFile } from "fs/promises";
8
+ import { Recorder, serializeSession } from "@vulcn/engine";
9
+ import chalk from "chalk";
10
+ import ora from "ora";
11
+ async function recordCommand(options) {
12
+ const spinner = ora("Starting browser...").start();
13
+ try {
14
+ const session = await Recorder.start(options.url, {
15
+ browser: options.browser,
16
+ headless: options.headless
17
+ });
18
+ spinner.succeed("Browser started");
19
+ console.log();
20
+ console.log(chalk.cyan("\u{1F3AC} Recording started"));
21
+ console.log(chalk.gray(` URL: ${options.url}`));
22
+ console.log(chalk.gray(` Browser: ${options.browser}`));
23
+ console.log();
24
+ console.log(
25
+ chalk.yellow(" Interact with the browser to record actions.")
26
+ );
27
+ console.log(chalk.yellow(" Press Ctrl+C to stop recording."));
28
+ console.log();
29
+ if (process.stdin.isTTY) {
30
+ process.stdin.setRawMode(true);
31
+ }
32
+ process.stdin.resume();
33
+ process.stdin.setEncoding("utf8");
34
+ let stopped = false;
35
+ const stopRecording = async () => {
36
+ if (stopped) return;
37
+ stopped = true;
38
+ console.log();
39
+ const saveSpinner = ora("Stopping recording...").start();
40
+ try {
41
+ const result = await session.stop();
42
+ const yaml = serializeSession(result);
43
+ await writeFile(options.output, yaml, "utf-8");
44
+ saveSpinner.succeed(`Session saved to ${chalk.green(options.output)}`);
45
+ console.log();
46
+ console.log(chalk.cyan(`\u{1F4DD} Recorded ${result.steps.length} steps`));
47
+ console.log();
48
+ console.log(chalk.gray("To run with payloads:"));
49
+ console.log(
50
+ chalk.white(` vulcn run ${options.output} --payload xss-basic`)
51
+ );
52
+ } catch (err) {
53
+ saveSpinner.fail("Failed to save session");
54
+ console.error(chalk.red(String(err)));
55
+ process.exit(1);
56
+ }
57
+ };
58
+ await new Promise((resolve) => {
59
+ const handleStop = () => {
60
+ process.stdin.removeAllListeners("data");
61
+ process.off("SIGINT", handleStop);
62
+ process.off("SIGTERM", handleStop);
63
+ stopRecording().then(() => {
64
+ resolve();
65
+ }).catch((err) => {
66
+ console.error(chalk.red(String(err)));
67
+ process.exit(1);
68
+ });
69
+ };
70
+ process.stdin.on("data", (key) => {
71
+ if (key === "") {
72
+ handleStop();
73
+ }
74
+ });
75
+ process.on("SIGINT", handleStop);
76
+ process.on("SIGTERM", handleStop);
77
+ });
78
+ } catch (err) {
79
+ spinner.fail("Failed to start recording");
80
+ console.error(chalk.red(String(err)));
81
+ process.exit(1);
82
+ }
83
+ }
84
+
85
+ // src/run.ts
86
+ import { readFile } from "fs/promises";
87
+ import {
88
+ Runner,
89
+ parseSession
90
+ } from "@vulcn/engine";
91
+ import chalk2 from "chalk";
92
+ import ora2 from "ora";
93
+ async function runCommand(sessionFile, options) {
94
+ const loadSpinner = ora2("Loading session...").start();
95
+ let sessionYaml;
96
+ try {
97
+ sessionYaml = await readFile(sessionFile, "utf-8");
98
+ } catch {
99
+ loadSpinner.fail(`Cannot read file: ${sessionFile}`);
100
+ process.exit(1);
101
+ }
102
+ let session;
103
+ try {
104
+ session = parseSession(sessionYaml);
105
+ loadSpinner.succeed(`Loaded session: ${chalk2.cyan(session.name)}`);
106
+ } catch (err) {
107
+ loadSpinner.fail("Invalid session file");
108
+ console.error(chalk2.red(String(err)));
109
+ process.exit(1);
110
+ }
111
+ const payloads = options.payload ?? ["xss-basic"];
112
+ console.log();
113
+ console.log(chalk2.cyan("\u{1F50D} Running security tests"));
114
+ console.log(chalk2.gray(` Session: ${session.name}`));
115
+ console.log(chalk2.gray(` Payloads: ${payloads.join(", ")}`));
116
+ console.log(chalk2.gray(` Browser: ${options.browser}`));
117
+ console.log(chalk2.gray(` Headless: ${options.headless}`));
118
+ console.log();
119
+ const runSpinner = ora2("Executing tests...").start();
120
+ try {
121
+ const result = await Runner.execute(session, payloads, {
122
+ browser: options.browser,
123
+ headless: options.headless,
124
+ onFinding: (finding) => {
125
+ runSpinner.stop();
126
+ console.log(chalk2.red(`\u26A0\uFE0F FINDING: ${finding.title}`));
127
+ console.log(chalk2.gray(` Step: ${finding.stepId}`));
128
+ console.log(
129
+ chalk2.gray(` Payload: ${finding.payload.slice(0, 50)}...`)
130
+ );
131
+ console.log(chalk2.gray(` URL: ${finding.url}`));
132
+ console.log();
133
+ runSpinner.start("Continuing tests...");
134
+ }
135
+ });
136
+ runSpinner.succeed("Tests completed");
137
+ console.log();
138
+ console.log(chalk2.cyan("\u{1F4CA} Results"));
139
+ console.log(chalk2.gray(` Steps executed: ${result.stepsExecuted}`));
140
+ console.log(chalk2.gray(` Payloads tested: ${result.payloadsTested}`));
141
+ console.log(
142
+ chalk2.gray(` Duration: ${(result.duration / 1e3).toFixed(1)}s`)
143
+ );
144
+ console.log();
145
+ if (result.findings.length > 0) {
146
+ console.log(chalk2.red(`\u{1F6A8} ${result.findings.length} findings detected!`));
147
+ console.log();
148
+ for (const finding of result.findings) {
149
+ const severityColor = finding.severity === "critical" || finding.severity === "high" ? chalk2.red : finding.severity === "medium" ? chalk2.yellow : chalk2.gray;
150
+ console.log(
151
+ severityColor(`[${finding.severity.toUpperCase()}] ${finding.title}`)
152
+ );
153
+ console.log(chalk2.gray(` Type: ${finding.type}`));
154
+ console.log(chalk2.gray(` Step: ${finding.stepId}`));
155
+ console.log(chalk2.gray(` URL: ${finding.url}`));
156
+ console.log(chalk2.gray(` Payload: ${finding.payload}`));
157
+ console.log();
158
+ }
159
+ process.exit(1);
160
+ } else {
161
+ console.log(chalk2.green("\u2705 No vulnerabilities detected"));
162
+ }
163
+ if (result.errors.length > 0) {
164
+ console.log();
165
+ console.log(
166
+ chalk2.yellow(`\u26A0\uFE0F ${result.errors.length} errors during execution:`)
167
+ );
168
+ for (const err of result.errors.slice(0, 5)) {
169
+ console.log(chalk2.gray(` - ${err}`));
170
+ }
171
+ if (result.errors.length > 5) {
172
+ console.log(chalk2.gray(` ... and ${result.errors.length - 5} more`));
173
+ }
174
+ }
175
+ } catch (err) {
176
+ runSpinner.fail("Test execution failed");
177
+ console.error(chalk2.red(String(err)));
178
+ process.exit(1);
179
+ }
180
+ }
181
+
182
+ // src/payloads.ts
183
+ import { BUILTIN_PAYLOADS } from "@vulcn/engine";
184
+ import chalk3 from "chalk";
185
+ async function payloadsCommand() {
186
+ console.log();
187
+ console.log(chalk3.cyan("\u{1F4E6} Available Payloads"));
188
+ console.log();
189
+ const payloads = Object.values(BUILTIN_PAYLOADS);
190
+ for (const payload of payloads) {
191
+ console.log(chalk3.white(` ${payload.name}`));
192
+ console.log(chalk3.gray(` Category: ${payload.category}`));
193
+ console.log(chalk3.gray(` ${payload.description}`));
194
+ console.log(chalk3.gray(` Payloads: ${payload.payloads.length}`));
195
+ console.log();
196
+ }
197
+ console.log(chalk3.gray("Usage:"));
198
+ console.log(chalk3.white(" vulcn run session.vulcn.yml --payload xss-basic"));
199
+ }
200
+
201
+ // src/install.ts
202
+ import { installBrowsers, checkBrowsers } from "@vulcn/engine";
203
+ import chalk4 from "chalk";
204
+ import ora3 from "ora";
205
+ async function installCommand(browsers, options) {
206
+ let browsersToInstall;
207
+ if (options?.all) {
208
+ browsersToInstall = ["chromium", "firefox", "webkit"];
209
+ } else if (browsers && browsers.length > 0) {
210
+ browsersToInstall = browsers;
211
+ } else {
212
+ browsersToInstall = ["chromium"];
213
+ }
214
+ console.log();
215
+ console.log(chalk4.cyan("\u{1F527} Installing browsers for Vulcn"));
216
+ console.log();
217
+ try {
218
+ await installBrowsers(browsersToInstall);
219
+ console.log();
220
+ console.log(chalk4.green("\u2705 Browsers installed successfully"));
221
+ } catch (err) {
222
+ console.error(chalk4.red("Failed to install browsers:"), err);
223
+ process.exit(1);
224
+ }
225
+ }
226
+ async function doctorCommand() {
227
+ console.log();
228
+ console.log(chalk4.cyan("\u{1FA7A} Vulcn Browser Check"));
229
+ console.log();
230
+ const spinner = ora3("Checking available browsers...").start();
231
+ try {
232
+ const status = await checkBrowsers();
233
+ spinner.stop();
234
+ console.log(chalk4.white("System Browsers:"));
235
+ console.log(
236
+ ` Chrome: ${status.systemChrome ? chalk4.green("\u2713 Available") : chalk4.gray("\u2717 Not found")}`
237
+ );
238
+ console.log(
239
+ ` Edge: ${status.systemEdge ? chalk4.green("\u2713 Available") : chalk4.gray("\u2717 Not found")}`
240
+ );
241
+ console.log();
242
+ console.log(chalk4.white("Playwright Browsers:"));
243
+ console.log(
244
+ ` Chromium: ${status.playwrightChromium ? chalk4.green("\u2713 Installed") : chalk4.gray("\u2717 Not installed")}`
245
+ );
246
+ console.log(
247
+ ` Firefox: ${status.playwrightFirefox ? chalk4.green("\u2713 Installed") : chalk4.gray("\u2717 Not installed")}`
248
+ );
249
+ console.log(
250
+ ` WebKit: ${status.playwrightWebkit ? chalk4.green("\u2713 Installed") : chalk4.gray("\u2717 Not installed")}`
251
+ );
252
+ console.log();
253
+ if (status.systemChrome || status.systemEdge) {
254
+ console.log(
255
+ chalk4.green("\u2705 Ready to use! Vulcn will use your system browser.")
256
+ );
257
+ } else if (status.playwrightChromium) {
258
+ console.log(
259
+ chalk4.green("\u2705 Ready to use! Vulcn will use Playwright Chromium.")
260
+ );
261
+ } else {
262
+ console.log(chalk4.yellow("\u26A0\uFE0F No browsers found."));
263
+ console.log();
264
+ console.log(chalk4.white("Options:"));
265
+ console.log(chalk4.gray(" 1. Install Google Chrome (recommended)"));
266
+ console.log(chalk4.gray(" 2. Run: vulcn install"));
267
+ }
268
+ } catch (err) {
269
+ spinner.fail("Failed to check browsers");
270
+ console.error(chalk4.red(String(err)));
271
+ process.exit(1);
272
+ }
273
+ }
274
+
275
+ // src/index.ts
276
+ var program = new Command();
277
+ program.name("vulcn").description("Security testing recorder & runner").version("0.1.0");
278
+ program.command("record").description("Record browser interactions").requiredOption("-u, --url <url>", "Starting URL to record from").option("-o, --output <file>", "Output file path", "session.vulcn.yml").option(
279
+ "-b, --browser <browser>",
280
+ "Browser to use (chromium, firefox, webkit)",
281
+ "chromium"
282
+ ).option("--headless", "Run in headless mode", false).action(recordCommand);
283
+ program.command("run").description("Run a recorded session with payloads").argument("<session>", "Session file to run (.vulcn.yml)").option(
284
+ "-p, --payload <names...>",
285
+ "Payloads to use (e.g., xss-basic, sqli-basic)"
286
+ ).option("-b, --browser <browser>", "Browser to use", "chromium").option("--headless", "Run in headless mode", true).option("--no-headless", "Run with visible browser").action(runCommand);
287
+ program.command("payloads").description("List available payloads").action(payloadsCommand);
288
+ program.command("install").description("Install Playwright browsers").argument("[browsers...]", "Browsers to install (chromium, firefox, webkit)").option("--all", "Install all browsers").action(installCommand);
289
+ program.command("doctor").description("Check available browsers").action(doctorCommand);
290
+ program.parse();
291
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/record.ts","../src/run.ts","../src/payloads.ts","../src/install.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { recordCommand } from \"./record\";\nimport { runCommand } from \"./run\";\nimport { payloadsCommand } from \"./payloads\";\nimport { installCommand, doctorCommand } from \"./install\";\n\nconst program = new Command();\n\nprogram\n .name(\"vulcn\")\n .description(\"Security testing recorder & runner\")\n .version(\"0.1.0\");\n\n// vulcn record\nprogram\n .command(\"record\")\n .description(\"Record browser interactions\")\n .requiredOption(\"-u, --url <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(\"-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 .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\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 url: string;\n output: string;\n browser: string;\n headless: boolean;\n}\n\nexport async function recordCommand(options: RecordOptions) {\n const spinner = ora(\"Starting browser...\").start();\n\n try {\n const session = await Recorder.start(options.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: ${options.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 } from \"node:fs/promises\";\nimport {\n Runner,\n parseSession,\n type BrowserType,\n type PayloadName,\n} from \"@vulcn/engine\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\n\ninterface RunOptions {\n payload?: string[];\n browser: string;\n headless: boolean;\n}\n\nexport async function runCommand(sessionFile: string, options: RunOptions) {\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 // Validate payloads\n const payloads = (options.payload ?? [\"xss-basic\"]) as PayloadName[];\n console.log();\n console.log(chalk.cyan(\"🔍 Running security tests\"));\n console.log(chalk.gray(` Session: ${session.name}`));\n console.log(chalk.gray(` Payloads: ${payloads.join(\", \")}`));\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(session, payloads, {\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\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 { BUILTIN_PAYLOADS } from \"@vulcn/engine\";\nimport chalk from \"chalk\";\n\nexport async function payloadsCommand() {\n console.log();\n console.log(chalk.cyan(\"📦 Available Payloads\"));\n console.log();\n\n const payloads = Object.values(BUILTIN_PAYLOADS);\n\n for (const payload of payloads) {\n console.log(chalk.white(` ${payload.name}`));\n console.log(chalk.gray(` Category: ${payload.category}`));\n console.log(chalk.gray(` ${payload.description}`));\n console.log(chalk.gray(` Payloads: ${payload.payloads.length}`));\n console.log();\n }\n\n console.log(chalk.gray(\"Usage:\"));\n console.log(chalk.white(\" vulcn run session.vulcn.yml --payload xss-basic\"));\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"],"mappings":"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","names":["chalk","ora","chalk","chalk","ora"]}
package/package.json ADDED
@@ -0,0 +1,75 @@
1
+ {
2
+ "name": "vulcn",
3
+ "version": "0.1.0",
4
+ "description": "Security testing CLI - Record once, test with payloads, find vulnerabilities",
5
+ "type": "module",
6
+ "bin": {
7
+ "vulcn": "./vulcn.mjs"
8
+ },
9
+ "main": "./dist/index.js",
10
+ "files": [
11
+ "dist",
12
+ "vulcn.mjs",
13
+ "CHANGELOG.md",
14
+ "LICENSE",
15
+ "README.md"
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
+ "keywords": [
27
+ "vulcn",
28
+ "security",
29
+ "testing",
30
+ "cli",
31
+ "recorder",
32
+ "xss",
33
+ "sql-injection",
34
+ "penetration-testing",
35
+ "pentest",
36
+ "vulnerability",
37
+ "scanner",
38
+ "playwright",
39
+ "browser",
40
+ "automation"
41
+ ],
42
+ "author": "rawlab",
43
+ "license": "MIT",
44
+ "repository": {
45
+ "type": "git",
46
+ "url": "git+https://github.com/rawlab-dev/vulcn.git",
47
+ "directory": "cli"
48
+ },
49
+ "homepage": "https://rawlab.dev/vulcn",
50
+ "bugs": {
51
+ "url": "https://github.com/rawlab-dev/vulcn/issues"
52
+ },
53
+ "engines": {
54
+ "node": ">=18.0.0"
55
+ },
56
+ "os": [
57
+ "darwin",
58
+ "linux",
59
+ "win32"
60
+ ],
61
+ "publishConfig": {
62
+ "access": "public"
63
+ },
64
+ "dependencies": {
65
+ "@vulcn/engine": "workspace:*",
66
+ "commander": "^13.1.0",
67
+ "chalk": "^5.4.0",
68
+ "ora": "^8.2.0"
69
+ },
70
+ "devDependencies": {
71
+ "typescript": "^5.7.0",
72
+ "tsup": "^8.4.0",
73
+ "@types/node": "^22.0.0"
74
+ }
75
+ }
package/vulcn.mjs ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+
3
+ import module from "node:module";
4
+
5
+ // Enable Node.js module compile cache for faster startup
6
+ // https://nodejs.org/api/module.html#module-compile-cache
7
+ if (module.enableCompileCache && !process.env.NODE_DISABLE_COMPILE_CACHE) {
8
+ try {
9
+ module.enableCompileCache();
10
+ } catch {
11
+ // Ignore errors (older Node versions)
12
+ }
13
+ }
14
+
15
+ await import("./cli/dist/index.js");