blitzstrike 2.4.77 → 2.4.79
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 +32 -0
- package/dist/index.js +15 -7
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,38 @@ 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.79] — 2026-09-17
|
|
9
|
+
|
|
10
|
+
### Changed — precision pass (FP reduction, benchmark-driven)
|
|
11
|
+
|
|
12
|
+
- Removed the bare `exec(` sink (sqlite `db.exec(...)` / `stmt.exec(...)` was
|
|
13
|
+
flagged as command execution in Node apps). Command injection is still covered
|
|
14
|
+
by `child_process.exec/spawn`, `system`, `shell_exec`, `subprocess.*`,
|
|
15
|
+
`os.system`, `popen`.
|
|
16
|
+
- `detectRouteAuthz`: added `requireAdmin`/`requireRole`/`requirePermission`/
|
|
17
|
+
`isAdmin`/`checkRole`/`bearer`/`apiAuth`/`getApiKeyFromRequest`/`verifyApiKey`
|
|
18
|
+
to the express auth model + widened the window to ±3, and added a public-path
|
|
19
|
+
SEGMENT matcher for multi-segment public routes (`/api/system/version`,
|
|
20
|
+
`/.well-known/jwks.json`, `/v1/metrics`).
|
|
21
|
+
- `detectHardcodedSecret`: skip values that are function calls
|
|
22
|
+
(`getApiKeyFromRequest(req)`, `fs.readFileSync(...)`, `make_token(...)`) or DOM
|
|
23
|
+
reads (`document.getElementById(...).value`) — those are computed at runtime.
|
|
24
|
+
|
|
25
|
+
FP labs on the 30-lab benchmark dropped 16 → 8 (TP 12 unchanged).
|
|
26
|
+
|
|
27
|
+
## [2.4.78] — 2026-09-17
|
|
28
|
+
|
|
29
|
+
### Fixed — taint-engine sanitizer name collision (whole-class FN)
|
|
30
|
+
|
|
31
|
+
- The Python taint adapter neutralized every identifier inside a sanitizer call
|
|
32
|
+
(e.g. `int(os.environ.get("PORT", "5000"))` neutralized the method name `get`
|
|
33
|
+
for sql_execution/command_execution). Because taint state is keyed by name, that
|
|
34
|
+
polluted the `get` in `request.args.get(...)` elsewhere and wrongly suppressed
|
|
35
|
+
real findings (labs20 f-string SQLi went undetected). Sanitizers now only
|
|
36
|
+
neutralize VALUE arguments, skipping dotted-chain receiver/method names and
|
|
37
|
+
string literals. Python f-string SQLi (`request.args.get -> f"{var}" -> execute`)
|
|
38
|
+
is now caught.
|
|
39
|
+
|
|
8
40
|
## [2.4.77] — 2026-09-17
|
|
9
41
|
|
|
10
42
|
### Changed — SQLi Node/Python coverage + missing_authz root-path precision
|
package/dist/index.js
CHANGED
|
@@ -7190,7 +7190,6 @@ var init_scanner = __esm(() => {
|
|
|
7190
7190
|
"eval(": "RCE (code execution)",
|
|
7191
7191
|
"assert(": "RCE (code execution, PHP <8)",
|
|
7192
7192
|
"system(": "RCE (command execution)",
|
|
7193
|
-
"exec(": "RCE (command execution)",
|
|
7194
7193
|
"shell_exec(": "RCE (command execution)",
|
|
7195
7194
|
"passthru(": "RCE (command execution)",
|
|
7196
7195
|
"proc_open(": "RCE (command execution)",
|
|
@@ -15981,7 +15980,7 @@ function detectRouteAuthz(code, file, out) {
|
|
|
15981
15980
|
const ln = lineNoOf(code, m.index);
|
|
15982
15981
|
const window2 = ls.slice(Math.max(0, ln - d.window), Math.min(ls.length, ln + d.window + 1)).join(`
|
|
15983
15982
|
`);
|
|
15984
|
-
if (PUBLIC_ROUTE_RE.test(m[0] + " " + window2))
|
|
15983
|
+
if (PUBLIC_ROUTE_RE.test(m[0] + " " + window2) || PUBLIC_SEGMENT_RE.test(m[0] + " " + window2))
|
|
15985
15984
|
continue;
|
|
15986
15985
|
if (d.auth.test(window2))
|
|
15987
15986
|
continue;
|
|
@@ -16010,7 +16009,7 @@ function detectMissingAuthz(code, file) {
|
|
|
16010
16009
|
return true;
|
|
16011
16010
|
});
|
|
16012
16011
|
}
|
|
16013
|
-
var FRAMEWORKS, INDIRECT_AUTH, AUTH_RE, NONCE_RE, DANGEROUS_OP_RE, ROUTE_DETECTORS, PUBLIC_ROUTE_RE;
|
|
16012
|
+
var FRAMEWORKS, INDIRECT_AUTH, AUTH_RE, NONCE_RE, DANGEROUS_OP_RE, ROUTE_DETECTORS, PUBLIC_ROUTE_RE, PUBLIC_SEGMENT_RE;
|
|
16014
16013
|
var init_framework_security = __esm(() => {
|
|
16015
16014
|
FRAMEWORKS = {
|
|
16016
16015
|
wordpress: {
|
|
@@ -16092,13 +16091,14 @@ var init_framework_security = __esm(() => {
|
|
|
16092
16091
|
{ 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 },
|
|
16093
16092
|
{ 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 },
|
|
16094
16093
|
{ framework: "flask", entry: /@(?:app|bp|blueprint)\.(?:route|get|post|put|delete|patch|before_request)\s*\(/g, auth: /login_required|require_auth|auth_required|jwt_required|token_required|current_user|is_authenticated|before_request|verify_token|permission_required/, window: 3 },
|
|
16095
|
-
{ framework: "express", entry: /(?<!@)(?:app|router)\.(?:get|post|put|delete|patch|use)\s*\(\s*['"][^'"]+['"]/g, auth: /requireAuth|require_auth|authenticate|passport\.authenticate|req\.user|isAuthenticated|ensureAuthenticated|requireLogin|\.authorize|authMiddleware|verifyToken|verify_token|jwt\.verify/, window:
|
|
16094
|
+
{ framework: "express", entry: /(?<!@)(?:app|router)\.(?:get|post|put|delete|patch|use)\s*\(\s*['"][^'"]+['"]/g, auth: /requireAuth|require_auth|requireAdmin|requireRole|requirePermission|isAdmin|checkRole|getApiKeyFromRequest|verifyApiKey|checkApiKey|verifyInternalToken|authenticate|passport\.authenticate|req\.user|isAuthenticated|ensureAuthenticated|requireLogin|\.authorize|authMiddleware|verifyToken|verify_token|jwt\.verify|\bbearer\b|apiAuth/, window: 3 },
|
|
16096
16095
|
{ framework: "spring", entry: /@(?:Get|Post|Put|Delete|Patch|Request)Mapping\s*\(/g, auth: /@PreAuthorize|@Secured|@RolesAllowed|hasRole|hasAuthority|isAuthenticated|SecurityContextHolder/, window: 2 },
|
|
16097
16096
|
{ framework: "symfony", entry: /#\[(?:Route|Get|Post|Put|Delete|Patch)\b|@Route\s*\(/g, auth: /is_granted|denyAccessUnlessGranted|->isGranted\s*\(|IsGranted|Voter/, window: 2 },
|
|
16098
16097
|
{ framework: "aspnet", entry: /\[Http(?:Get|Post|Put|Delete|Patch)\b/g, auth: /\[Authorize|User\.Identity|IsInRole|AuthorizeAsync|\[AllowAnonymous|IAuthorizationService/, window: 2 },
|
|
16099
16098
|
{ 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 }
|
|
16100
16099
|
];
|
|
16101
|
-
PUBLIC_ROUTE_RE = /['"`]\/?(?:(?:api|v1|v2|o|auth|adminapi)\/)?(?:register|login|logout|signup|signin|forgot-password|reset-password|health|healthz|ready|status|version|ping|static|public|assets|css|js|img|favicon|echo|config|docs|openapi|swagger|robots|sitemap|graphql|graphiql|query|upload|callback|webhook|home|index|root)[/'"?]|['"`]\/?['"`](?!["'`])/i;
|
|
16100
|
+
PUBLIC_ROUTE_RE = /['"`]\/?(?:(?:api|v1|v2|o|auth|adminapi|system|internal)\/)?(?:register|login|logout|signup|signin|forgot-password|reset-password|health|healthz|ready|status|version|ping|static|public|assets|css|js|img|favicon|echo|config|docs|openapi|swagger|robots|sitemap|graphql|graphiql|query|upload|callback|webhook|home|index|root|jwks|well-known|openid-configuration|traces|logs|metrics)[/'"?]|['"`]\/?['"`](?!["'`])/i;
|
|
16101
|
+
PUBLIC_SEGMENT_RE = /['"`][^'"`]*\/(?:version|health|healthz|ready|status|ping|jwks|openid-configuration|well-known|metrics|traces|logs|favicon|robots|sitemap)(?:[.\/'"?]|$)/i;
|
|
16102
16102
|
});
|
|
16103
16103
|
|
|
16104
16104
|
// src/complex-bugs.ts
|
|
@@ -16596,6 +16596,10 @@ function detectHardcodedSecret(code, file, out) {
|
|
|
16596
16596
|
continue;
|
|
16597
16597
|
if (qm && /^["'][^"']+["']\s*\+/.test(valueRaw))
|
|
16598
16598
|
continue;
|
|
16599
|
+
if (!qm && new RegExp(`${value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\s*\\(`).test(valueRaw))
|
|
16600
|
+
continue;
|
|
16601
|
+
if (!qm && /document\.|window\.|localStorage\.|sessionStorage\./.test(valueRaw))
|
|
16602
|
+
continue;
|
|
16599
16603
|
const ln = lineNo2(code, m.index);
|
|
16600
16604
|
flaggedLines.add(ln);
|
|
16601
16605
|
let sev = "high";
|
|
@@ -56908,9 +56912,13 @@ var pythonAdapter = {
|
|
|
56908
56912
|
sinks.push({ variable: v, kind, line: lineOf(n), cwe });
|
|
56909
56913
|
}
|
|
56910
56914
|
for (const [re, kinds] of PY_SANITIZERS) {
|
|
56911
|
-
if (re.test(full))
|
|
56912
|
-
for (const v of argVars)
|
|
56915
|
+
if (re.test(full)) {
|
|
56916
|
+
for (const v of argVars) {
|
|
56917
|
+
if (new RegExp(`\\b${v}\\s*[.(]`).test(full))
|
|
56918
|
+
continue;
|
|
56913
56919
|
sanitizers.push({ variable: v, neutralizes: kinds, line: lineOf(n) });
|
|
56920
|
+
}
|
|
56921
|
+
}
|
|
56914
56922
|
}
|
|
56915
56923
|
calls.push({ name: callee, args: argVars, line: lineOf(n) });
|
|
56916
56924
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "blitzstrike",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.79",
|
|
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": {
|