blitzstrike 2.4.71 → 2.4.73
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 +34 -0
- package/dist/index.js +420 -177
- package/intelligence/hackbot-arena.json +339 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -15584,11 +15584,11 @@ var require_src = __commonJS(function(exports, module) {
|
|
|
15584
15584
|
});
|
|
15585
15585
|
|
|
15586
15586
|
// src/mcp-status.ts
|
|
15587
|
-
import { existsSync as
|
|
15587
|
+
import { existsSync as existsSync10 } from "node:fs";
|
|
15588
15588
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
15589
15589
|
async function checkMcpServers() {
|
|
15590
15590
|
const out = [];
|
|
15591
|
-
const bin = ["/usr/bin/chrome-devtools-mcp", "/usr/local/bin/chrome-devtools-mcp"].find((p) =>
|
|
15591
|
+
const bin = ["/usr/bin/chrome-devtools-mcp", "/usr/local/bin/chrome-devtools-mcp"].find((p) => existsSync10(p));
|
|
15592
15592
|
const npxOk = spawnSync3("npx", ["--version"], { timeout: 8000 }).error === undefined;
|
|
15593
15593
|
const devtoolsOk = Boolean(bin) || npxOk;
|
|
15594
15594
|
out.push({
|
|
@@ -17009,12 +17009,12 @@ $r = openai.chat.completions.create(['messages' => [['role' => 'user', 'content'
|
|
|
17009
17009
|
});
|
|
17010
17010
|
|
|
17011
17011
|
// src/variants.ts
|
|
17012
|
-
import { readFileSync as
|
|
17013
|
-
import { join as
|
|
17014
|
-
import { fileURLToPath as
|
|
17012
|
+
import { readFileSync as readFileSync20 } from "node:fs";
|
|
17013
|
+
import { join as join20, dirname as dirname5 } from "node:path";
|
|
17014
|
+
import { fileURLToPath as fileURLToPath11 } from "node:url";
|
|
17015
17015
|
function loadVariants() {
|
|
17016
17016
|
try {
|
|
17017
|
-
const doc = JSON.parse(
|
|
17017
|
+
const doc = JSON.parse(readFileSync20(join20(__dirname5, "..", "intelligence", "variants.json"), "utf8"));
|
|
17018
17018
|
return doc.variants ?? [];
|
|
17019
17019
|
} catch {
|
|
17020
17020
|
return [];
|
|
@@ -17065,18 +17065,18 @@ function variantCoverageText() {
|
|
|
17065
17065
|
return lines.join(`
|
|
17066
17066
|
`);
|
|
17067
17067
|
}
|
|
17068
|
-
var
|
|
17068
|
+
var __dirname5, CROSS_FILE_ONLY;
|
|
17069
17069
|
var init_variants = __esm(() => {
|
|
17070
17070
|
init_complex_bugs();
|
|
17071
|
-
|
|
17071
|
+
__dirname5 = dirname5(fileURLToPath11(import.meta.url));
|
|
17072
17072
|
CROSS_FILE_ONLY = new Set(["priv_esc"]);
|
|
17073
17073
|
});
|
|
17074
17074
|
|
|
17075
17075
|
// src/sync.ts
|
|
17076
|
-
import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync8, readFileSync as
|
|
17077
|
-
import { join as
|
|
17076
|
+
import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync8, readFileSync as readFileSync26, readdirSync as readdirSync7, statSync as statSync4, rmSync as rmSync4 } from "node:fs";
|
|
17077
|
+
import { join as join24 } from "node:path";
|
|
17078
17078
|
import { homedir as homedir10 } from "node:os";
|
|
17079
|
-
import { fileURLToPath as
|
|
17079
|
+
import { fileURLToPath as fileURLToPath13 } from "node:url";
|
|
17080
17080
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
17081
17081
|
function dirExists(p) {
|
|
17082
17082
|
try {
|
|
@@ -17091,7 +17091,7 @@ function countFiles(dir) {
|
|
|
17091
17091
|
const walk = (d) => {
|
|
17092
17092
|
for (const e of readdirSync7(d, { withFileTypes: true })) {
|
|
17093
17093
|
if (e.isDirectory())
|
|
17094
|
-
walk(
|
|
17094
|
+
walk(join24(d, e.name));
|
|
17095
17095
|
else
|
|
17096
17096
|
n++;
|
|
17097
17097
|
}
|
|
@@ -17105,8 +17105,8 @@ function countFiles(dir) {
|
|
|
17105
17105
|
function syncData() {
|
|
17106
17106
|
if (!dirExists(DATA_ROOT2))
|
|
17107
17107
|
mkdirSync9(DATA_ROOT2, { recursive: true });
|
|
17108
|
-
const payloadsPath =
|
|
17109
|
-
const templatesPath =
|
|
17108
|
+
const payloadsPath = join24(DATA_ROOT2, "payloads");
|
|
17109
|
+
const templatesPath = join24(DATA_ROOT2, "templates");
|
|
17110
17110
|
const hasPayloads = dirExists(payloadsPath) && countFiles(payloadsPath) > 0;
|
|
17111
17111
|
const hasTemplates = dirExists(templatesPath) && countFiles(templatesPath) > 0;
|
|
17112
17112
|
if (hasPayloads && hasTemplates) {
|
|
@@ -17116,8 +17116,8 @@ function syncData() {
|
|
|
17116
17116
|
data_root: DATA_ROOT2
|
|
17117
17117
|
};
|
|
17118
17118
|
}
|
|
17119
|
-
const localPayloads =
|
|
17120
|
-
const localTemplates =
|
|
17119
|
+
const localPayloads = join24(ROOT7, "payloads");
|
|
17120
|
+
const localTemplates = join24(ROOT7, "templates");
|
|
17121
17121
|
let payloadsSynced = false;
|
|
17122
17122
|
let templatesSynced = false;
|
|
17123
17123
|
if (!hasPayloads && dirExists(localPayloads)) {
|
|
@@ -17130,7 +17130,7 @@ function syncData() {
|
|
|
17130
17130
|
}
|
|
17131
17131
|
const gitOk = spawnSync4("git", ["--version"]).status === 0;
|
|
17132
17132
|
if (gitOk && (!dirExists(payloadsPath) || countFiles(payloadsPath) === 0 || !dirExists(templatesPath) || countFiles(templatesPath) === 0)) {
|
|
17133
|
-
const tmp =
|
|
17133
|
+
const tmp = join24(DATA_ROOT2, ".tmp-clone");
|
|
17134
17134
|
if (dirExists(tmp))
|
|
17135
17135
|
rmSync4(tmp, { recursive: true, force: true });
|
|
17136
17136
|
const r = spawnSync4("git", ["clone", "--depth", "1", "--filter=blob:none", "--sparse", GITHUB_REPO, tmp], { timeout: 120000 });
|
|
@@ -17138,11 +17138,11 @@ function syncData() {
|
|
|
17138
17138
|
const sparse = spawnSync4("git", ["-C", tmp, "sparse-checkout", "set", "payloads", "templates"], { timeout: 120000 });
|
|
17139
17139
|
if (sparse.status === 0) {
|
|
17140
17140
|
if (!dirExists(payloadsPath) || countFiles(payloadsPath) === 0) {
|
|
17141
|
-
copyDir(
|
|
17141
|
+
copyDir(join24(tmp, "payloads"), payloadsPath);
|
|
17142
17142
|
payloadsSynced = true;
|
|
17143
17143
|
}
|
|
17144
17144
|
if (!dirExists(templatesPath) || countFiles(templatesPath) === 0) {
|
|
17145
|
-
copyDir(
|
|
17145
|
+
copyDir(join24(tmp, "templates"), templatesPath);
|
|
17146
17146
|
templatesSynced = true;
|
|
17147
17147
|
}
|
|
17148
17148
|
}
|
|
@@ -17164,18 +17164,18 @@ function copyDir(src, dst) {
|
|
|
17164
17164
|
function manualCopy(src, dst) {
|
|
17165
17165
|
mkdirSync9(dst, { recursive: true });
|
|
17166
17166
|
for (const e of readdirSync7(src, { withFileTypes: true })) {
|
|
17167
|
-
const s =
|
|
17168
|
-
const d =
|
|
17167
|
+
const s = join24(src, e.name);
|
|
17168
|
+
const d = join24(dst, e.name);
|
|
17169
17169
|
if (e.isDirectory())
|
|
17170
17170
|
manualCopy(s, d);
|
|
17171
17171
|
else
|
|
17172
|
-
writeFileSync8(d,
|
|
17172
|
+
writeFileSync8(d, readFileSync26(s));
|
|
17173
17173
|
}
|
|
17174
17174
|
}
|
|
17175
17175
|
var ROOT7, DATA_ROOT2, GITHUB_REPO = "https://github.com/shinthink/blitzstrike.git";
|
|
17176
17176
|
var init_sync = __esm(() => {
|
|
17177
|
-
ROOT7 =
|
|
17178
|
-
DATA_ROOT2 = process.env.BLITZSTRIKE_DATA ??
|
|
17177
|
+
ROOT7 = join24(fileURLToPath13(new URL(".", import.meta.url)), "..");
|
|
17178
|
+
DATA_ROOT2 = process.env.BLITZSTRIKE_DATA ?? join24(homedir10(), ".blitzstrike", "data");
|
|
17179
17179
|
});
|
|
17180
17180
|
|
|
17181
17181
|
// src/update.ts
|
|
@@ -17220,15 +17220,15 @@ var init_update = __esm(() => {
|
|
|
17220
17220
|
});
|
|
17221
17221
|
|
|
17222
17222
|
// src/release.ts
|
|
17223
|
-
import { readFileSync as
|
|
17224
|
-
import { join as
|
|
17225
|
-
import { fileURLToPath as
|
|
17223
|
+
import { readFileSync as readFileSync28, existsSync as existsSync14 } from "node:fs";
|
|
17224
|
+
import { join as join25 } from "node:path";
|
|
17225
|
+
import { fileURLToPath as fileURLToPath14 } from "node:url";
|
|
17226
17226
|
import { execSync as execSync2 } from "node:child_process";
|
|
17227
17227
|
function validateRelease() {
|
|
17228
17228
|
const checks = [];
|
|
17229
17229
|
checks.push({ name: "package.json version", ok: true, detail: VERSION });
|
|
17230
17230
|
try {
|
|
17231
|
-
const changelog =
|
|
17231
|
+
const changelog = readFileSync28(join25(ROOT8, "CHANGELOG.md"), "utf8");
|
|
17232
17232
|
const m = changelog.match(/^##\s+\[([0-9]+\.[0-9]+\.[0-9]+)\]/m);
|
|
17233
17233
|
const changelogVersion = m?.[1] ?? null;
|
|
17234
17234
|
checks.push({
|
|
@@ -17260,22 +17260,22 @@ function validateRelease() {
|
|
|
17260
17260
|
return { version: VERSION, checks, consistent: checks.filter((c) => !c.soft).every((c) => c.ok) };
|
|
17261
17261
|
}
|
|
17262
17262
|
function lockfilePresent() {
|
|
17263
|
-
return
|
|
17263
|
+
return existsSync14(join25(ROOT8, "package-lock.json")) || existsSync14(join25(ROOT8, "bun.lock")) || existsSync14(join25(ROOT8, "bun.lockb"));
|
|
17264
17264
|
}
|
|
17265
17265
|
var ROOT8;
|
|
17266
17266
|
var init_release = __esm(() => {
|
|
17267
17267
|
init_version();
|
|
17268
|
-
ROOT8 =
|
|
17268
|
+
ROOT8 = join25(fileURLToPath14(new URL(".", import.meta.url)), "..");
|
|
17269
17269
|
});
|
|
17270
17270
|
|
|
17271
17271
|
// src/dependency.ts
|
|
17272
|
-
import { readFileSync as
|
|
17273
|
-
import { join as
|
|
17274
|
-
import { fileURLToPath as
|
|
17272
|
+
import { readFileSync as readFileSync29 } from "node:fs";
|
|
17273
|
+
import { join as join26 } from "node:path";
|
|
17274
|
+
import { fileURLToPath as fileURLToPath15 } from "node:url";
|
|
17275
17275
|
function checkDependencies() {
|
|
17276
17276
|
let pkg = {};
|
|
17277
17277
|
try {
|
|
17278
|
-
pkg = JSON.parse(
|
|
17278
|
+
pkg = JSON.parse(readFileSync29(join26(ROOT9, "package.json"), "utf8"));
|
|
17279
17279
|
} catch {
|
|
17280
17280
|
return { install_scripts: [], git_dependencies: [], total_dependencies: 0, safe: false };
|
|
17281
17281
|
}
|
|
@@ -17298,14 +17298,14 @@ function checkDependencies() {
|
|
|
17298
17298
|
}
|
|
17299
17299
|
var ROOT9;
|
|
17300
17300
|
var init_dependency = __esm(() => {
|
|
17301
|
-
ROOT9 =
|
|
17301
|
+
ROOT9 = join26(fileURLToPath15(new URL(".", import.meta.url)), "..");
|
|
17302
17302
|
});
|
|
17303
17303
|
|
|
17304
17304
|
// src/cli.ts
|
|
17305
|
-
import { readFileSync as
|
|
17306
|
-
import { join as
|
|
17305
|
+
import { readFileSync as readFileSync30, existsSync as existsSync15, writeFileSync as writeFileSync9, mkdirSync as mkdirSync10 } from "node:fs";
|
|
17306
|
+
import { join as join27, dirname as dirname6 } from "node:path";
|
|
17307
17307
|
import { homedir as homedir11 } from "node:os";
|
|
17308
|
-
import { fileURLToPath as
|
|
17308
|
+
import { fileURLToPath as fileURLToPath16 } from "node:url";
|
|
17309
17309
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
17310
17310
|
function which(cmd) {
|
|
17311
17311
|
return spawnSync5("sh", ["-c", 'command -v "$1" >/dev/null 2>&1', "sh", cmd]).status === 0;
|
|
@@ -17348,7 +17348,7 @@ async function runDoctor() {
|
|
|
17348
17348
|
detail: h1 ? `X-HackerOne-Research: ${h1}` : "H1_USERNAME not set",
|
|
17349
17349
|
fix: h1 ? undefined : "export H1_USERNAME=<your-hackerone-username> (adds X-HackerOne-Research to outbound requests)"
|
|
17350
17350
|
});
|
|
17351
|
-
const dataOk =
|
|
17351
|
+
const dataOk = existsSync15(join27(ROOT10, "chains.json")) && existsSync15(join27(ROOT10, "tools-catalog.json"));
|
|
17352
17352
|
issues.push({
|
|
17353
17353
|
name: "Data layers (chains + tools-catalog)",
|
|
17354
17354
|
status: dataOk ? "ok" : "fail",
|
|
@@ -17399,29 +17399,29 @@ BlitzStrike — ${verdict}`);
|
|
|
17399
17399
|
function resolveCommand() {
|
|
17400
17400
|
if (which("blitzstrike"))
|
|
17401
17401
|
return { command: "blitzstrike", args: ["serve", "--mcp"] };
|
|
17402
|
-
const src =
|
|
17403
|
-
if (which("bun") &&
|
|
17402
|
+
const src = join27(ROOT10, "src", "index.ts");
|
|
17403
|
+
if (which("bun") && existsSync15(src))
|
|
17404
17404
|
return { command: "bun", args: ["run", src, "serve", "--mcp"] };
|
|
17405
17405
|
if (which("npx"))
|
|
17406
17406
|
return { command: "npx", args: ["-y", "blitzstrike", "serve", "--mcp"] };
|
|
17407
17407
|
if (which("bunx"))
|
|
17408
17408
|
return { command: "bunx", args: ["blitzstrike", "serve", "--mcp"] };
|
|
17409
|
-
const dist =
|
|
17410
|
-
if (
|
|
17409
|
+
const dist = join27(ROOT10, "dist", "index.js");
|
|
17410
|
+
if (existsSync15(dist))
|
|
17411
17411
|
return { command: "bun", args: [dist, "serve", "--mcp"] };
|
|
17412
17412
|
return { command: "npx", args: ["-y", "blitzstrike", "serve", "--mcp"] };
|
|
17413
17413
|
}
|
|
17414
17414
|
function readJson(p) {
|
|
17415
17415
|
try {
|
|
17416
|
-
return JSON.parse(
|
|
17416
|
+
return JSON.parse(readFileSync30(p, "utf8"));
|
|
17417
17417
|
} catch {
|
|
17418
17418
|
return null;
|
|
17419
17419
|
}
|
|
17420
17420
|
}
|
|
17421
17421
|
function jsonMcpServersWrite(p) {
|
|
17422
17422
|
return (command, args) => {
|
|
17423
|
-
const dir =
|
|
17424
|
-
if (!
|
|
17423
|
+
const dir = dirname6(p);
|
|
17424
|
+
if (!existsSync15(dir))
|
|
17425
17425
|
mkdirSync10(dir, { recursive: true });
|
|
17426
17426
|
const existing = readJson(p) ?? {};
|
|
17427
17427
|
existing.mcpServers = {
|
|
@@ -17433,8 +17433,8 @@ function jsonMcpServersWrite(p) {
|
|
|
17433
17433
|
}
|
|
17434
17434
|
function opencodeWrite(p) {
|
|
17435
17435
|
return (command, args) => {
|
|
17436
|
-
const dir =
|
|
17437
|
-
if (!
|
|
17436
|
+
const dir = dirname6(p);
|
|
17437
|
+
if (!existsSync15(dir))
|
|
17438
17438
|
mkdirSync10(dir, { recursive: true });
|
|
17439
17439
|
const existing = readJson(p) ?? {};
|
|
17440
17440
|
existing.mcp = {
|
|
@@ -17446,26 +17446,26 @@ function opencodeWrite(p) {
|
|
|
17446
17446
|
};
|
|
17447
17447
|
}
|
|
17448
17448
|
function copyOpenCodeAgents() {
|
|
17449
|
-
const srcDir =
|
|
17450
|
-
const dstDir =
|
|
17451
|
-
if (!
|
|
17449
|
+
const srcDir = join27(ROOT10, "opencode-agents");
|
|
17450
|
+
const dstDir = join27(homedir11(), ".config", "opencode", "agents");
|
|
17451
|
+
if (!existsSync15(srcDir))
|
|
17452
17452
|
return;
|
|
17453
|
-
if (!
|
|
17453
|
+
if (!existsSync15(dstDir))
|
|
17454
17454
|
mkdirSync10(dstDir, { recursive: true });
|
|
17455
17455
|
for (const f of ["Blitz Strike.md", "Blitz.md", "Eagle Eye.md", "Strike.md"]) {
|
|
17456
|
-
const src =
|
|
17457
|
-
const dst =
|
|
17458
|
-
if (
|
|
17459
|
-
writeFileSync9(dst,
|
|
17456
|
+
const src = join27(srcDir, f);
|
|
17457
|
+
const dst = join27(dstDir, f);
|
|
17458
|
+
if (existsSync15(src)) {
|
|
17459
|
+
writeFileSync9(dst, readFileSync30(src, "utf8"));
|
|
17460
17460
|
}
|
|
17461
17461
|
}
|
|
17462
17462
|
}
|
|
17463
17463
|
function codexWrite(p) {
|
|
17464
17464
|
return (command, args) => {
|
|
17465
|
-
const dir =
|
|
17466
|
-
if (!
|
|
17465
|
+
const dir = dirname6(p);
|
|
17466
|
+
if (!existsSync15(dir))
|
|
17467
17467
|
mkdirSync10(dir, { recursive: true });
|
|
17468
|
-
let existing =
|
|
17468
|
+
let existing = existsSync15(p) ? readFileSync30(p, "utf8") : "";
|
|
17469
17469
|
if (!existing.trimEnd().endsWith(`
|
|
17470
17470
|
`))
|
|
17471
17471
|
existing += `
|
|
@@ -17481,10 +17481,10 @@ args = ${JSON.stringify(args)}
|
|
|
17481
17481
|
}
|
|
17482
17482
|
function hermesWrite(p) {
|
|
17483
17483
|
return (command, args) => {
|
|
17484
|
-
const dir =
|
|
17485
|
-
if (!
|
|
17484
|
+
const dir = dirname6(p);
|
|
17485
|
+
if (!existsSync15(dir))
|
|
17486
17486
|
mkdirSync10(dir, { recursive: true });
|
|
17487
|
-
let existing =
|
|
17487
|
+
let existing = existsSync15(p) ? readFileSync30(p, "utf8") : "";
|
|
17488
17488
|
existing = existing.replace(/^ blitzstrike:\n(?: .*\n?)*/m, "");
|
|
17489
17489
|
if (!existing.trimEnd().endsWith(`
|
|
17490
17490
|
`))
|
|
@@ -17511,74 +17511,74 @@ mcp_servers:
|
|
|
17511
17511
|
function detectAgents() {
|
|
17512
17512
|
const home = homedir11();
|
|
17513
17513
|
const agents = [];
|
|
17514
|
-
const claudeJson =
|
|
17514
|
+
const claudeJson = join27(home, ".claude.json");
|
|
17515
17515
|
agents.push({
|
|
17516
17516
|
name: "Claude Code",
|
|
17517
17517
|
detectPath: claudeJson,
|
|
17518
|
-
installed: () =>
|
|
17518
|
+
installed: () => existsSync15(claudeJson) || which("claude"),
|
|
17519
17519
|
write: jsonMcpServersWrite(claudeJson)
|
|
17520
17520
|
});
|
|
17521
|
-
const claudeDesktop =
|
|
17521
|
+
const claudeDesktop = join27(home, ".config", "Claude", "claude_desktop_config.json");
|
|
17522
17522
|
agents.push({
|
|
17523
17523
|
name: "Claude Desktop",
|
|
17524
17524
|
detectPath: claudeDesktop,
|
|
17525
|
-
installed: () =>
|
|
17525
|
+
installed: () => existsSync15(claudeDesktop),
|
|
17526
17526
|
write: jsonMcpServersWrite(claudeDesktop)
|
|
17527
17527
|
});
|
|
17528
|
-
const cursor =
|
|
17528
|
+
const cursor = join27(home, ".cursor", "mcp.json");
|
|
17529
17529
|
agents.push({
|
|
17530
17530
|
name: "Cursor",
|
|
17531
17531
|
detectPath: cursor,
|
|
17532
|
-
installed: () =>
|
|
17532
|
+
installed: () => existsSync15(join27(home, ".cursor")) || which("cursor"),
|
|
17533
17533
|
write: jsonMcpServersWrite(cursor)
|
|
17534
17534
|
});
|
|
17535
|
-
const opencode =
|
|
17535
|
+
const opencode = join27(home, ".config", "opencode", "opencode.jsonc");
|
|
17536
17536
|
agents.push({
|
|
17537
17537
|
name: "OpenCode",
|
|
17538
17538
|
detectPath: opencode,
|
|
17539
|
-
installed: () =>
|
|
17539
|
+
installed: () => existsSync15(join27(home, ".config", "opencode")) || which("opencode"),
|
|
17540
17540
|
write: opencodeWrite(opencode)
|
|
17541
17541
|
});
|
|
17542
|
-
const codex =
|
|
17542
|
+
const codex = join27(home, ".codex", "config.toml");
|
|
17543
17543
|
agents.push({
|
|
17544
17544
|
name: "Codex",
|
|
17545
17545
|
detectPath: codex,
|
|
17546
|
-
installed: () =>
|
|
17546
|
+
installed: () => existsSync15(join27(home, ".codex")) || which("codex"),
|
|
17547
17547
|
write: codexWrite(codex)
|
|
17548
17548
|
});
|
|
17549
|
-
const hermes =
|
|
17549
|
+
const hermes = join27(home, ".hermes", "config.yaml");
|
|
17550
17550
|
agents.push({
|
|
17551
17551
|
name: "Hermes",
|
|
17552
17552
|
detectPath: hermes,
|
|
17553
|
-
installed: () =>
|
|
17553
|
+
installed: () => existsSync15(join27(home, ".hermes")) || which("hermes"),
|
|
17554
17554
|
write: hermesWrite(hermes)
|
|
17555
17555
|
});
|
|
17556
|
-
const gemini =
|
|
17556
|
+
const gemini = join27(home, ".gemini", "settings.json");
|
|
17557
17557
|
agents.push({
|
|
17558
17558
|
name: "Gemini CLI",
|
|
17559
17559
|
detectPath: gemini,
|
|
17560
|
-
installed: () =>
|
|
17560
|
+
installed: () => existsSync15(join27(home, ".gemini")) || which("gemini"),
|
|
17561
17561
|
write: jsonMcpServersWrite(gemini)
|
|
17562
17562
|
});
|
|
17563
|
-
const windsurf =
|
|
17563
|
+
const windsurf = join27(home, ".codeium", "windsurf", "mcp_config.json");
|
|
17564
17564
|
agents.push({
|
|
17565
17565
|
name: "Windsurf",
|
|
17566
17566
|
detectPath: windsurf,
|
|
17567
|
-
installed: () =>
|
|
17567
|
+
installed: () => existsSync15(join27(home, ".codeium")) || which("windsurf"),
|
|
17568
17568
|
write: jsonMcpServersWrite(windsurf)
|
|
17569
17569
|
});
|
|
17570
|
-
const copilot =
|
|
17570
|
+
const copilot = join27(home, ".copilot", "mcp.json");
|
|
17571
17571
|
agents.push({
|
|
17572
17572
|
name: "Copilot",
|
|
17573
17573
|
detectPath: copilot,
|
|
17574
|
-
installed: () =>
|
|
17574
|
+
installed: () => existsSync15(join27(home, ".copilot")),
|
|
17575
17575
|
write: jsonMcpServersWrite(copilot)
|
|
17576
17576
|
});
|
|
17577
|
-
const cline =
|
|
17577
|
+
const cline = join27(home, ".cline", "mcp_settings.json");
|
|
17578
17578
|
agents.push({
|
|
17579
17579
|
name: "Cline",
|
|
17580
17580
|
detectPath: cline,
|
|
17581
|
-
installed: () =>
|
|
17581
|
+
installed: () => existsSync15(join27(home, ".cline")),
|
|
17582
17582
|
write: jsonMcpServersWrite(cline)
|
|
17583
17583
|
});
|
|
17584
17584
|
return agents;
|
|
@@ -17696,7 +17696,7 @@ var init_cli = __esm(() => {
|
|
|
17696
17696
|
init_release();
|
|
17697
17697
|
init_dependency();
|
|
17698
17698
|
init_mcp_status();
|
|
17699
|
-
ROOT10 =
|
|
17699
|
+
ROOT10 = join27(fileURLToPath16(new URL(".", import.meta.url)), "..");
|
|
17700
17700
|
});
|
|
17701
17701
|
|
|
17702
17702
|
// node_modules/zod/v3/helpers/util.js
|
|
@@ -32334,7 +32334,7 @@ class StdioServerTransport {
|
|
|
32334
32334
|
|
|
32335
32335
|
// src/server.ts
|
|
32336
32336
|
init_scanner();
|
|
32337
|
-
import { readFileSync as
|
|
32337
|
+
import { readFileSync as readFileSync27 } from "node:fs";
|
|
32338
32338
|
|
|
32339
32339
|
// src/recon.ts
|
|
32340
32340
|
var TIMEOUT_MS = 25000;
|
|
@@ -32417,7 +32417,7 @@ async function nvdLookup(cveId) {
|
|
|
32417
32417
|
|
|
32418
32418
|
// src/orchestrator.ts
|
|
32419
32419
|
init_scanner();
|
|
32420
|
-
import { readFileSync as readFileSync9, existsSync as
|
|
32420
|
+
import { readFileSync as readFileSync9, existsSync as existsSync8, statSync as statSync2 } from "node:fs";
|
|
32421
32421
|
import { join as join11 } from "node:path";
|
|
32422
32422
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
32423
32423
|
|
|
@@ -33181,6 +33181,8 @@ function resolveFinding(finding, verdict) {
|
|
|
33181
33181
|
|
|
33182
33182
|
// src/hash.ts
|
|
33183
33183
|
import { createHash as createHash3 } from "node:crypto";
|
|
33184
|
+
import { createReadStream, existsSync as existsSync4 } from "node:fs";
|
|
33185
|
+
import { createInterface } from "node:readline";
|
|
33184
33186
|
var COMMON_PASSWORDS = [
|
|
33185
33187
|
"password",
|
|
33186
33188
|
"123456",
|
|
@@ -33211,6 +33213,14 @@ var COMMON_PASSWORDS = [
|
|
|
33211
33213
|
"P@ssw0rd",
|
|
33212
33214
|
"qwertyuiop"
|
|
33213
33215
|
];
|
|
33216
|
+
var AUTOLOAD_WORDLISTS = [
|
|
33217
|
+
"/usr/share/wordlists/rockyou.txt",
|
|
33218
|
+
"/opt/seclists/Passwords/Leaked-Databases/rockyou-70.txt",
|
|
33219
|
+
"/opt/seclists/Passwords/Leaked-Databases/rockyou-35.txt",
|
|
33220
|
+
"/opt/seclists/Passwords/Leaked-Databases/rockyou-40.txt",
|
|
33221
|
+
"/opt/seclists/Passwords/Common-Credentials/100k-most-used-passwords-NCSC.txt",
|
|
33222
|
+
"/opt/seclists/Passwords/Common-Credentials/10k-most-common.txt"
|
|
33223
|
+
];
|
|
33214
33224
|
function identifyHash(hash) {
|
|
33215
33225
|
if (/^\$2[aby]\$\d+\$/.test(hash))
|
|
33216
33226
|
return "bcrypt";
|
|
@@ -33243,31 +33253,141 @@ var HASHCAT_MODE = {
|
|
|
33243
33253
|
sha512crypt: "1800",
|
|
33244
33254
|
ntlm: "1000"
|
|
33245
33255
|
};
|
|
33246
|
-
|
|
33256
|
+
function hashMatches(type, pw, hash) {
|
|
33257
|
+
const target = hash.toLowerCase();
|
|
33258
|
+
if (type === "md5")
|
|
33259
|
+
return createHash3("md5").update(pw).digest("hex") === target;
|
|
33260
|
+
if (type === "sha1")
|
|
33261
|
+
return createHash3("sha1").update(pw).digest("hex") === target;
|
|
33262
|
+
if (type === "sha256")
|
|
33263
|
+
return createHash3("sha256").update(pw).digest("hex") === target;
|
|
33264
|
+
if (type === "sha512")
|
|
33265
|
+
return createHash3("sha512").update(pw).digest("hex") === target;
|
|
33266
|
+
if (type === "ntlm") {
|
|
33267
|
+
const md4 = (buf) => {
|
|
33268
|
+
const pad = (s) => {
|
|
33269
|
+
const len = s.length;
|
|
33270
|
+
const bitLen = len * 8;
|
|
33271
|
+
const out = Buffer.concat([s, Buffer.from([128])]);
|
|
33272
|
+
const mod = out.length % 64;
|
|
33273
|
+
const padLen = mod < 56 ? 56 - mod : 120 - mod;
|
|
33274
|
+
const padded = Buffer.concat([out, Buffer.alloc(padLen)]);
|
|
33275
|
+
const lenBuf = Buffer.alloc(8);
|
|
33276
|
+
lenBuf.writeUInt32LE(bitLen >>> 0, 0);
|
|
33277
|
+
lenBuf.writeUInt32LE(Math.floor(bitLen / 4294967296), 4);
|
|
33278
|
+
return Buffer.concat([padded, lenBuf]);
|
|
33279
|
+
};
|
|
33280
|
+
const rotl = (x, n) => (x << n | x >>> 32 - n) >>> 0;
|
|
33281
|
+
const F = (x, y, z) => x & y | ~x & z;
|
|
33282
|
+
const G = (x, y, z) => x & y | x & z | y & z;
|
|
33283
|
+
const H = (x, y, z) => x ^ y ^ z;
|
|
33284
|
+
const msg = pad(buf);
|
|
33285
|
+
let a0 = 1732584193, b0 = 4023233417, c0 = 2562383102, d0 = 271733878;
|
|
33286
|
+
for (let i = 0;i < msg.length; i += 64) {
|
|
33287
|
+
const X = [];
|
|
33288
|
+
for (let j = 0;j < 16; j++)
|
|
33289
|
+
X[j] = msg.readUInt32LE(i + j * 4);
|
|
33290
|
+
let A = a0, B = b0, C = c0, D = d0;
|
|
33291
|
+
for (let r = 0;r < 16; r++) {
|
|
33292
|
+
const k = r;
|
|
33293
|
+
const s = [3, 7, 11, 19][r % 4];
|
|
33294
|
+
const order = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
|
33295
|
+
A = rotl(A + F(B, C, D) + X[order[k]] + 0 >>> 0, s);
|
|
33296
|
+
[A, B, C, D] = [D, A, B, C];
|
|
33297
|
+
}
|
|
33298
|
+
for (let r = 0;r < 16; r++) {
|
|
33299
|
+
const order = [0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15];
|
|
33300
|
+
const s = [3, 5, 9, 13][r % 4];
|
|
33301
|
+
A = rotl(A + G(B, C, D) + X[order[r]] + 1518500249 >>> 0, s);
|
|
33302
|
+
[A, B, C, D] = [D, A, B, C];
|
|
33303
|
+
}
|
|
33304
|
+
for (let r = 0;r < 16; r++) {
|
|
33305
|
+
const order = [0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15];
|
|
33306
|
+
const s = [3, 9, 11, 15][r % 4];
|
|
33307
|
+
A = rotl(A + H(B, C, D) + X[order[r]] + 1859775393 >>> 0, s);
|
|
33308
|
+
[A, B, C, D] = [D, A, B, C];
|
|
33309
|
+
}
|
|
33310
|
+
a0 = a0 + A >>> 0;
|
|
33311
|
+
b0 = b0 + B >>> 0;
|
|
33312
|
+
c0 = c0 + C >>> 0;
|
|
33313
|
+
d0 = d0 + D >>> 0;
|
|
33314
|
+
}
|
|
33315
|
+
const le = (x) => Buffer.from([x & 255, x >>> 8 & 255, x >>> 16 & 255, x >>> 24 & 255]);
|
|
33316
|
+
return Buffer.concat([le(a0), le(b0), le(c0), le(d0)]).toString("hex");
|
|
33317
|
+
};
|
|
33318
|
+
const utf16le = Buffer.from(pw, "utf16le");
|
|
33319
|
+
return md4(utf16le) === target;
|
|
33320
|
+
}
|
|
33321
|
+
return false;
|
|
33322
|
+
}
|
|
33323
|
+
async function crackWordlists(hash, type, paths, maxCandidates) {
|
|
33324
|
+
let checked = 0;
|
|
33325
|
+
for (const p of paths) {
|
|
33326
|
+
if (!existsSync4(p))
|
|
33327
|
+
continue;
|
|
33328
|
+
const stream = createReadStream(p, { encoding: "utf8" });
|
|
33329
|
+
const rl = createInterface({ input: stream, crlfDelay: Infinity });
|
|
33330
|
+
let found = null;
|
|
33331
|
+
for await (const line of rl) {
|
|
33332
|
+
if (found)
|
|
33333
|
+
break;
|
|
33334
|
+
const pw = line.endsWith("\r") ? line.slice(0, -1) : line;
|
|
33335
|
+
if (!pw)
|
|
33336
|
+
continue;
|
|
33337
|
+
checked += 1;
|
|
33338
|
+
if (checked > maxCandidates)
|
|
33339
|
+
break;
|
|
33340
|
+
if (hashMatches(type, pw, hash))
|
|
33341
|
+
found = pw;
|
|
33342
|
+
}
|
|
33343
|
+
stream.destroy();
|
|
33344
|
+
if (found)
|
|
33345
|
+
return { password: found, checked };
|
|
33346
|
+
if (checked > maxCandidates)
|
|
33347
|
+
break;
|
|
33348
|
+
}
|
|
33349
|
+
return { password: null, checked };
|
|
33350
|
+
}
|
|
33351
|
+
async function crackHash(hash, extra = [], opts = {}) {
|
|
33247
33352
|
const type = identifyHash(hash);
|
|
33248
|
-
const
|
|
33249
|
-
const
|
|
33250
|
-
|
|
33251
|
-
|
|
33252
|
-
|
|
33253
|
-
|
|
33254
|
-
|
|
33255
|
-
|
|
33256
|
-
|
|
33257
|
-
|
|
33258
|
-
|
|
33259
|
-
|
|
33260
|
-
|
|
33261
|
-
|
|
33262
|
-
|
|
33263
|
-
|
|
33353
|
+
const maxCandidates = opts.maxCandidates ?? 5000000;
|
|
33354
|
+
const fast = [...new Set([...extra, ...COMMON_PASSWORDS])];
|
|
33355
|
+
let matched = "";
|
|
33356
|
+
for (const pw of fast) {
|
|
33357
|
+
if (hashMatches(type, pw, hash)) {
|
|
33358
|
+
matched = pw;
|
|
33359
|
+
break;
|
|
33360
|
+
}
|
|
33361
|
+
}
|
|
33362
|
+
if (matched) {
|
|
33363
|
+
return {
|
|
33364
|
+
type,
|
|
33365
|
+
cracked: true,
|
|
33366
|
+
matches: [matched],
|
|
33367
|
+
source: "common",
|
|
33368
|
+
recommendation: `CRACKED — authenticate with '${matched}' and continue the chain (login → dashboard → privileged actions).`
|
|
33369
|
+
};
|
|
33370
|
+
}
|
|
33371
|
+
const explicit = opts.wordlist ? Array.isArray(opts.wordlist) ? opts.wordlist : [opts.wordlist] : [];
|
|
33372
|
+
const paths = [...new Set([...explicit, ...AUTOLOAD_WORDLISTS])];
|
|
33373
|
+
const { password, checked } = await crackWordlists(hash, type, paths, maxCandidates);
|
|
33374
|
+
if (password) {
|
|
33375
|
+
return {
|
|
33376
|
+
type,
|
|
33377
|
+
cracked: true,
|
|
33378
|
+
matches: [password],
|
|
33379
|
+
source: "wordlist",
|
|
33380
|
+
candidates_checked: checked,
|
|
33381
|
+
recommendation: `CRACKED from wordlist — authenticate with '${password}' and continue the chain (login → dashboard → privileged actions).`
|
|
33382
|
+
};
|
|
33264
33383
|
}
|
|
33265
33384
|
const mode = HASHCAT_MODE[type];
|
|
33266
33385
|
return {
|
|
33267
33386
|
type,
|
|
33268
|
-
cracked:
|
|
33269
|
-
matches,
|
|
33270
|
-
|
|
33387
|
+
cracked: false,
|
|
33388
|
+
matches: [],
|
|
33389
|
+
candidates_checked: checked,
|
|
33390
|
+
recommendation: mode ? `Not in the built-in common list or ${checked} wordlist candidates. Full crack: hashcat -m ${mode} -a 0 <hashes.txt> <wordlist> (bcrypt cost 12 needs GPU + time). Pass a target-specific wordlist via the wordlist arg (e.g. company names, usernames, pattern guesses). Reuse the credential if it matches another account's hash (password reuse).` : "Unknown hash format — save it and identify manually before cracking."
|
|
33271
33391
|
};
|
|
33272
33392
|
}
|
|
33273
33393
|
|
|
@@ -33447,7 +33567,7 @@ async function browserValidate(check, target, payload) {
|
|
|
33447
33567
|
|
|
33448
33568
|
// src/devtools.ts
|
|
33449
33569
|
import { spawn as spawn2, spawnSync as spawnSync2 } from "node:child_process";
|
|
33450
|
-
import { existsSync as
|
|
33570
|
+
import { existsSync as existsSync5, readdirSync as readdirSync3 } from "node:fs";
|
|
33451
33571
|
import { join as join7 } from "node:path";
|
|
33452
33572
|
import { homedir as homedir4 } from "node:os";
|
|
33453
33573
|
function mcpClient(command, args) {
|
|
@@ -33521,17 +33641,17 @@ function findChromium() {
|
|
|
33521
33641
|
for (const c of candidates) {
|
|
33522
33642
|
for (const dir of ["/usr/bin", "/usr/local/bin", "/opt/google/chrome"]) {
|
|
33523
33643
|
const p = join7(dir, c);
|
|
33524
|
-
if (
|
|
33644
|
+
if (existsSync5(p))
|
|
33525
33645
|
return p;
|
|
33526
33646
|
}
|
|
33527
33647
|
}
|
|
33528
33648
|
const pw = join7(homedir4(), ".cache", "ms-playwright");
|
|
33529
|
-
if (
|
|
33649
|
+
if (existsSync5(pw)) {
|
|
33530
33650
|
for (const d of readdirSync3(pw)) {
|
|
33531
33651
|
if (!d.startsWith("chromium"))
|
|
33532
33652
|
continue;
|
|
33533
33653
|
const full = join7(pw, d, "chrome-linux64", "chrome");
|
|
33534
|
-
if (
|
|
33654
|
+
if (existsSync5(full))
|
|
33535
33655
|
return full;
|
|
33536
33656
|
}
|
|
33537
33657
|
}
|
|
@@ -33539,7 +33659,7 @@ function findChromium() {
|
|
|
33539
33659
|
}
|
|
33540
33660
|
function chromeDevtoolsCommand() {
|
|
33541
33661
|
for (const c of ["/usr/bin/chrome-devtools-mcp", "/usr/local/bin/chrome-devtools-mcp"]) {
|
|
33542
|
-
if (
|
|
33662
|
+
if (existsSync5(c))
|
|
33543
33663
|
return { command: c, args: [] };
|
|
33544
33664
|
}
|
|
33545
33665
|
const npx = spawnSync2("npx", ["--version"], { timeout: 8000 });
|
|
@@ -33851,12 +33971,12 @@ function uniqueFindings(findings) {
|
|
|
33851
33971
|
}
|
|
33852
33972
|
|
|
33853
33973
|
// src/intel.ts
|
|
33854
|
-
import { readFileSync as readFileSync8, existsSync as
|
|
33974
|
+
import { readFileSync as readFileSync8, existsSync as existsSync7 } from "node:fs";
|
|
33855
33975
|
import { join as join9 } from "node:path";
|
|
33856
33976
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
33857
33977
|
|
|
33858
33978
|
// src/intelligence.ts
|
|
33859
|
-
import { readFileSync as readFileSync7, appendFileSync as appendFileSync3, mkdirSync as mkdirSync4, existsSync as
|
|
33979
|
+
import { readFileSync as readFileSync7, appendFileSync as appendFileSync3, mkdirSync as mkdirSync4, existsSync as existsSync6 } from "node:fs";
|
|
33860
33980
|
import { join as join8 } from "node:path";
|
|
33861
33981
|
import { createHash as createHash4 } from "node:crypto";
|
|
33862
33982
|
import { homedir as homedir5 } from "node:os";
|
|
@@ -33882,14 +34002,14 @@ function sinkToVector(sinkType) {
|
|
|
33882
34002
|
return SINK_TO_VECTOR[sinkType.toLowerCase()] ?? sinkType.toLowerCase();
|
|
33883
34003
|
}
|
|
33884
34004
|
function ensureDir2() {
|
|
33885
|
-
if (!
|
|
34005
|
+
if (!existsSync6(HOME_DIR3))
|
|
33886
34006
|
mkdirSync4(HOME_DIR3, { recursive: true });
|
|
33887
34007
|
}
|
|
33888
34008
|
function dedupHash2(vector, tech, target, outcome) {
|
|
33889
34009
|
return createHash4("sha256").update(`${vector}\x00${tech}\x00${target}\x00${outcome}`).digest("hex").slice(0, 16);
|
|
33890
34010
|
}
|
|
33891
34011
|
function loadIntel() {
|
|
33892
|
-
if (!
|
|
34012
|
+
if (!existsSync6(INTEL_PATH))
|
|
33893
34013
|
return [];
|
|
33894
34014
|
try {
|
|
33895
34015
|
const out = [];
|
|
@@ -34041,7 +34161,7 @@ var ROOT3 = join9(fileURLToPath4(new URL(".", import.meta.url)), "..");
|
|
|
34041
34161
|
var INTEL = join9(ROOT3, "intelligence");
|
|
34042
34162
|
function loadJson(name) {
|
|
34043
34163
|
const p = join9(INTEL, `${name}.json`);
|
|
34044
|
-
if (!
|
|
34164
|
+
if (!existsSync7(p))
|
|
34045
34165
|
return null;
|
|
34046
34166
|
try {
|
|
34047
34167
|
return JSON.parse(readFileSync8(p, "utf8"));
|
|
@@ -34328,12 +34448,12 @@ var PACKAGE_PAYLOADS = join9(ROOT3, "payloads");
|
|
|
34328
34448
|
var PACKAGE_TEMPLATES = join9(ROOT3, "templates");
|
|
34329
34449
|
var DATA_ROOT = process.env.BLITZSTRIKE_DATA ?? join9(homedir6(), ".blitzstrike", "data");
|
|
34330
34450
|
function payloadsDir() {
|
|
34331
|
-
if (
|
|
34451
|
+
if (existsSync7(PACKAGE_PAYLOADS))
|
|
34332
34452
|
return PACKAGE_PAYLOADS;
|
|
34333
34453
|
return join9(DATA_ROOT, "payloads");
|
|
34334
34454
|
}
|
|
34335
34455
|
function templatesDir() {
|
|
34336
|
-
if (
|
|
34456
|
+
if (existsSync7(PACKAGE_TEMPLATES))
|
|
34337
34457
|
return PACKAGE_TEMPLATES;
|
|
34338
34458
|
return join9(DATA_ROOT, "templates");
|
|
34339
34459
|
}
|
|
@@ -35941,7 +36061,7 @@ function classifyTarget(target) {
|
|
|
35941
36061
|
if (/^https?:\/\//i.test(target))
|
|
35942
36062
|
return { kind: "live", target };
|
|
35943
36063
|
try {
|
|
35944
|
-
if (
|
|
36064
|
+
if (existsSync8(target) && (statSync2(target).isDirectory() || statSync2(target).isFile())) {
|
|
35945
36065
|
return { kind: "source", target };
|
|
35946
36066
|
}
|
|
35947
36067
|
} catch {}
|
|
@@ -36082,7 +36202,7 @@ function runEngagement(target, scope = "", mode = "bug-bounty", maxFiles = 2000,
|
|
|
36082
36202
|
};
|
|
36083
36203
|
const isPath = (() => {
|
|
36084
36204
|
try {
|
|
36085
|
-
return
|
|
36205
|
+
return existsSync8(target) && (statSync2(target).isDirectory() || statSync2(target).isFile());
|
|
36086
36206
|
} catch {
|
|
36087
36207
|
return false;
|
|
36088
36208
|
}
|
|
@@ -57558,7 +57678,7 @@ function analyzePatchFiles(oldPath, newPath, language) {
|
|
|
57558
57678
|
}
|
|
57559
57679
|
|
|
57560
57680
|
// src/frameworks.ts
|
|
57561
|
-
import { readFileSync as readFileSync16, existsSync as
|
|
57681
|
+
import { readFileSync as readFileSync16, existsSync as existsSync9 } from "node:fs";
|
|
57562
57682
|
import { join as join15 } from "node:path";
|
|
57563
57683
|
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
57564
57684
|
var ROOT4 = join15(fileURLToPath7(new URL(".", import.meta.url)), "..");
|
|
@@ -57568,7 +57688,7 @@ function load2() {
|
|
|
57568
57688
|
if (cache)
|
|
57569
57689
|
return cache;
|
|
57570
57690
|
const p = join15(INTEL2, "frameworks.json");
|
|
57571
|
-
if (!
|
|
57691
|
+
if (!existsSync9(p))
|
|
57572
57692
|
return null;
|
|
57573
57693
|
try {
|
|
57574
57694
|
cache = JSON.parse(readFileSync16(p, "utf8"));
|
|
@@ -58253,7 +58373,7 @@ function submissionGate(input) {
|
|
|
58253
58373
|
// src/git-history.ts
|
|
58254
58374
|
init_complex_bugs();
|
|
58255
58375
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
58256
|
-
import { existsSync as
|
|
58376
|
+
import { existsSync as existsSync11 } from "node:fs";
|
|
58257
58377
|
import { join as join17 } from "node:path";
|
|
58258
58378
|
function parseDeletions(output) {
|
|
58259
58379
|
const out = [];
|
|
@@ -58283,7 +58403,7 @@ function blobBeforeDeletion(root, commit, path) {
|
|
|
58283
58403
|
function scanGitHistory(root, opts) {
|
|
58284
58404
|
const limit = opts?.limit ?? 30;
|
|
58285
58405
|
const findings = [];
|
|
58286
|
-
if (!
|
|
58406
|
+
if (!existsSync11(join17(root, ".git"))) {
|
|
58287
58407
|
return { root, is_git_repo: false, total: 0, findings: [], error: "not a git repository (no .git dir)" };
|
|
58288
58408
|
}
|
|
58289
58409
|
if (opts?.secretPattern) {
|
|
@@ -58429,6 +58549,103 @@ async function validateLeakedKey(input) {
|
|
|
58429
58549
|
};
|
|
58430
58550
|
}
|
|
58431
58551
|
|
|
58552
|
+
// src/hackbot-arena.ts
|
|
58553
|
+
import { readFileSync as readFileSync18 } from "node:fs";
|
|
58554
|
+
import { join as join18, dirname as dirname3 } from "node:path";
|
|
58555
|
+
import { fileURLToPath as fileURLToPath9 } from "node:url";
|
|
58556
|
+
var __dirname3 = dirname3(fileURLToPath9(import.meta.url));
|
|
58557
|
+
function load4() {
|
|
58558
|
+
try {
|
|
58559
|
+
return JSON.parse(readFileSync18(join18(__dirname3, "..", "intelligence", "hackbot-arena.json"), "utf8"));
|
|
58560
|
+
} catch {
|
|
58561
|
+
return { total: 0, flag_format: "FLAG{nusasec-<32 hex>}", labs: [] };
|
|
58562
|
+
}
|
|
58563
|
+
}
|
|
58564
|
+
var VECTOR_MAP = [
|
|
58565
|
+
{ re: /jwt|algorithm confusion|rs256|hs256/i, vectors: ["jwt"], detectors: ["missing_authz"], chains: ["jwt"], tools: ["jwt_analyze", "live_recon"] },
|
|
58566
|
+
{ re: /ssrf|server-side request/i, vectors: ["ssrf"], detectors: ["ssrf"], chains: ["ssrf"], tools: ["live_recon", "blind_oracle", "active_scan"] },
|
|
58567
|
+
{ re: /sql injection|sqli|postgresql|sql/i, vectors: ["sql_injection"], detectors: ["sql_injection"], chains: ["sql_injection"], tools: ["live_recon", "blind_oracle", "active_scan"] },
|
|
58568
|
+
{ re: /ssti|template injection|liquid|jinja|twig/i, vectors: ["ssti"], detectors: ["ssti"], chains: ["ssti"], tools: ["live_recon", "blind_oracle"] },
|
|
58569
|
+
{ re: /command injection|os command|command execution/i, vectors: ["command_injection"], detectors: ["command_injection"], chains: ["command_injection"], tools: ["live_recon", "blind_oracle"] },
|
|
58570
|
+
{ re: /idor|bola|authorization|broken function|role|membership|ownership|entitlement|directory search|excessive data|data exposure|harvest/i, vectors: ["broken_object_level_authorization"], detectors: ["missing_authz"], chains: ["idor"], tools: ["live_recon", "active_scan", "param_precedence"] },
|
|
58571
|
+
{ re: /graphql/i, vectors: ["graphql_exposure"], detectors: ["graphql_exposure", "sql_injection"], chains: ["graphql"], tools: ["live_recon", "active_scan"] },
|
|
58572
|
+
{ re: /cache/i, vectors: ["web_cache_deception"], detectors: [], chains: ["cache_deception"], tools: ["cache_gap", "live_recon"] },
|
|
58573
|
+
{ re: /credential|key|token|bearer|secret|leak|websocket|rum|api key/i, vectors: ["hardcoded_secret"], detectors: ["hardcoded_secret"], chains: ["secret_leak"], tools: ["live_recon", "drive_devtools", "scan_git_history"] },
|
|
58574
|
+
{ re: /rate.limit|batching|otp/i, vectors: ["business_logic"], detectors: [], chains: ["rate_limit_bypass"], tools: ["race_test", "active_scan"] },
|
|
58575
|
+
{ re: /mass assignment|self.regist|admin account|user creation|scope/i, vectors: ["mass_assignment"], detectors: ["mass_assignment", "missing_authz"], chains: ["mass_assignment"], tools: ["live_recon", "active_scan"] },
|
|
58576
|
+
{ re: /deserialization|rce|workflow|execution/i, vectors: ["code_execution"], detectors: ["deserialization"], chains: ["deserialization"], tools: ["live_recon", "active_scan"] }
|
|
58577
|
+
];
|
|
58578
|
+
function mapLab(lab) {
|
|
58579
|
+
const out = { vectors: [], detectors: [], chains: [], tools: [] };
|
|
58580
|
+
for (const m of VECTOR_MAP) {
|
|
58581
|
+
if (m.re.test(lab.vuln_class)) {
|
|
58582
|
+
out.vectors.push(...m.vectors);
|
|
58583
|
+
out.detectors.push(...m.detectors);
|
|
58584
|
+
out.chains.push(...m.chains);
|
|
58585
|
+
out.tools.push(...m.tools);
|
|
58586
|
+
}
|
|
58587
|
+
}
|
|
58588
|
+
out.vectors = [...new Set(out.vectors)];
|
|
58589
|
+
out.detectors = [...new Set(out.detectors)];
|
|
58590
|
+
out.chains = [...new Set(out.chains)];
|
|
58591
|
+
out.tools = [...new Set(out.tools)];
|
|
58592
|
+
return out;
|
|
58593
|
+
}
|
|
58594
|
+
function findByLab(labId) {
|
|
58595
|
+
const id = labId.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
58596
|
+
return load4().labs.find((l) => l.id.toLowerCase() === id || l.id.toLowerCase() === `labs${id}`) ?? null;
|
|
58597
|
+
}
|
|
58598
|
+
function hackbotArenaList() {
|
|
58599
|
+
const doc = load4();
|
|
58600
|
+
return {
|
|
58601
|
+
arena: "Hackbot-Arena (NusaSec)",
|
|
58602
|
+
total: doc.total,
|
|
58603
|
+
flag_format: doc.flag_format,
|
|
58604
|
+
note: "Port = 8080 + lab number (labs01 -> 8081 … labs30 -> 8110). Each lab has a solver/ reference exploit + judge.success_when solve criteria.",
|
|
58605
|
+
labs: doc.labs.map((l) => ({ id: l.id, name: l.name, difficulty: l.difficulty, port: l.port, vuln_class: l.vuln_class, stack: l.stack }))
|
|
58606
|
+
};
|
|
58607
|
+
}
|
|
58608
|
+
function hackbotArenaBrief(labId) {
|
|
58609
|
+
const lab = findByLab(labId);
|
|
58610
|
+
if (!lab)
|
|
58611
|
+
return { error: `unknown lab '${labId}'`, hint: "use hackbot_arena_list() to see all 30 labs" };
|
|
58612
|
+
const plan = mapLab(lab);
|
|
58613
|
+
return {
|
|
58614
|
+
id: lab.id,
|
|
58615
|
+
name: lab.name,
|
|
58616
|
+
difficulty: lab.difficulty,
|
|
58617
|
+
target: `http://localhost:${lab.port}`,
|
|
58618
|
+
vuln_class: lab.vuln_class,
|
|
58619
|
+
stack: lab.stack,
|
|
58620
|
+
flag_format: load4().flag_format,
|
|
58621
|
+
attack_plan: {
|
|
58622
|
+
vectors: plan.vectors,
|
|
58623
|
+
detectors: plan.detectors,
|
|
58624
|
+
chains: plan.chains,
|
|
58625
|
+
tools: plan.tools
|
|
58626
|
+
},
|
|
58627
|
+
hint: `Start with live_recon(target) to fingerprint, then drive the ${plan.chains.join(" + ") || "detected"} chain. Verify every step live (strike_verify / browser_validate) and recover the flag. Flag format: ${load4().flag_format}.`
|
|
58628
|
+
};
|
|
58629
|
+
}
|
|
58630
|
+
function hackbotArenaCoverage() {
|
|
58631
|
+
const doc = load4();
|
|
58632
|
+
const rows = doc.labs.map((l) => {
|
|
58633
|
+
const plan = mapLab(l);
|
|
58634
|
+
return { id: l.id, name: l.name, vuln_class: l.vuln_class, vectors: plan.vectors, detectors: plan.detectors, chains: plan.chains };
|
|
58635
|
+
});
|
|
58636
|
+
const withVector = rows.filter((r) => r.vectors.length > 0).length;
|
|
58637
|
+
const withDetector = rows.filter((r) => r.detectors.length > 0).length;
|
|
58638
|
+
return {
|
|
58639
|
+
arena: "Hackbot-Arena (NusaSec)",
|
|
58640
|
+
total_labs: doc.total,
|
|
58641
|
+
labs_with_mapped_vector: withVector,
|
|
58642
|
+
labs_with_detector_coverage: withDetector,
|
|
58643
|
+
coverage_ratio: Number((withVector / doc.total).toFixed(2)),
|
|
58644
|
+
note: "A mapped vector/detector means Blitz Strike has the deterministic tooling to drive that vuln class; the agent still has to execute the chain + recover the flag.",
|
|
58645
|
+
rows
|
|
58646
|
+
};
|
|
58647
|
+
}
|
|
58648
|
+
|
|
58432
58649
|
// src/severity.ts
|
|
58433
58650
|
var VRT_MAP = {
|
|
58434
58651
|
sql_injection: { vrt: "injection > sql_injection", priority: "P1", severity: "critical", rationale: "SQL injection reaches sensitive data or enables admin takeover." },
|
|
@@ -58493,13 +58710,13 @@ function listSeverityMap() {
|
|
|
58493
58710
|
}
|
|
58494
58711
|
|
|
58495
58712
|
// src/datarefresh.ts
|
|
58496
|
-
import { readFileSync as
|
|
58497
|
-
import { join as
|
|
58498
|
-
import { fileURLToPath as
|
|
58499
|
-
var
|
|
58713
|
+
import { readFileSync as readFileSync19 } from "node:fs";
|
|
58714
|
+
import { join as join19, dirname as dirname4 } from "node:path";
|
|
58715
|
+
import { fileURLToPath as fileURLToPath10 } from "node:url";
|
|
58716
|
+
var __dirname4 = dirname4(fileURLToPath10(import.meta.url));
|
|
58500
58717
|
function loadJson2(rel) {
|
|
58501
58718
|
try {
|
|
58502
|
-
return JSON.parse(
|
|
58719
|
+
return JSON.parse(readFileSync19(join19(__dirname4, "..", rel), "utf8"));
|
|
58503
58720
|
} catch {
|
|
58504
58721
|
return null;
|
|
58505
58722
|
}
|
|
@@ -58534,18 +58751,18 @@ init_verify_harness();
|
|
|
58534
58751
|
init_variants();
|
|
58535
58752
|
|
|
58536
58753
|
// src/benchmark.ts
|
|
58537
|
-
import { readFileSync as
|
|
58538
|
-
import { join as
|
|
58539
|
-
import { fileURLToPath as
|
|
58754
|
+
import { readFileSync as readFileSync21, readdirSync as readdirSync5, writeFileSync as writeFileSync6, rmSync as rmSync3, mkdirSync as mkdirSync7 } from "node:fs";
|
|
58755
|
+
import { join as join21 } from "node:path";
|
|
58756
|
+
import { fileURLToPath as fileURLToPath12 } from "node:url";
|
|
58540
58757
|
import { tmpdir as tmpdir3, homedir as homedir8 } from "node:os";
|
|
58541
58758
|
init_complex_bugs();
|
|
58542
|
-
var ROOT5 =
|
|
58543
|
-
var CORPUS =
|
|
58544
|
-
var CAPTURED_CORPUS_DIR = process.env.BLITZSTRIKE_CORPUS_DIR ??
|
|
58759
|
+
var ROOT5 = join21(fileURLToPath12(new URL(".", import.meta.url)), "..");
|
|
58760
|
+
var CORPUS = join21(ROOT5, "bench", "corpus");
|
|
58761
|
+
var CAPTURED_CORPUS_DIR = process.env.BLITZSTRIKE_CORPUS_DIR ?? join21(homedir8(), ".blitzstrike", "corpus");
|
|
58545
58762
|
function parseCorpusFile(path) {
|
|
58546
58763
|
let text;
|
|
58547
58764
|
try {
|
|
58548
|
-
text =
|
|
58765
|
+
text = readFileSync21(path, "utf8");
|
|
58549
58766
|
} catch {
|
|
58550
58767
|
return null;
|
|
58551
58768
|
}
|
|
@@ -58601,7 +58818,7 @@ function loadDir(dir) {
|
|
|
58601
58818
|
for (const f of readdirSync5(dir)) {
|
|
58602
58819
|
if (!f.endsWith(".md"))
|
|
58603
58820
|
continue;
|
|
58604
|
-
const e = parseCorpusFile(
|
|
58821
|
+
const e = parseCorpusFile(join21(dir, f));
|
|
58605
58822
|
if (e)
|
|
58606
58823
|
entries.push(e);
|
|
58607
58824
|
}
|
|
@@ -58628,7 +58845,7 @@ function captureFalsePositive(input) {
|
|
|
58628
58845
|
input.code,
|
|
58629
58846
|
"```"
|
|
58630
58847
|
].filter((l) => l !== null);
|
|
58631
|
-
const path =
|
|
58848
|
+
const path = join21(CAPTURED_CORPUS_DIR, `${id}.md`);
|
|
58632
58849
|
writeFileSync6(path, lines.join(`
|
|
58633
58850
|
`) + `
|
|
58634
58851
|
`, "utf8");
|
|
@@ -58650,7 +58867,7 @@ function detect(entry) {
|
|
|
58650
58867
|
}
|
|
58651
58868
|
const lang = entry.language;
|
|
58652
58869
|
if (lang === "php") {
|
|
58653
|
-
const tmp =
|
|
58870
|
+
const tmp = join21(tmpdir3(), `blitzstrike-bench-${entry.id}-${process.pid}.php`);
|
|
58654
58871
|
writeFileSync6(tmp, entry.code);
|
|
58655
58872
|
const r = analyzeDataFlow2(tmp);
|
|
58656
58873
|
rmSync3(tmp, { force: true });
|
|
@@ -58719,25 +58936,25 @@ function runBenchmark() {
|
|
|
58719
58936
|
}
|
|
58720
58937
|
|
|
58721
58938
|
// src/obligations.ts
|
|
58722
|
-
import { readFileSync as
|
|
58723
|
-
import { join as
|
|
58939
|
+
import { readFileSync as readFileSync22, appendFileSync as appendFileSync4, mkdirSync as mkdirSync8, existsSync as existsSync12, writeFileSync as writeFileSync7 } from "node:fs";
|
|
58940
|
+
import { join as join22 } from "node:path";
|
|
58724
58941
|
import { createHash as createHash6 } from "node:crypto";
|
|
58725
58942
|
import { homedir as homedir9 } from "node:os";
|
|
58726
|
-
var HOME_DIR4 = process.env.BLITZSTRIKE_HOME ??
|
|
58727
|
-
var OBLIGATION_PATH =
|
|
58943
|
+
var HOME_DIR4 = process.env.BLITZSTRIKE_HOME ?? join22(homedir9(), ".blitzstrike");
|
|
58944
|
+
var OBLIGATION_PATH = join22(HOME_DIR4, "obligations.jsonl");
|
|
58728
58945
|
function ensureDir3() {
|
|
58729
|
-
if (!
|
|
58946
|
+
if (!existsSync12(HOME_DIR4))
|
|
58730
58947
|
mkdirSync8(HOME_DIR4, { recursive: true });
|
|
58731
58948
|
}
|
|
58732
58949
|
function shortId2(claim) {
|
|
58733
58950
|
return `obl-${createHash6("sha256").update(`${claim}\x00${Date.now()}`).digest("hex").slice(0, 12)}`;
|
|
58734
58951
|
}
|
|
58735
58952
|
function loadObligations() {
|
|
58736
|
-
if (!
|
|
58953
|
+
if (!existsSync12(OBLIGATION_PATH))
|
|
58737
58954
|
return [];
|
|
58738
58955
|
try {
|
|
58739
58956
|
const out = [];
|
|
58740
|
-
for (const line of
|
|
58957
|
+
for (const line of readFileSync22(OBLIGATION_PATH, "utf8").split(`
|
|
58741
58958
|
`)) {
|
|
58742
58959
|
const t = line.trim();
|
|
58743
58960
|
if (!t)
|
|
@@ -58841,11 +59058,11 @@ init_framework_security();
|
|
|
58841
59058
|
// src/variant-scan.ts
|
|
58842
59059
|
init_scanner();
|
|
58843
59060
|
init_complex_bugs();
|
|
58844
|
-
import { readFileSync as
|
|
59061
|
+
import { readFileSync as readFileSync24 } from "node:fs";
|
|
58845
59062
|
|
|
58846
59063
|
// src/cross-file.ts
|
|
58847
59064
|
init_scanner();
|
|
58848
|
-
import { readFileSync as
|
|
59065
|
+
import { readFileSync as readFileSync23 } from "node:fs";
|
|
58849
59066
|
var PUBLIC_HOOK_RE = /(?:wp_ajax_nopriv_\w+|admin_post_nopriv_\w+|init|template_redirect|wp_loaded|parse_request|user_register|um_user_register|register_new_user|authenticate)/;
|
|
58850
59067
|
var PRIV_SINK_RE = /\b(set_role|add_role|remove_role|set_user_role|wp_set_current_user|wp_set_auth_cookie|wp_insert_user|wp_create_user|wp_update_user)\s*\(/;
|
|
58851
59068
|
var ROLE_META_RE = /update_user_meta\s*\(\s*[^,]+,\s*['"](wp_capabilities|role|roles|capabilities|wp_user_level)['"]/;
|
|
@@ -58897,7 +59114,7 @@ function detectCrossFilePrivesc(root) {
|
|
|
58897
59114
|
for (const file of files) {
|
|
58898
59115
|
let code;
|
|
58899
59116
|
try {
|
|
58900
|
-
code = stripComments(
|
|
59117
|
+
code = stripComments(readFileSync23(file, "utf8"));
|
|
58901
59118
|
} catch {
|
|
58902
59119
|
continue;
|
|
58903
59120
|
}
|
|
@@ -58938,7 +59155,7 @@ function detectCrossFilePrivesc(root) {
|
|
|
58938
59155
|
for (const file of files) {
|
|
58939
59156
|
let code;
|
|
58940
59157
|
try {
|
|
58941
|
-
code = stripComments(
|
|
59158
|
+
code = stripComments(readFileSync23(file, "utf8"));
|
|
58942
59159
|
} catch {
|
|
58943
59160
|
continue;
|
|
58944
59161
|
}
|
|
@@ -58961,7 +59178,7 @@ function detectCrossFilePrivesc(root) {
|
|
|
58961
59178
|
for (const file of files) {
|
|
58962
59179
|
let code;
|
|
58963
59180
|
try {
|
|
58964
|
-
code = stripComments(
|
|
59181
|
+
code = stripComments(readFileSync23(file, "utf8"));
|
|
58965
59182
|
} catch {
|
|
58966
59183
|
continue;
|
|
58967
59184
|
}
|
|
@@ -59076,7 +59293,7 @@ function variantScan(root, opts = {}) {
|
|
|
59076
59293
|
for (const file of files) {
|
|
59077
59294
|
let code;
|
|
59078
59295
|
try {
|
|
59079
|
-
code =
|
|
59296
|
+
code = readFileSync24(file, "utf8");
|
|
59080
59297
|
} catch {
|
|
59081
59298
|
continue;
|
|
59082
59299
|
}
|
|
@@ -59736,17 +59953,17 @@ function analyzeJwt(token, opts = {}) {
|
|
|
59736
59953
|
}
|
|
59737
59954
|
|
|
59738
59955
|
// src/enterprise-benchmark.ts
|
|
59739
|
-
import { existsSync as
|
|
59740
|
-
import { join as
|
|
59956
|
+
import { existsSync as existsSync13, readFileSync as readFileSync25, readdirSync as readdirSync6, statSync as statSync3 } from "node:fs";
|
|
59957
|
+
import { join as join23, resolve } from "node:path";
|
|
59741
59958
|
init_complex_bugs();
|
|
59742
59959
|
var ROOT6 = resolve(process.cwd(), "bench", "enterprise");
|
|
59743
59960
|
var ENTERPRISE_FIXTURES = [
|
|
59744
|
-
{ id: "php-laravel", dir:
|
|
59745
|
-
{ id: "js-express", dir:
|
|
59746
|
-
{ id: "py-django", dir:
|
|
59747
|
-
{ id: "java-spring", dir:
|
|
59748
|
-
{ id: "wp-batch-route", dir:
|
|
59749
|
-
{ id: "php-complex", dir:
|
|
59961
|
+
{ id: "php-laravel", dir: join23(ROOT6, "php-laravel"), expected_vulns: 4 },
|
|
59962
|
+
{ id: "js-express", dir: join23(ROOT6, "js-express"), expected_vulns: 2 },
|
|
59963
|
+
{ id: "py-django", dir: join23(ROOT6, "py-django"), expected_vulns: 2 },
|
|
59964
|
+
{ id: "java-spring", dir: join23(ROOT6, "java-spring"), expected_vulns: 2 },
|
|
59965
|
+
{ id: "wp-batch-route", dir: join23(ROOT6, "wp-batch-route"), expected_vulns: 3 },
|
|
59966
|
+
{ id: "php-complex", dir: join23(ROOT6, "php-complex"), expected_vulns: 4 }
|
|
59750
59967
|
];
|
|
59751
59968
|
function sourceFiles(root) {
|
|
59752
59969
|
const out = [];
|
|
@@ -59758,7 +59975,7 @@ function sourceFiles(root) {
|
|
|
59758
59975
|
return;
|
|
59759
59976
|
}
|
|
59760
59977
|
for (const e of entries) {
|
|
59761
|
-
const p =
|
|
59978
|
+
const p = join23(dir, e);
|
|
59762
59979
|
let st;
|
|
59763
59980
|
try {
|
|
59764
59981
|
st = statSync3(p);
|
|
@@ -59779,7 +59996,7 @@ function detectFixture(dir) {
|
|
|
59779
59996
|
for (const f of sourceFiles(dir)) {
|
|
59780
59997
|
let code;
|
|
59781
59998
|
try {
|
|
59782
|
-
code =
|
|
59999
|
+
code = readFileSync25(f, "utf8");
|
|
59783
60000
|
} catch {
|
|
59784
60001
|
continue;
|
|
59785
60002
|
}
|
|
@@ -59797,7 +60014,7 @@ function detectFixture(dir) {
|
|
|
59797
60014
|
function runEnterpriseBenchmark() {
|
|
59798
60015
|
const fixtures = [];
|
|
59799
60016
|
for (const fx of ENTERPRISE_FIXTURES) {
|
|
59800
|
-
if (!
|
|
60017
|
+
if (!existsSync13(fx.dir)) {
|
|
59801
60018
|
fixtures.push({ id: fx.id, available: false, detected: 0, expected: fx.expected_vulns, recall: 0 });
|
|
59802
60019
|
continue;
|
|
59803
60020
|
}
|
|
@@ -60221,16 +60438,19 @@ function createServer() {
|
|
|
60221
60438
|
});
|
|
60222
60439
|
server.registerTool("crack_hash", {
|
|
60223
60440
|
title: "Identify + crack a dumped credential hash",
|
|
60224
|
-
description: "CREDENTIAL: when you dump password hashes, EXECUTE this instead of leaving 'crack the hashes' as a recommendation. Identifies the hash type (bcrypt/md5/sha1/sha256/sha512/ntlm) and immediately tries a built-in common-password list offline, then returns the exact hashcat/john command for the full crack. Pass one hash string or a list.",
|
|
60441
|
+
description: "CREDENTIAL: when you dump password hashes, EXECUTE this instead of leaving 'crack the hashes' as a recommendation. Identifies the hash type (bcrypt/md5/sha1/sha256/sha512/ntlm) and immediately tries a built-in common-password list offline, then streams any supplied wordlist (and autoloads seclists/rockyou when present), then returns the exact hashcat/john command for the full crack. Pass one hash string or a list.",
|
|
60225
60442
|
inputSchema: {
|
|
60226
60443
|
hash: string2().describe("The hash string (or a list of hashes, one per line)"),
|
|
60227
|
-
extra: array(string2()).optional().describe("Extra candidate passwords to try (e.g. usernames, target-specific words)")
|
|
60444
|
+
extra: array(string2()).optional().describe("Extra candidate passwords to try (e.g. usernames, target-specific words)"),
|
|
60445
|
+
wordlist: string2().optional().describe("Optional wordlist file path(s) to stream (comma-separated). Autoloads rockyou/seclists if present."),
|
|
60446
|
+
maxCandidates: number2().int().optional().describe("Max wordlist candidates to stream (default 5,000,000)")
|
|
60228
60447
|
}
|
|
60229
|
-
}, async ({ hash, extra }) => {
|
|
60448
|
+
}, async ({ hash, extra, wordlist, maxCandidates }) => {
|
|
60230
60449
|
const hashes = hash.split(/\r?\n/).map((h) => h.trim()).filter(Boolean).slice(0, 50);
|
|
60450
|
+
const wl = wordlist ? wordlist.split(",").map((s) => s.trim()).filter(Boolean) : undefined;
|
|
60231
60451
|
const results = [];
|
|
60232
60452
|
for (const h of hashes) {
|
|
60233
|
-
results.push({ hash: h.slice(0, 24) + (h.length > 24 ? "…" : ""), ...await crackHash(h, extra ?? []) });
|
|
60453
|
+
results.push({ hash: h.slice(0, 24) + (h.length > 24 ? "…" : ""), ...await crackHash(h, extra ?? [], { wordlist: wl, maxCandidates }) });
|
|
60234
60454
|
}
|
|
60235
60455
|
return { content: [{ type: "text", text: JSON.stringify({ hashes_scanned: results.length, results }) }] };
|
|
60236
60456
|
});
|
|
@@ -60462,6 +60682,29 @@ ${statusLine}` : statusLine },
|
|
|
60462
60682
|
}, async (input) => {
|
|
60463
60683
|
return { content: [{ type: "text", text: JSON.stringify(await validateLeakedKey(input)) }] };
|
|
60464
60684
|
});
|
|
60685
|
+
server.registerTool("hackbot_arena_list", {
|
|
60686
|
+
title: "List Hackbot Arena benchmark labs",
|
|
60687
|
+
description: "BENCHMARK: list the 30 Hackbot Arena (NusaSec) dockerized web-security labs — a local benchmark of realistic vulnerability chains with deterministic flags. Returns id/name/difficulty/port/vuln_class per lab (evaluator view; no flags or solutions).",
|
|
60688
|
+
inputSchema: {}
|
|
60689
|
+
}, async () => {
|
|
60690
|
+
return { content: [{ type: "text", text: JSON.stringify(hackbotArenaList()) }] };
|
|
60691
|
+
});
|
|
60692
|
+
server.registerTool("hackbot_arena_brief", {
|
|
60693
|
+
title: "Attack-plan brief for one Hackbot Arena lab",
|
|
60694
|
+
description: "BENCHMARK: given a lab id (e.g. labs03), return the target URL, vuln class, stack, flag format, and the DERIVED Blitz Strike attack plan (vectors/detectors/chains/tools) to solve it. This is the agent brief — it never contains the flag, judge criteria, or reference solution.",
|
|
60695
|
+
inputSchema: {
|
|
60696
|
+
labId: string2().describe("Lab id (e.g. labs03, labs20)")
|
|
60697
|
+
}
|
|
60698
|
+
}, async ({ labId }) => {
|
|
60699
|
+
return { content: [{ type: "text", text: JSON.stringify(hackbotArenaBrief(labId)) }] };
|
|
60700
|
+
});
|
|
60701
|
+
server.registerTool("hackbot_arena_coverage", {
|
|
60702
|
+
title: "Blitz Strike coverage vs Hackbot Arena",
|
|
60703
|
+
description: "BENCHMARK: map all 30 Hackbot Arena labs against Blitz Strike's detector/vector coverage — which vuln classes Blitz Strike has deterministic tooling for, per lab, plus the derived chains.",
|
|
60704
|
+
inputSchema: {}
|
|
60705
|
+
}, async () => {
|
|
60706
|
+
return { content: [{ type: "text", text: JSON.stringify(hackbotArenaCoverage()) }] };
|
|
60707
|
+
});
|
|
60465
60708
|
server.registerTool("fofa_search", {
|
|
60466
60709
|
title: "FOFA asset search",
|
|
60467
60710
|
description: "STRIKE: search the FOFA asset index (needs FOFA_EMAIL + FOFA_KEY).",
|
|
@@ -60847,7 +61090,7 @@ ${statusLine}` : statusLine },
|
|
|
60847
61090
|
let src = code;
|
|
60848
61091
|
if (!src && path) {
|
|
60849
61092
|
try {
|
|
60850
|
-
src =
|
|
61093
|
+
src = readFileSync27(path, "utf8");
|
|
60851
61094
|
} catch {
|
|
60852
61095
|
return { content: [{ type: "text", text: JSON.stringify({ error: "unreadable path" }) }] };
|
|
60853
61096
|
}
|
|
@@ -61465,7 +61708,7 @@ ${statusLine}` : statusLine },
|
|
|
61465
61708
|
description: "Route confusion (separate class from source→sink taint): detect attacker-controlled dispatch (call_user_func/forward/dispatch), dynamic method calls ($obj->$m()), dynamic include (LFI), batch/proxy forwarding without per-route auth re-check, and route matching without path normalization.",
|
|
61466
61709
|
inputSchema: { path: string2().describe("Source file path (PHP)") }
|
|
61467
61710
|
}, async ({ path }) => {
|
|
61468
|
-
const code =
|
|
61711
|
+
const code = readFileSync27(path, "utf8");
|
|
61469
61712
|
const findings = detectRouteConfusion(code, path);
|
|
61470
61713
|
return {
|
|
61471
61714
|
content: [{
|
|
@@ -61479,7 +61722,7 @@ ${statusLine}` : statusLine },
|
|
|
61479
61722
|
description: "Complex-bug detection beyond taint: deserialization→POP gadget chain (unserialize + magic method), type juggling (loose ==/!= vs hash/secret), mass assignment (extract/parse_str without a safe flag), prototype pollution (unsafe merge of request data), CRLF/header injection (user input into a header), path confusion (user input into a file path without canonicalization), SSRF (user-controlled URL with no host allowlist), XXE (user XML parsed without disabling entities), SSTI (user input into a template render with no sandbox), wrong-context sanitization (sanitize_text_field() into a SQL query), and missing authorization/nonce on WordPress entry points (wp_ajax_* / admin_post_* / register_rest_route without current_user_can, nonce verification, or permission_callback).",
|
|
61480
61723
|
inputSchema: { path: string2().describe("Source file path") }
|
|
61481
61724
|
}, async ({ path }) => {
|
|
61482
|
-
const code =
|
|
61725
|
+
const code = readFileSync27(path, "utf8");
|
|
61483
61726
|
const findings = detectComplexBugs(code, path);
|
|
61484
61727
|
return {
|
|
61485
61728
|
content: [{
|
|
@@ -61565,7 +61808,7 @@ ${statusLine}` : statusLine },
|
|
|
61565
61808
|
let lang = language;
|
|
61566
61809
|
if (path && !code) {
|
|
61567
61810
|
try {
|
|
61568
|
-
src =
|
|
61811
|
+
src = readFileSync27(path, "utf8");
|
|
61569
61812
|
} catch {
|
|
61570
61813
|
return { content: [{ type: "text", text: JSON.stringify({ error: `cannot read ${path}` }) }] };
|
|
61571
61814
|
}
|
|
@@ -61814,15 +62057,15 @@ async function serve() {
|
|
|
61814
62057
|
|
|
61815
62058
|
// src/index.ts
|
|
61816
62059
|
init_cli();
|
|
61817
|
-
import { readFileSync as
|
|
61818
|
-
import { join as
|
|
61819
|
-
import { fileURLToPath as
|
|
61820
|
-
var ROOT11 =
|
|
62060
|
+
import { readFileSync as readFileSync31, existsSync as existsSync16 } from "node:fs";
|
|
62061
|
+
import { join as join28 } from "node:path";
|
|
62062
|
+
import { fileURLToPath as fileURLToPath17 } from "node:url";
|
|
62063
|
+
var ROOT11 = join28(fileURLToPath17(new URL(".", import.meta.url)), "..");
|
|
61821
62064
|
function readVersion() {
|
|
61822
62065
|
try {
|
|
61823
|
-
const p =
|
|
61824
|
-
if (
|
|
61825
|
-
return JSON.parse(
|
|
62066
|
+
const p = join28(ROOT11, "package.json");
|
|
62067
|
+
if (existsSync16(p))
|
|
62068
|
+
return JSON.parse(readFileSync31(p, "utf8")).version ?? "1.0.0";
|
|
61826
62069
|
} catch {}
|
|
61827
62070
|
return "1.0.0";
|
|
61828
62071
|
}
|