blitzstrike 1.0.51 → 1.0.52
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 +14 -0
- package/dist/index.js +287 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,20 @@ All notable changes to Blitz Strike are documented here.
|
|
|
5
5
|
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
7
7
|
|
|
8
|
+
## [1.0.52] — 2026-09-13
|
|
9
|
+
|
|
10
|
+
### Added — Autonomous Security Engine (phase 12: browser automation agent)
|
|
11
|
+
|
|
12
|
+
- **Browser Automation Agent** (`src/browser-agent.ts`, §16):
|
|
13
|
+
- Session-based (one persistent page) so multi-step flows work.
|
|
14
|
+
- Ops: `open`/`navigate`/`click`/`type`/`evaluate`/`screenshot`/`back`/`forward`/
|
|
15
|
+
`get_cookie`/`set_cookie`, plus `detectAuthForm()` and `browserDiagnostics()`.
|
|
16
|
+
- Graceful degradation — every op reports `unavailable` when `playwright-core`
|
|
17
|
+
(optional peer) is missing, never throws.
|
|
18
|
+
- New `@browser` mission agent (URL-scope-gated) — detects login forms and JS
|
|
19
|
+
runtime errors and emits auth-flow hypotheses.
|
|
20
|
+
- New MCP tool `browser_agent` (session ops + detect_auth_form + diagnostics + close).
|
|
21
|
+
|
|
8
22
|
## [1.0.51] — 2026-09-13
|
|
9
23
|
|
|
10
24
|
### Added — Autonomous Security Engine (phase 11: adversarial reviewer)
|
package/dist/index.js
CHANGED
|
@@ -17722,6 +17722,219 @@ var init_universal_taint = __esm(() => {
|
|
|
17722
17722
|
extensionMap = new Map;
|
|
17723
17723
|
});
|
|
17724
17724
|
|
|
17725
|
+
// src/browser-agent.ts
|
|
17726
|
+
async function ensureChromium2() {
|
|
17727
|
+
if (chromiumCache2)
|
|
17728
|
+
return chromiumCache2;
|
|
17729
|
+
try {
|
|
17730
|
+
chromiumCache2 = await import("playwright-core");
|
|
17731
|
+
return chromiumCache2;
|
|
17732
|
+
} catch {
|
|
17733
|
+
return null;
|
|
17734
|
+
}
|
|
17735
|
+
}
|
|
17736
|
+
async function ensureSession() {
|
|
17737
|
+
if (page)
|
|
17738
|
+
return { available: true };
|
|
17739
|
+
const chr = await ensureChromium2();
|
|
17740
|
+
if (!chr)
|
|
17741
|
+
return { available: false, reason: "playwright-core not installed (optional peer dependency)" };
|
|
17742
|
+
try {
|
|
17743
|
+
browser = await chr.chromium.launch({ headless: true });
|
|
17744
|
+
page = await browser.newPage();
|
|
17745
|
+
page.on("console", (m) => {
|
|
17746
|
+
const msg = m;
|
|
17747
|
+
if (msg.type() === "error")
|
|
17748
|
+
consoleErrors.push(msg.text());
|
|
17749
|
+
});
|
|
17750
|
+
page.on("pageerror", (e) => pageErrors.push(String(e)));
|
|
17751
|
+
return { available: true };
|
|
17752
|
+
} catch (e) {
|
|
17753
|
+
return { available: false, reason: e instanceof Error ? e.message : String(e) };
|
|
17754
|
+
}
|
|
17755
|
+
}
|
|
17756
|
+
function unavailable2(op, reason) {
|
|
17757
|
+
return { op, ok: false, unavailable: true, detail: reason };
|
|
17758
|
+
}
|
|
17759
|
+
function fail(op, e) {
|
|
17760
|
+
return { op, ok: false, unavailable: false, detail: e instanceof Error ? e.message : String(e) };
|
|
17761
|
+
}
|
|
17762
|
+
async function browserOpen(url) {
|
|
17763
|
+
const s = await ensureSession();
|
|
17764
|
+
if (!s.available || !page)
|
|
17765
|
+
return unavailable2("open", s.reason ?? "unavailable");
|
|
17766
|
+
try {
|
|
17767
|
+
await page.goto(url, { waitUntil: "domcontentloaded", timeout: 20000 });
|
|
17768
|
+
return { op: "open", ok: true, unavailable: false, detail: `opened ${redactSecrets(page.url())}` };
|
|
17769
|
+
} catch (e) {
|
|
17770
|
+
return fail("open", e);
|
|
17771
|
+
}
|
|
17772
|
+
}
|
|
17773
|
+
async function browserNavigate(url) {
|
|
17774
|
+
return browserOpen(url);
|
|
17775
|
+
}
|
|
17776
|
+
async function browserClick(selector) {
|
|
17777
|
+
const s = await ensureSession();
|
|
17778
|
+
if (!s.available || !page)
|
|
17779
|
+
return unavailable2("click", s.reason ?? "unavailable");
|
|
17780
|
+
try {
|
|
17781
|
+
await page.click(selector);
|
|
17782
|
+
return { op: "click", ok: true, unavailable: false, detail: `clicked ${selector}` };
|
|
17783
|
+
} catch (e) {
|
|
17784
|
+
return fail("click", e);
|
|
17785
|
+
}
|
|
17786
|
+
}
|
|
17787
|
+
async function browserType(selector, text) {
|
|
17788
|
+
const s = await ensureSession();
|
|
17789
|
+
if (!s.available || !page)
|
|
17790
|
+
return unavailable2("type", s.reason ?? "unavailable");
|
|
17791
|
+
try {
|
|
17792
|
+
await page.fill(selector, text);
|
|
17793
|
+
return { op: "type", ok: true, unavailable: false, detail: `typed into ${selector}` };
|
|
17794
|
+
} catch (e) {
|
|
17795
|
+
return fail("type", e);
|
|
17796
|
+
}
|
|
17797
|
+
}
|
|
17798
|
+
async function browserEvaluate(js) {
|
|
17799
|
+
const s = await ensureSession();
|
|
17800
|
+
if (!s.available || !page)
|
|
17801
|
+
return unavailable2("evaluate", s.reason ?? "unavailable");
|
|
17802
|
+
try {
|
|
17803
|
+
const value = await page.evaluate((code) => {
|
|
17804
|
+
const fn = new Function(`"use strict"; return (${code})`)();
|
|
17805
|
+
return typeof fn === "function" ? fn() : fn;
|
|
17806
|
+
}, js);
|
|
17807
|
+
return { op: "evaluate", ok: true, unavailable: false, detail: "evaluated", value };
|
|
17808
|
+
} catch (e) {
|
|
17809
|
+
return fail("evaluate", e);
|
|
17810
|
+
}
|
|
17811
|
+
}
|
|
17812
|
+
async function browserScreenshot(path) {
|
|
17813
|
+
const s = await ensureSession();
|
|
17814
|
+
if (!s.available || !page)
|
|
17815
|
+
return unavailable2("screenshot", s.reason ?? "unavailable");
|
|
17816
|
+
try {
|
|
17817
|
+
const buf = await page.screenshot(path ? { path } : {});
|
|
17818
|
+
return { op: "screenshot", ok: true, unavailable: false, detail: path ? `saved ${path}` : "captured (in-memory)", value: path ? undefined : buf.byteLength };
|
|
17819
|
+
} catch (e) {
|
|
17820
|
+
return fail("screenshot", e);
|
|
17821
|
+
}
|
|
17822
|
+
}
|
|
17823
|
+
async function browserBack() {
|
|
17824
|
+
const s = await ensureSession();
|
|
17825
|
+
if (!s.available || !page)
|
|
17826
|
+
return unavailable2("back", s.reason ?? "unavailable");
|
|
17827
|
+
try {
|
|
17828
|
+
await page.goBack();
|
|
17829
|
+
return { op: "back", ok: true, unavailable: false, detail: `back to ${redactSecrets(page.url())}` };
|
|
17830
|
+
} catch (e) {
|
|
17831
|
+
return fail("back", e);
|
|
17832
|
+
}
|
|
17833
|
+
}
|
|
17834
|
+
async function browserForward() {
|
|
17835
|
+
const s = await ensureSession();
|
|
17836
|
+
if (!s.available || !page)
|
|
17837
|
+
return unavailable2("forward", s.reason ?? "unavailable");
|
|
17838
|
+
try {
|
|
17839
|
+
await page.goForward();
|
|
17840
|
+
return { op: "forward", ok: true, unavailable: false, detail: `forward to ${redactSecrets(page.url())}` };
|
|
17841
|
+
} catch (e) {
|
|
17842
|
+
return fail("forward", e);
|
|
17843
|
+
}
|
|
17844
|
+
}
|
|
17845
|
+
async function browserGetCookie(name) {
|
|
17846
|
+
const s = await ensureSession();
|
|
17847
|
+
if (!s.available || !page)
|
|
17848
|
+
return unavailable2("get_cookie", s.reason ?? "unavailable");
|
|
17849
|
+
try {
|
|
17850
|
+
const cookies = await page.context().cookies();
|
|
17851
|
+
const hit = cookies.filter((c) => c.name === name);
|
|
17852
|
+
return { op: "get_cookie", ok: true, unavailable: false, detail: hit.length ? "found" : "not found", value: hit };
|
|
17853
|
+
} catch (e) {
|
|
17854
|
+
return fail("get_cookie", e);
|
|
17855
|
+
}
|
|
17856
|
+
}
|
|
17857
|
+
async function browserSetCookie(name, value) {
|
|
17858
|
+
const s = await ensureSession();
|
|
17859
|
+
if (!s.available || !page)
|
|
17860
|
+
return unavailable2("set_cookie", s.reason ?? "unavailable");
|
|
17861
|
+
try {
|
|
17862
|
+
const url = page.url();
|
|
17863
|
+
await page.context().addCookies([{ name, value, url }]);
|
|
17864
|
+
return { op: "set_cookie", ok: true, unavailable: false, detail: `set ${name}` };
|
|
17865
|
+
} catch (e) {
|
|
17866
|
+
return fail("set_cookie", e);
|
|
17867
|
+
}
|
|
17868
|
+
}
|
|
17869
|
+
async function browserClose() {
|
|
17870
|
+
if (browser) {
|
|
17871
|
+
await browser.close().catch(() => {
|
|
17872
|
+
return;
|
|
17873
|
+
});
|
|
17874
|
+
browser = null;
|
|
17875
|
+
page = null;
|
|
17876
|
+
}
|
|
17877
|
+
}
|
|
17878
|
+
async function detectAuthForm() {
|
|
17879
|
+
const s = await ensureSession();
|
|
17880
|
+
if (!s.available || !page)
|
|
17881
|
+
return unavailable2("evaluate", s.reason ?? "unavailable");
|
|
17882
|
+
try {
|
|
17883
|
+
const value = await page.evaluate(() => {
|
|
17884
|
+
const forms = Array.from(document.querySelectorAll("form"));
|
|
17885
|
+
const loginForm = forms.find((f) => /login|signin|auth/i.test(f.action || "") || f.querySelector('input[type="password"]'));
|
|
17886
|
+
if (!loginForm)
|
|
17887
|
+
return { found: false };
|
|
17888
|
+
const userField = loginForm.querySelector('input[type="email"], input[type="text"], input[name*="user"], input[name*="email"], input[name*="login"]');
|
|
17889
|
+
const passField = loginForm.querySelector('input[type="password"]');
|
|
17890
|
+
return {
|
|
17891
|
+
found: true,
|
|
17892
|
+
action: loginForm.action || "(self)",
|
|
17893
|
+
has_user: Boolean(userField),
|
|
17894
|
+
has_pass: Boolean(passField),
|
|
17895
|
+
user_selector: userField ? `input[name="${userField.name || ""}"], input[type="${userField.type}"]` : null,
|
|
17896
|
+
pass_selector: passField ? 'input[type="password"]' : null
|
|
17897
|
+
};
|
|
17898
|
+
});
|
|
17899
|
+
return { op: "evaluate", ok: true, unavailable: false, detail: value.found ? "login form detected" : "no login form", value };
|
|
17900
|
+
} catch (e) {
|
|
17901
|
+
return fail("evaluate", e);
|
|
17902
|
+
}
|
|
17903
|
+
}
|
|
17904
|
+
async function browserAgent(op, args = []) {
|
|
17905
|
+
switch (op) {
|
|
17906
|
+
case "open":
|
|
17907
|
+
return browserOpen(args[0] ?? "");
|
|
17908
|
+
case "navigate":
|
|
17909
|
+
return browserNavigate(args[0] ?? "");
|
|
17910
|
+
case "click":
|
|
17911
|
+
return browserClick(args[0] ?? "");
|
|
17912
|
+
case "type":
|
|
17913
|
+
return browserType(args[0] ?? "", args[1] ?? "");
|
|
17914
|
+
case "evaluate":
|
|
17915
|
+
return browserEvaluate(args[0] ?? "");
|
|
17916
|
+
case "screenshot":
|
|
17917
|
+
return browserScreenshot(args[0] || undefined);
|
|
17918
|
+
case "back":
|
|
17919
|
+
return browserBack();
|
|
17920
|
+
case "forward":
|
|
17921
|
+
return browserForward();
|
|
17922
|
+
case "get_cookie":
|
|
17923
|
+
return browserGetCookie(args[0] ?? "");
|
|
17924
|
+
case "set_cookie":
|
|
17925
|
+
return browserSetCookie(args[0] ?? "", args[1] ?? "");
|
|
17926
|
+
}
|
|
17927
|
+
}
|
|
17928
|
+
function browserDiagnostics() {
|
|
17929
|
+
return { console_errors: [...consoleErrors], page_errors: [...pageErrors] };
|
|
17930
|
+
}
|
|
17931
|
+
var chromiumCache2 = null, browser = null, page = null, consoleErrors, pageErrors;
|
|
17932
|
+
var init_browser_agent = __esm(() => {
|
|
17933
|
+
init_evidence();
|
|
17934
|
+
consoleErrors = [];
|
|
17935
|
+
pageErrors = [];
|
|
17936
|
+
});
|
|
17937
|
+
|
|
17725
17938
|
// src/sync.ts
|
|
17726
17939
|
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync4, readFileSync as readFileSync16, readdirSync as readdirSync5, statSync as statSync3, rmSync as rmSync3 } from "node:fs";
|
|
17727
17940
|
import { join as join12 } from "node:path";
|
|
@@ -18359,7 +18572,7 @@ function sourceFiles(root, max = 500) {
|
|
|
18359
18572
|
function agentFor(type) {
|
|
18360
18573
|
return AGENTS[type];
|
|
18361
18574
|
}
|
|
18362
|
-
var reconAgent, webAgent, sourceAgent, analysisAgent, authAgent, validatorAgent, reviewerAgent, reporterAgent, mobileAgent, cloudAgent, commanderAgent, apiAgent, AGENTS;
|
|
18575
|
+
var reconAgent, webAgent, sourceAgent, analysisAgent, authAgent, validatorAgent, reviewerAgent, browserAgent2, reporterAgent, mobileAgent, cloudAgent, commanderAgent, apiAgent, AGENTS;
|
|
18363
18576
|
var init_agents = __esm(() => {
|
|
18364
18577
|
init_planner();
|
|
18365
18578
|
init_reviewer();
|
|
@@ -18556,6 +18769,52 @@ var init_agents = __esm(() => {
|
|
|
18556
18769
|
return { ok: true, output: { outcomes: results.map((r) => ({ id: r.hypothesis_id, outcome: r.outcome })) }, hypotheses, graph: emptyGraph() };
|
|
18557
18770
|
}
|
|
18558
18771
|
};
|
|
18772
|
+
browserAgent2 = {
|
|
18773
|
+
type: "browser",
|
|
18774
|
+
responsibility: "Drive a real browser to detect DOM issues and auth flows.",
|
|
18775
|
+
tools: ["browser_open", "browser_click", "browser_type", "browser_evaluate", "browser_screenshot", "browser_navigate", "browser_back", "browser_forward", "browser_get_cookie", "browser_set_cookie"],
|
|
18776
|
+
async execute(_task, ctx) {
|
|
18777
|
+
if (!/^https?:\/\//i.test(ctx.mission.target) || !ctx.scopeAllowed) {
|
|
18778
|
+
return { ok: false, output: {}, hypotheses: [], graph: emptyGraph(), error: "browser agent requires an authorized URL target" };
|
|
18779
|
+
}
|
|
18780
|
+
await Promise.resolve().then(() => init_browser_agent());
|
|
18781
|
+
const opened = await browserOpen(ctx.mission.target);
|
|
18782
|
+
if (opened.unavailable) {
|
|
18783
|
+
return { ok: false, output: {}, hypotheses: [], graph: emptyGraph(), error: opened.detail };
|
|
18784
|
+
}
|
|
18785
|
+
const auth = await detectAuthForm();
|
|
18786
|
+
const diag = browserDiagnostics();
|
|
18787
|
+
await browserClose();
|
|
18788
|
+
const hypotheses = [];
|
|
18789
|
+
const authInfo = auth.value ?? {};
|
|
18790
|
+
if (authInfo.found) {
|
|
18791
|
+
hypotheses.push(makeHypothesis({
|
|
18792
|
+
type: "auth_flow_detected",
|
|
18793
|
+
target: ctx.mission.target,
|
|
18794
|
+
evidence: `login form detected (user_field=${authInfo.has_user}, pass_field=${authInfo.has_pass})`,
|
|
18795
|
+
confidence: 0.6,
|
|
18796
|
+
required_validation: "login flow",
|
|
18797
|
+
potential_impact: "auth boundary"
|
|
18798
|
+
}));
|
|
18799
|
+
}
|
|
18800
|
+
if (diag.console_errors.length > 0 || diag.page_errors.length > 0) {
|
|
18801
|
+
hypotheses.push(makeHypothesis({
|
|
18802
|
+
type: "js_runtime_error",
|
|
18803
|
+
target: ctx.mission.target,
|
|
18804
|
+
evidence: `console_errors=${diag.console_errors.length} page_errors=${diag.page_errors.length}`,
|
|
18805
|
+
confidence: 0.4,
|
|
18806
|
+
required_validation: "review",
|
|
18807
|
+
potential_impact: "unspecified"
|
|
18808
|
+
}));
|
|
18809
|
+
}
|
|
18810
|
+
return {
|
|
18811
|
+
ok: true,
|
|
18812
|
+
output: { opened: opened.ok, auth_form: authInfo.found ?? false, console_errors: diag.console_errors.length, page_errors: diag.page_errors.length },
|
|
18813
|
+
hypotheses,
|
|
18814
|
+
graph: emptyGraph()
|
|
18815
|
+
};
|
|
18816
|
+
}
|
|
18817
|
+
};
|
|
18559
18818
|
reporterAgent = {
|
|
18560
18819
|
type: "reporter",
|
|
18561
18820
|
responsibility: "Produce the final structured mission report.",
|
|
@@ -18666,7 +18925,8 @@ ${m.hypotheses.map((h) => `- [${h.status}] ${h.type} @ ${h.target} (confidence $
|
|
|
18666
18925
|
analysis: analysisAgent,
|
|
18667
18926
|
validator: validatorAgent,
|
|
18668
18927
|
reviewer: reviewerAgent,
|
|
18669
|
-
reporter: reporterAgent
|
|
18928
|
+
reporter: reporterAgent,
|
|
18929
|
+
browser: browserAgent2
|
|
18670
18930
|
};
|
|
18671
18931
|
});
|
|
18672
18932
|
|
|
@@ -18792,7 +19052,8 @@ var init_recovery = __esm(() => {
|
|
|
18792
19052
|
analysis: ["source"],
|
|
18793
19053
|
validator: ["reviewer"],
|
|
18794
19054
|
reviewer: ["validator"],
|
|
18795
|
-
reporter: []
|
|
19055
|
+
reporter: [],
|
|
19056
|
+
browser: ["web"]
|
|
18796
19057
|
};
|
|
18797
19058
|
});
|
|
18798
19059
|
|
|
@@ -53121,6 +53382,7 @@ async function browserValidate(check, target, payload) {
|
|
|
53121
53382
|
}
|
|
53122
53383
|
|
|
53123
53384
|
// src/server.ts
|
|
53385
|
+
init_browser_agent();
|
|
53124
53386
|
init_universal_taint();
|
|
53125
53387
|
|
|
53126
53388
|
// src/guidance.ts
|
|
@@ -54684,6 +54946,28 @@ function createServer() {
|
|
|
54684
54946
|
const result = await browserValidate(check, target, payload);
|
|
54685
54947
|
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
|
54686
54948
|
});
|
|
54949
|
+
server.registerTool("browser_agent", {
|
|
54950
|
+
title: "Browser automation agent (session)",
|
|
54951
|
+
description: "PHASE 12: drive a real headless-Chromium session. Ops: open, navigate, click, type, evaluate, screenshot, back, forward, get_cookie, set_cookie, plus detect_auth_form, diagnostics, close. Enables multi-step flows (login/MFA) and DOM issue detection. Requires playwright-core (optional peer dependency).",
|
|
54952
|
+
inputSchema: {
|
|
54953
|
+
op: _enum(["open", "navigate", "click", "type", "evaluate", "screenshot", "back", "forward", "get_cookie", "set_cookie", "detect_auth_form", "diagnostics", "close"]),
|
|
54954
|
+
args: array(string2()).optional().describe("Positional args (url, selector, text, js, cookie name/value, screenshot path)")
|
|
54955
|
+
}
|
|
54956
|
+
}, async ({ op, args }) => {
|
|
54957
|
+
if (op === "detect_auth_form") {
|
|
54958
|
+
const r = await detectAuthForm();
|
|
54959
|
+
return { content: [{ type: "text", text: JSON.stringify(r) }] };
|
|
54960
|
+
}
|
|
54961
|
+
if (op === "diagnostics") {
|
|
54962
|
+
return { content: [{ type: "text", text: JSON.stringify(browserDiagnostics()) }] };
|
|
54963
|
+
}
|
|
54964
|
+
if (op === "close") {
|
|
54965
|
+
await browserClose();
|
|
54966
|
+
return { content: [{ type: "text", text: JSON.stringify({ ok: true, detail: "session closed" }) }] };
|
|
54967
|
+
}
|
|
54968
|
+
const r = await browserAgent(op, args ?? []);
|
|
54969
|
+
return { content: [{ type: "text", text: JSON.stringify(r) }] };
|
|
54970
|
+
});
|
|
54687
54971
|
server.registerTool("taint_tree", {
|
|
54688
54972
|
title: "Whole-tree taint scan",
|
|
54689
54973
|
description: "EAGLE-EYE: run inter-procedural taint analysis across an entire source tree.",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "blitzstrike",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.52",
|
|
4
4
|
"description": "Blitz Strike — a universal MCP security-audit toolbelt. BLITZ sweeps the attack surface, EAGLE-EYE traces source-to-sink, STRIKE verifies live. 57 attack chains, 130-tool catalog, intelligence data layer. One server, every agent.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|