blitzstrike 2.4.35 → 2.4.37
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 +19 -0
- package/dist/index.js +139 -99
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,25 @@ 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
|
+
## [2.4.37] — 2026-09-14
|
|
9
|
+
|
|
10
|
+
### Fixed — benchmark top-level recall/f1 (self-audit)
|
|
11
|
+
|
|
12
|
+
- `run_benchmark` now returns top-level `recall` and `f1` (previously only
|
|
13
|
+
`detection_rate` held the recall value, and no top-level f1). Matches the
|
|
14
|
+
per-detector shape for consistency. No functional change.
|
|
15
|
+
|
|
16
|
+
## [2.4.36] — 2026-09-14
|
|
17
|
+
|
|
18
|
+
### Changed — Framework Knowledge Graph is now MULTI-framework (not WordPress-only)
|
|
19
|
+
|
|
20
|
+
- `framework-security.ts` now covers 9 frameworks: WordPress, Laravel, Django,
|
|
21
|
+
Flask, Express, Spring, Symfony, ASP.NET Core, Ruby on Rails — each with its
|
|
22
|
+
auth / nonce / entry-point / sanitizer primitives as data.
|
|
23
|
+
- `detectMissingAuthz` now detects missing authorization across ALL frameworks
|
|
24
|
+
(route middleware, decorators, annotations), not just WP AJAX/REST hooks.
|
|
25
|
+
- `framework_knowledge` tool returns the framework list on an unknown id.
|
|
26
|
+
|
|
8
27
|
## [2.4.35] — 2026-09-14
|
|
9
28
|
|
|
10
29
|
### Added — Variant Mining (confirm once, weaponize everywhere)
|
package/dist/index.js
CHANGED
|
@@ -56260,52 +56260,94 @@ function detectWrongSanitizer(code, file) {
|
|
|
56260
56260
|
}
|
|
56261
56261
|
|
|
56262
56262
|
// src/framework-security.ts
|
|
56263
|
-
var WP_PRIMITIVES = {
|
|
56264
|
-
framework: "wordpress",
|
|
56265
|
-
auth_primitives: [
|
|
56266
|
-
"current_user_can",
|
|
56267
|
-
"current_user_can_edit_post",
|
|
56268
|
-
"current_user_can_for_blog",
|
|
56269
|
-
"current_user_can_edit_others_posts",
|
|
56270
|
-
"is_user_logged_in",
|
|
56271
|
-
"authorize"
|
|
56272
|
-
],
|
|
56273
|
-
nonce_primitives: [
|
|
56274
|
-
"wp_verify_nonce",
|
|
56275
|
-
"check_ajax_referer",
|
|
56276
|
-
"check_admin_referer",
|
|
56277
|
-
"verify_nonce"
|
|
56278
|
-
],
|
|
56279
|
-
entry_point_hooks: [
|
|
56280
|
-
"wp_ajax_",
|
|
56281
|
-
"wp_ajax_nopriv_",
|
|
56282
|
-
"admin_post_",
|
|
56283
|
-
"admin_post_nopriv_",
|
|
56284
|
-
"register_rest_route",
|
|
56285
|
-
"add_shortcode",
|
|
56286
|
-
"init",
|
|
56287
|
-
"rest_api_init"
|
|
56288
|
-
],
|
|
56289
|
-
sanitizers: [
|
|
56290
|
-
"sanitize_text_field",
|
|
56291
|
-
"esc_sql",
|
|
56292
|
-
"esc_html",
|
|
56293
|
-
"esc_attr",
|
|
56294
|
-
"esc_url",
|
|
56295
|
-
"wp_kses",
|
|
56296
|
-
"wp_kses_post",
|
|
56297
|
-
"absint",
|
|
56298
|
-
"sanitize_email",
|
|
56299
|
-
"sanitize_file_name"
|
|
56300
|
-
]
|
|
56301
|
-
};
|
|
56302
56263
|
var FRAMEWORKS = {
|
|
56303
|
-
wordpress:
|
|
56304
|
-
|
|
56264
|
+
wordpress: {
|
|
56265
|
+
framework: "wordpress",
|
|
56266
|
+
auth_primitives: ["current_user_can", "current_user_can_edit_post", "is_user_logged_in", "authorize"],
|
|
56267
|
+
nonce_primitives: ["wp_verify_nonce", "check_ajax_referer", "check_admin_referer", "verify_nonce"],
|
|
56268
|
+
entry_point_hooks: ["wp_ajax_", "wp_ajax_nopriv_", "admin_post_", "admin_post_nopriv_", "register_rest_route", "add_shortcode", "init", "rest_api_init"],
|
|
56269
|
+
sanitizers: ["sanitize_text_field", "esc_sql", "esc_html", "esc_attr", "esc_url", "wp_kses", "wp_kses_post", "absint", "sanitize_email", "sanitize_file_name"]
|
|
56270
|
+
},
|
|
56271
|
+
wp: {
|
|
56272
|
+
framework: "wordpress",
|
|
56273
|
+
auth_primitives: ["current_user_can", "is_user_logged_in", "authorize"],
|
|
56274
|
+
nonce_primitives: ["wp_verify_nonce", "check_ajax_referer", "check_admin_referer"],
|
|
56275
|
+
entry_point_hooks: ["wp_ajax_", "wp_ajax_nopriv_", "register_rest_route"],
|
|
56276
|
+
sanitizers: ["sanitize_text_field", "esc_sql", "esc_html", "absint"]
|
|
56277
|
+
},
|
|
56278
|
+
laravel: {
|
|
56279
|
+
framework: "laravel",
|
|
56280
|
+
auth_primitives: ["auth", "authorize", "Gate::", "can:", "->middleware('auth'", "->can(", "$this->authorize", "@can", "@cannot", "policy"],
|
|
56281
|
+
nonce_primitives: ["@csrf", "csrf_field", "VerifyCsrfToken"],
|
|
56282
|
+
entry_point_hooks: ["Route::get", "Route::post", "Route::put", "Route::delete", "Route::resource", "Route::match"],
|
|
56283
|
+
sanitizers: ["e(", "htmlspecialchars", "clean(", "strip_tags"]
|
|
56284
|
+
},
|
|
56285
|
+
django: {
|
|
56286
|
+
framework: "django",
|
|
56287
|
+
auth_primitives: ["login_required", "permission_required", "user_passes_test", "LoginRequiredMixin", "PermissionRequiredMixin", "permission_classes", "IsAuthenticated", "has_permission"],
|
|
56288
|
+
nonce_primitives: ["csrf_protect", "CsrfViewMiddleware", "@csrf"],
|
|
56289
|
+
entry_point_hooks: ["def ", "@api_view", "path(", "url(", "re_path("],
|
|
56290
|
+
sanitizers: ["escape(", "mark_safe", "html.escape"]
|
|
56291
|
+
},
|
|
56292
|
+
flask: {
|
|
56293
|
+
framework: "flask",
|
|
56294
|
+
auth_primitives: ["login_required", "@login_required", "current_user.is_authenticated", "permission_required"],
|
|
56295
|
+
nonce_primitives: ["CSRFProtect", "csrf_token"],
|
|
56296
|
+
entry_point_hooks: ["@app.route", "@blueprint.route", "@bp.route"],
|
|
56297
|
+
sanitizers: ["escape(", "Markup", "html.escape"]
|
|
56298
|
+
},
|
|
56299
|
+
express: {
|
|
56300
|
+
framework: "express",
|
|
56301
|
+
auth_primitives: ["requireAuth", "authenticate", "passport.authenticate", "req.user", "isAuthenticated", "ensureAuthenticated", "requireLogin", "authorize", "authMiddleware"],
|
|
56302
|
+
nonce_primitives: ["csurf", "csrfProtection", "helmet"],
|
|
56303
|
+
entry_point_hooks: ["app.get", "app.post", "router.get", "router.post"],
|
|
56304
|
+
sanitizers: ["escapeHtml", "encodeURIComponent", "sanitize", "xss"]
|
|
56305
|
+
},
|
|
56306
|
+
spring: {
|
|
56307
|
+
framework: "spring",
|
|
56308
|
+
auth_primitives: ["@PreAuthorize", "@Secured", "@RolesAllowed", "hasRole", "hasAuthority", "isAuthenticated", "SecurityContextHolder"],
|
|
56309
|
+
nonce_primitives: ["csrf", "CsrfToken"],
|
|
56310
|
+
entry_point_hooks: ["@GetMapping", "@PostMapping", "@RequestMapping", "@Controller"],
|
|
56311
|
+
sanitizers: ["HtmlUtils.htmlEscape", "escapeHtml", "StringEscapeUtils"]
|
|
56312
|
+
},
|
|
56313
|
+
symfony: {
|
|
56314
|
+
framework: "symfony",
|
|
56315
|
+
auth_primitives: ["is_granted", "denyAccessUnlessGranted", "->isGranted(", "IsGranted", "Voter"],
|
|
56316
|
+
nonce_primitives: ["isCsrfTokenValid", "csrf_token"],
|
|
56317
|
+
entry_point_hooks: ["#[Route", "@Route", "#[Get", "#[Post"],
|
|
56318
|
+
sanitizers: ["e(", "htmlspecialchars", "escape("]
|
|
56319
|
+
},
|
|
56320
|
+
aspnet: {
|
|
56321
|
+
framework: "aspnet",
|
|
56322
|
+
auth_primitives: ["[Authorize", "[AllowAnonymous", "User.Identity", "IsInRole", "AuthorizeAsync", "IAuthorizationService"],
|
|
56323
|
+
nonce_primitives: ["ValidateAntiForgeryToken", "Antiforgery"],
|
|
56324
|
+
entry_point_hooks: ["[HttpGet", "[HttpPost", "[Route("],
|
|
56325
|
+
sanitizers: ["HtmlEncoder", "Html.Raw", "UrlEncoder"]
|
|
56326
|
+
},
|
|
56327
|
+
rails: {
|
|
56328
|
+
framework: "rails",
|
|
56329
|
+
auth_primitives: ["authenticate_user!", "authorize", "before_action :authenticate", "before_action :authorize", "current_user"],
|
|
56330
|
+
nonce_primitives: ["protect_from_forgery", "form_authenticity_token"],
|
|
56331
|
+
entry_point_hooks: ["def ", "before_action"],
|
|
56332
|
+
sanitizers: ["h(", "html_escape", "sanitize"]
|
|
56333
|
+
}
|
|
56305
56334
|
};
|
|
56306
56335
|
function frameworkKnowledge(framework = "wordpress") {
|
|
56307
56336
|
return FRAMEWORKS[framework.toLowerCase()] ?? null;
|
|
56308
56337
|
}
|
|
56338
|
+
function listFrameworks2() {
|
|
56339
|
+
const s = new Set;
|
|
56340
|
+
for (const k of Object.keys(FRAMEWORKS))
|
|
56341
|
+
s.add(FRAMEWORKS[k].framework);
|
|
56342
|
+
return [...s];
|
|
56343
|
+
}
|
|
56344
|
+
function lineNoOf(code, pos) {
|
|
56345
|
+
let n = 1;
|
|
56346
|
+
for (let i = 0;i < pos; i++)
|
|
56347
|
+
if (code.charCodeAt(i) === 10)
|
|
56348
|
+
n++;
|
|
56349
|
+
return n;
|
|
56350
|
+
}
|
|
56309
56351
|
function functionBody(code, name) {
|
|
56310
56352
|
const idx = code.search(new RegExp(`function\\s+${name}\\s*\\(`));
|
|
56311
56353
|
if (idx === -1)
|
|
@@ -56325,16 +56367,8 @@ function functionBody(code, name) {
|
|
|
56325
56367
|
}
|
|
56326
56368
|
return code.slice(open);
|
|
56327
56369
|
}
|
|
56328
|
-
function lineNoOf(code, pos) {
|
|
56329
|
-
let n = 1;
|
|
56330
|
-
for (let i = 0;i < pos; i++)
|
|
56331
|
-
if (code.charCodeAt(i) === 10)
|
|
56332
|
-
n++;
|
|
56333
|
-
return n;
|
|
56334
|
-
}
|
|
56335
56370
|
var INDIRECT_AUTH = /\b[a-zA-Z0-9_]*(auth|permission|cap|nonce|can_|check|verify|allow)[a-zA-Z0-9_]*\s*\(/;
|
|
56336
|
-
function
|
|
56337
|
-
const out = [];
|
|
56371
|
+
function detectWpAuthz(code, file, out) {
|
|
56338
56372
|
const ajaxRe = /add_action\s*\(\s*['"](wp_ajax(?:_nopriv)?_\w+)['"]\s*,\s*['"](\w+)['"]/g;
|
|
56339
56373
|
let m;
|
|
56340
56374
|
while ((m = ajaxRe.exec(code)) !== null) {
|
|
@@ -56348,26 +56382,10 @@ function detectMissingAuthz(code, file) {
|
|
|
56348
56382
|
const hasNonce = /wp_verify_nonce|check_ajax_referer|check_admin_referer|verify_nonce/.test(body);
|
|
56349
56383
|
const line = lineNoOf(code, m.index);
|
|
56350
56384
|
if (nopriv && !hasCap) {
|
|
56351
|
-
out.push({
|
|
56352
|
-
file,
|
|
56353
|
-
line,
|
|
56354
|
-
type: "missing_authz",
|
|
56355
|
-
category: "Missing capability check (unauthenticated AJAX handler)",
|
|
56356
|
-
severity: "high",
|
|
56357
|
-
evidence: `add_action('${hook}', '${handler}')`,
|
|
56358
|
-
detail: `Unauthenticated AJAX handler '${handler}()' performs no current_user_can()/authorization check — any unauthenticated visitor can trigger it (auth bypass / privilege escalation).`
|
|
56359
|
-
});
|
|
56385
|
+
out.push({ file, line, type: "missing_authz", category: "Missing capability check (unauthenticated AJAX handler)", severity: "high", evidence: `add_action('${hook}', '${handler}')`, detail: `Unauthenticated AJAX handler '${handler}()' performs no current_user_can()/authorization check — any unauthenticated visitor can trigger it (auth bypass / privilege escalation).` });
|
|
56360
56386
|
}
|
|
56361
56387
|
if (!hasNonce) {
|
|
56362
|
-
out.push({
|
|
56363
|
-
file,
|
|
56364
|
-
line,
|
|
56365
|
-
type: "missing_nonce",
|
|
56366
|
-
category: "Missing nonce verification",
|
|
56367
|
-
severity: "medium",
|
|
56368
|
-
evidence: `add_action('${hook}', '${handler}')`,
|
|
56369
|
-
detail: `AJAX handler '${handler}()' does not verify a nonce (wp_verify_nonce / check_ajax_referer) — CSRF: an attacker can force an authenticated admin to trigger it.`
|
|
56370
|
-
});
|
|
56388
|
+
out.push({ file, line, type: "missing_nonce", category: "Missing nonce verification", severity: "medium", evidence: `add_action('${hook}', '${handler}')`, detail: `AJAX handler '${handler}()' does not verify a nonce (wp_verify_nonce / check_ajax_referer) — CSRF.` });
|
|
56371
56389
|
}
|
|
56372
56390
|
}
|
|
56373
56391
|
const adminRe = /add_action\s*\(\s*['"](admin_post(?:_nopriv)?_\w+)['"]\s*,\s*['"](\w+)['"]/g;
|
|
@@ -56382,26 +56400,10 @@ function detectMissingAuthz(code, file) {
|
|
|
56382
56400
|
const hasNonce = /wp_verify_nonce|check_admin_referer|verify_nonce/.test(body);
|
|
56383
56401
|
const line = lineNoOf(code, m.index);
|
|
56384
56402
|
if (nopriv && !hasCap) {
|
|
56385
|
-
out.push({
|
|
56386
|
-
file,
|
|
56387
|
-
line,
|
|
56388
|
-
type: "missing_authz",
|
|
56389
|
-
category: "Missing capability check (unauthenticated admin-post handler)",
|
|
56390
|
-
severity: "high",
|
|
56391
|
-
evidence: `add_action('${hook}', '${handler}')`,
|
|
56392
|
-
detail: `Unauthenticated admin-post handler '${handler}()' has no authorization check — auth bypass / privilege escalation.`
|
|
56393
|
-
});
|
|
56403
|
+
out.push({ file, line, type: "missing_authz", category: "Missing capability check (unauthenticated admin-post handler)", severity: "high", evidence: `add_action('${hook}', '${handler}')`, detail: `Unauthenticated admin-post handler '${handler}()' has no authorization check — auth bypass / privilege escalation.` });
|
|
56394
56404
|
}
|
|
56395
56405
|
if (!hasNonce) {
|
|
56396
|
-
out.push({
|
|
56397
|
-
file,
|
|
56398
|
-
line,
|
|
56399
|
-
type: "missing_nonce",
|
|
56400
|
-
category: "Missing nonce verification",
|
|
56401
|
-
severity: "medium",
|
|
56402
|
-
evidence: `add_action('${hook}', '${handler}')`,
|
|
56403
|
-
detail: `admin-post handler '${handler}()' does not verify a nonce — CSRF.`
|
|
56404
|
-
});
|
|
56406
|
+
out.push({ file, line, type: "missing_nonce", category: "Missing nonce verification", severity: "medium", evidence: `add_action('${hook}', '${handler}')`, detail: `admin-post handler '${handler}()' does not verify a nonce — CSRF.` });
|
|
56405
56407
|
}
|
|
56406
56408
|
}
|
|
56407
56409
|
const restRe = /register_rest_route\s*\(\s*['"]([^'"]+)['"]\s*,\s*['"]([^'"]+)['"]/g;
|
|
@@ -56410,16 +56412,47 @@ function detectMissingAuthz(code, file) {
|
|
|
56410
56412
|
const window2 = code.slice(m.index, m.index + 800);
|
|
56411
56413
|
if (/permission_callback/.test(window2))
|
|
56412
56414
|
continue;
|
|
56413
|
-
out.push({
|
|
56414
|
-
|
|
56415
|
-
|
|
56416
|
-
|
|
56417
|
-
|
|
56418
|
-
|
|
56419
|
-
|
|
56420
|
-
|
|
56421
|
-
|
|
56415
|
+
out.push({ file, line, type: "missing_authz", category: "REST route missing permission_callback", severity: "high", evidence: `register_rest_route('${m[1]}', '${m[2]}')`, detail: `REST route '${m[1]}${m[2]}' has no permission_callback — the endpoint defaults to public (auth bypass).` });
|
|
56416
|
+
}
|
|
56417
|
+
}
|
|
56418
|
+
var ROUTE_DETECTORS = [
|
|
56419
|
+
{ framework: "laravel", entry: /Route::(?:get|post|put|patch|delete|any|match|resource)\s*\(\s*['"][^'"]+['"]/g, auth: /->middleware\s*\(\s*['"]auth|middleware\s*\(\s*\[[^\]]*['"]auth|->can\s*\(|\$this->authorize|Gate::|authorize\s*\(|@can\b/, window: 2 },
|
|
56420
|
+
{ framework: "django", entry: /@api_view\s*\(|def\s+\w+\s*\(\s*request\s*[,)]/g, auth: /login_required|permission_required|user_passes_test|LoginRequiredMixin|PermissionRequiredMixin|permission_classes|IsAuthenticated|has_permission/, window: 3 },
|
|
56421
|
+
{ framework: "flask", entry: /@(?:app|bp|blueprint)\.route\s*\(/g, auth: /login_required|current_user\.is_authenticated|permission_required/, window: 3 },
|
|
56422
|
+
{ framework: "express", entry: /(?:app|router)\.(?:get|post|put|delete|patch|use)\s*\(\s*['"][^'"]+['"]/g, auth: /requireAuth|authenticate|passport\.authenticate|req\.user|isAuthenticated|ensureAuthenticated|requireLogin|\.authorize|authMiddleware/, window: 2 },
|
|
56423
|
+
{ framework: "spring", entry: /@(?:Get|Post|Put|Delete|Patch|Request)Mapping\s*\(/g, auth: /@PreAuthorize|@Secured|@RolesAllowed|hasRole|hasAuthority|isAuthenticated|SecurityContextHolder/, window: 2 },
|
|
56424
|
+
{ framework: "symfony", entry: /#\[(?:Route|Get|Post|Put|Delete|Patch)\b|@Route\s*\(/g, auth: /is_granted|denyAccessUnlessGranted|->isGranted\s*\(|IsGranted|Voter/, window: 2 },
|
|
56425
|
+
{ framework: "aspnet", entry: /\[Http(?:Get|Post|Put|Delete|Patch)\b/g, auth: /\[Authorize|User\.Identity|IsInRole|AuthorizeAsync|\[AllowAnonymous|IAuthorizationService/, window: 2 },
|
|
56426
|
+
{ framework: "rails", entry: /class\s+\w+\s*<\s*ApplicationController/g, auth: /before_action\s+:authenticate|before_action\s+:authorize|authenticate_user!|authorize\s+|current_user|authenticate/, window: 6 }
|
|
56427
|
+
];
|
|
56428
|
+
function detectRouteAuthz(code, file, out) {
|
|
56429
|
+
const ls = code.split(`
|
|
56430
|
+
`);
|
|
56431
|
+
for (const d of ROUTE_DETECTORS) {
|
|
56432
|
+
d.entry.lastIndex = 0;
|
|
56433
|
+
let m;
|
|
56434
|
+
while ((m = d.entry.exec(code)) !== null) {
|
|
56435
|
+
const ln = lineNoOf(code, m.index);
|
|
56436
|
+
const window2 = ls.slice(Math.max(0, ln - d.window), Math.min(ls.length, ln + d.window + 1)).join(`
|
|
56437
|
+
`);
|
|
56438
|
+
if (d.auth.test(window2))
|
|
56439
|
+
continue;
|
|
56440
|
+
out.push({
|
|
56441
|
+
file,
|
|
56442
|
+
line: ln,
|
|
56443
|
+
type: "missing_authz",
|
|
56444
|
+
category: `${d.framework}: endpoint without authorization`,
|
|
56445
|
+
severity: "high",
|
|
56446
|
+
evidence: (ls[ln - 1] ?? "").trim(),
|
|
56447
|
+
detail: `${d.framework} endpoint has no authorization enforcement in the surrounding ${d.window}-line window — auth bypass / privilege escalation.`
|
|
56448
|
+
});
|
|
56449
|
+
}
|
|
56422
56450
|
}
|
|
56451
|
+
}
|
|
56452
|
+
function detectMissingAuthz(code, file) {
|
|
56453
|
+
const out = [];
|
|
56454
|
+
detectWpAuthz(code, file, out);
|
|
56455
|
+
detectRouteAuthz(code, file, out);
|
|
56423
56456
|
const seen = new Set;
|
|
56424
56457
|
return out.filter((f) => {
|
|
56425
56458
|
const key = `${f.type}:${f.line}`;
|
|
@@ -56903,6 +56936,8 @@ function runBenchmark() {
|
|
|
56903
56936
|
const detectionRate = tp + fn > 0 ? tp / (tp + fn) : 0;
|
|
56904
56937
|
const falsePositiveRate = fp + tn > 0 ? fp / (fp + tn) : 0;
|
|
56905
56938
|
const precision = tp + fp > 0 ? tp / (tp + fp) : 0;
|
|
56939
|
+
const recall = detectionRate;
|
|
56940
|
+
const f1 = precision + recall > 0 ? 2 * precision * recall / (precision + recall) : 0;
|
|
56906
56941
|
const byDetector = {};
|
|
56907
56942
|
for (const r of results) {
|
|
56908
56943
|
const d = r.entry.detector ?? "taint";
|
|
@@ -56927,6 +56962,8 @@ function runBenchmark() {
|
|
|
56927
56962
|
detection_rate: Number(detectionRate.toFixed(3)),
|
|
56928
56963
|
false_positive_rate: Number(falsePositiveRate.toFixed(3)),
|
|
56929
56964
|
precision: Number(precision.toFixed(3)),
|
|
56965
|
+
recall: Number(recall.toFixed(3)),
|
|
56966
|
+
f1: Number(f1.toFixed(3)),
|
|
56930
56967
|
by_detector: detectorMetrics,
|
|
56931
56968
|
captured_false_positives: {
|
|
56932
56969
|
total: captured.length,
|
|
@@ -58076,14 +58113,17 @@ ${statusLine}` : statusLine },
|
|
|
58076
58113
|
return { content: [{ type: "text", text: JSON.stringify(analyzeSecurityState({ sanitizers: arr, sinkType: sink_type })) }] };
|
|
58077
58114
|
});
|
|
58078
58115
|
server.registerTool("framework_knowledge", {
|
|
58079
|
-
title: "Framework security knowledge graph",
|
|
58080
|
-
description: "FRAMEWORK-KNOWLEDGE: return a framework's security primitives as data — authorization primitives
|
|
58116
|
+
title: "Framework security knowledge graph (multi-framework)",
|
|
58117
|
+
description: "FRAMEWORK-KNOWLEDGE: return a framework's security primitives as data — authorization primitives, nonce/CSRF primitives, entry-point hooks, and sanitizers. Supports wordpress, laravel, django, flask, express, spring, symfony, aspnet, rails. Powers the multi-framework missing-authz/nonce detector.",
|
|
58081
58118
|
inputSchema: {
|
|
58082
|
-
framework: string2().optional().describe("Framework id (
|
|
58119
|
+
framework: string2().optional().describe("Framework id (wordpress, laravel, django, flask, express, spring, symfony, aspnet, rails)")
|
|
58083
58120
|
}
|
|
58084
58121
|
}, async ({ framework }) => {
|
|
58085
58122
|
const k = frameworkKnowledge(framework ?? "wordpress");
|
|
58086
|
-
|
|
58123
|
+
if (!k) {
|
|
58124
|
+
return { content: [{ type: "text", text: JSON.stringify({ error: "framework not in the knowledge graph", framework, available: listFrameworks2() }) }] };
|
|
58125
|
+
}
|
|
58126
|
+
return { content: [{ type: "text", text: JSON.stringify(k) }] };
|
|
58087
58127
|
});
|
|
58088
58128
|
server.registerTool("variant_scan", {
|
|
58089
58129
|
title: "Mass variant-mining scan of an install base",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "blitzstrike",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.37",
|
|
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": {
|