blitzstrike 2.4.62 → 2.4.64
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 +323 -148
- package/intelligence/variants.json +352 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7409,18 +7409,53 @@ function redactSecrets(text) {
|
|
|
7409
7409
|
var SECRET_FIELDS = "api[_-]?key|apikey|api[_-]?secret|access[_-]?key|access[_-]?token|secret[_-]?key|secret[_-]?access[_-]?key|auth[_-]?token|client[_-]?secret|consumer[_-]?secret|consumer[_-]?key|private[_-]?key|db[_-]?password|database[_-]?password|db[_-]?pass|passwd|password|jwt[_-]?secret|encryption[_-]?key|encryption[_-]?password|github[_-]?token|gitlab[_-]?token|stripe[_-]?key|sendgrid[_-]?api[_-]?key|datadog[_-]?api[_-]?key|cloudflare[_-]?api[_-]?key|slack[_-]?token|aws[_-]?access[_-]?key[_-]?id|aws[_-]?secret[_-]?access[_-]?key|aws[_-]?session[_-]?token|bot[_-]?token", SECRET_FORMATS, REDACTION_PATTERNS;
|
|
7410
7410
|
var init_secrets = __esm(() => {
|
|
7411
7411
|
SECRET_FORMATS = [
|
|
7412
|
-
{ name: "
|
|
7413
|
-
{ name: "AWS
|
|
7414
|
-
{ name: "
|
|
7415
|
-
{ name: "
|
|
7416
|
-
{ name: "
|
|
7417
|
-
{ name: "
|
|
7418
|
-
{ name: "
|
|
7419
|
-
{ name: "
|
|
7420
|
-
{ name: "
|
|
7421
|
-
{ name: "
|
|
7422
|
-
{ name: "
|
|
7423
|
-
{ name: "
|
|
7412
|
+
{ name: "AWS access key ID", re: /\bAKIA[0-9A-Z]{16}\b/g, severity: "critical", category: "aws" },
|
|
7413
|
+
{ name: "AWS session token (temporary)", re: /\bASIA[0-9A-Z]{16}\b/g, severity: "critical", category: "aws" },
|
|
7414
|
+
{ name: "AWS secret access key", re: /aws[_-]?secret[_-]?access[_-]?key['"\s:=]+([A-Za-z0-9/+=]{40})/gi, severity: "critical", category: "aws" },
|
|
7415
|
+
{ name: "GCP service account key", re: /"type"\s*:\s*"service_account"/g, severity: "critical", category: "gcp" },
|
|
7416
|
+
{ name: "Google API key", re: /\bAIza[0-9A-Za-z_-]{35}\b/g, severity: "high", category: "gcp" },
|
|
7417
|
+
{ name: "GitHub PAT (classic)", re: /\bghp_[A-Za-z0-9]{20,}\b/g, severity: "critical", category: "github" },
|
|
7418
|
+
{ name: "GitHub PAT (fine-grained)", re: /\bgithub_pat_[A-Za-z0-9_]{20,}\b/g, severity: "critical", category: "github" },
|
|
7419
|
+
{ name: "GitHub OAuth token", re: /\bgho_[A-Za-z0-9]{20,}\b/g, severity: "high", category: "github" },
|
|
7420
|
+
{ name: "GitHub server-to-server token", re: /\bgh[usr]_[A-Za-z0-9]{20,}\b/g, severity: "high", category: "github" },
|
|
7421
|
+
{ name: "Stripe live key", re: /\bsk_live_[0-9A-Za-z]{16,}\b/g, severity: "critical", category: "stripe" },
|
|
7422
|
+
{ name: "Stripe test key", re: /\bsk_test_[0-9A-Za-z]{16,}\b/g, severity: "low", category: "stripe" },
|
|
7423
|
+
{ name: "Stripe publishable key", re: /\bpk_(?:live|test)_[0-9A-Za-z]{16,}\b/g, severity: "low", category: "stripe" },
|
|
7424
|
+
{ name: "Slack token", re: /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g, severity: "high", category: "slack" },
|
|
7425
|
+
{ name: "Slack webhook URL", re: /https:\/\/hooks\.slack\.com\/services\/T[A-Z0-9]+\/B[A-Z0-9]+\/[A-Za-z0-9]+/g, severity: "medium", category: "slack" },
|
|
7426
|
+
{ name: "SendGrid API key", re: /\bSG\.[A-Za-z0-9_-]{16,}\.[A-Za-z0-9_-]{16,}\b/g, severity: "high", category: "email_svc" },
|
|
7427
|
+
{ name: "Mailgun API key", re: /\bkey-[0-9a-zA-Z]{32}\b/g, severity: "high", category: "email_svc" },
|
|
7428
|
+
{ name: "Twilio API key", re: /\bSK[0-9a-fA-F]{32}\b/g, severity: "high", category: "twilio" },
|
|
7429
|
+
{ name: "Twilio account SID", re: /\bAC[0-9a-f]{32}\b/g, severity: "medium", category: "twilio" },
|
|
7430
|
+
{ name: "Twilio auth token", re: /twilio(.{0,20})?(auth|token)['"=: ]+([a-f0-9]{32})/gi, severity: "high", category: "twilio" },
|
|
7431
|
+
{ name: "Heroku API key", re: /heroku(.{0,20})?api['"=: ]+([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/gi, severity: "medium", category: "paas" },
|
|
7432
|
+
{ name: "Firebase URL", re: /\bhttps?:\/\/[a-z0-9-]+\.firebaseio\.com\b/g, severity: "low", category: "firebase" },
|
|
7433
|
+
{ name: "JWT", re: /\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{4,}/g, severity: "medium", category: "jwt" },
|
|
7434
|
+
{ name: "Bearer token", re: /authorization['"=: ]+bearer\s+[A-Za-z0-9._-]{20,}/gi, severity: "medium", category: "bearer" },
|
|
7435
|
+
{ name: "Basic auth URL", re: /https?:\/\/[^/\s:@]+:[^/\s:@]+@[^/\s]+/g, severity: "medium", category: "basic_auth" },
|
|
7436
|
+
{ name: "RSA private key", re: /-----BEGIN RSA PRIVATE KEY-----/g, severity: "critical", category: "private_key" },
|
|
7437
|
+
{ name: "EC private key", re: /-----BEGIN EC PRIVATE KEY-----/g, severity: "critical", category: "private_key" },
|
|
7438
|
+
{ name: "OpenSSH private key", re: /-----BEGIN OPENSSH PRIVATE KEY-----/g, severity: "critical", category: "private_key" },
|
|
7439
|
+
{ name: "Generic private key", re: /-----BEGIN (DSA |PGP |)PRIVATE KEY-----/g, severity: "critical", category: "private_key" },
|
|
7440
|
+
{ name: "Generic API key / token", re: /(?:api[_-]?key|apikey|api_secret|access_token|secret[_-]?token)['"\s:=]+["']([A-Za-z0-9+/=_-]{24,})["']/gi, severity: "medium", category: "generic" },
|
|
7441
|
+
{ name: "Anthropic API key", re: /\bsk-ant-(?:api03|admin01)-[A-Za-z0-9_-]{20,}\b/g, severity: "critical", category: "ai_api" },
|
|
7442
|
+
{ name: "OpenAI API key (legacy)", re: /\bsk-[A-Za-z0-9]{20}T3BlbkFJ[A-Za-z0-9]{20}\b/g, severity: "critical", category: "ai_api" },
|
|
7443
|
+
{ name: "OpenAI project key", re: /\bsk-proj-[A-Za-z0-9_-]{20,}T3BlbkFJ[A-Za-z0-9_-]{20,}\b/g, severity: "critical", category: "ai_api" },
|
|
7444
|
+
{ name: "OpenAI session token", re: /\bsess-[A-Za-z0-9]{40}\b/g, severity: "high", category: "ai_api" },
|
|
7445
|
+
{ name: "Hugging Face token", re: /\bhf_[A-Za-z0-9]{30,}\b/g, severity: "high", category: "ai_api" },
|
|
7446
|
+
{ name: "Cloudflare API key", re: /cf[_-]?api[_-]?key['"\s:=]+([a-f0-9]{37})/gi, severity: "critical", category: "infra_api" },
|
|
7447
|
+
{ name: "DigitalOcean token", re: /\bdop_v1_[a-f0-9]{64}\b/g, severity: "high", category: "infra_api" },
|
|
7448
|
+
{ name: "npm token", re: /\bnpm_[A-Za-z0-9]{36}\b/g, severity: "high", category: "package_registry" },
|
|
7449
|
+
{ name: "PyPI token", re: /\bpypi-AgENdGV[A-Za-z0-9_-]+\b/g, severity: "high", category: "package_registry" },
|
|
7450
|
+
{ name: "Docker Hub PAT", re: /\bdckr_pat_[A-Za-z0-9_-]{27,}\b/g, severity: "high", category: "package_registry" },
|
|
7451
|
+
{ name: "Atlassian API token", re: /\bATATT3xFfGF0[A-Za-z0-9_-]{20,}\b/g, severity: "high", category: "saas_api" },
|
|
7452
|
+
{ name: "Linear API key", re: /\blin_api_[A-Za-z0-9]{40}\b/g, severity: "medium", category: "saas_api" },
|
|
7453
|
+
{ name: "New Relic license key", re: /\b(?:NRAA|NRAK|NRBR)-[A-F0-9]{27}\b/g, severity: "medium", category: "observability" },
|
|
7454
|
+
{ name: "Datadog API key", re: /dd[_-]?api[_-]?key['"\s:=]+([a-f0-9]{32})/gi, severity: "high", category: "observability" },
|
|
7455
|
+
{ name: "Sentry DSN", re: /https:\/\/[a-f0-9]+@o[0-9]+\.ingest\.sentry\.io\/[0-9]+/g, severity: "low", category: "observability" },
|
|
7456
|
+
{ name: "ngrok auth token", re: /\b[12][A-Za-z0-9]{26}_[A-Za-z0-9]{32,}\b/g, severity: "medium", category: "tunneling" },
|
|
7457
|
+
{ name: "Discord bot token", re: /\b[MN][A-Za-z\d]{23}\.[\w-]{6}\.[\w-]{27}\b/g, severity: "high", category: "bot_token" },
|
|
7458
|
+
{ name: "Telegram bot token", re: /\b\d{8,10}:[A-Za-z0-9_-]{35}\b/g, severity: "high", category: "bot_token" }
|
|
7424
7459
|
];
|
|
7425
7460
|
REDACTION_PATTERNS = [
|
|
7426
7461
|
[/(authorization\s*[:=]\s*)(bearer\s+)?[A-Za-z0-9._~+/=-]{8,}/gi, "$1$2[REDACTED]"],
|
|
@@ -7433,17 +7468,34 @@ var init_secrets = __esm(() => {
|
|
|
7433
7468
|
[/(session\s*[:=]\s*)["']?[A-Za-z0-9._-]{12,}["']?/gi, "$1[REDACTED]"],
|
|
7434
7469
|
[/(cookie\s*[:=]\s*)["']?[A-Za-z0-9._-]{12,}["']?/gi, "$1[REDACTED]"],
|
|
7435
7470
|
[/(set-cookie\s*:\s*)[^\r\n]+/gi, "$1[REDACTED]"],
|
|
7436
|
-
[/\
|
|
7437
|
-
[
|
|
7438
|
-
[
|
|
7439
|
-
[
|
|
7440
|
-
[
|
|
7441
|
-
[/\
|
|
7471
|
+
[/\bAKIA[0-9A-Z]{16}\b/g, "[REDACTED]"],
|
|
7472
|
+
[/\bASIA[0-9A-Z]{16}\b/g, "[REDACTED]"],
|
|
7473
|
+
[/\bghp_[A-Za-z0-9]{20,}\b/g, "[REDACTED]"],
|
|
7474
|
+
[/\bgithub_pat_[A-Za-z0-9_]{20,}\b/g, "[REDACTED]"],
|
|
7475
|
+
[/\bgho_[A-Za-z0-9]{20,}\b/g, "[REDACTED]"],
|
|
7476
|
+
[/\bgh[usr]_[A-Za-z0-9]{20,}\b/g, "[REDACTED]"],
|
|
7477
|
+
[/\bsk_live_[0-9A-Za-z]{16,}\b/g, "[REDACTED]"],
|
|
7478
|
+
[/\bsk_test_[0-9A-Za-z]{16,}\b/g, "[REDACTED]"],
|
|
7479
|
+
[/\bpk_(?:live|test)_[0-9A-Za-z]{16,}\b/g, "[REDACTED]"],
|
|
7442
7480
|
[/\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g, "[REDACTED]"],
|
|
7443
7481
|
[/\bAIza[0-9A-Za-z_-]{35}\b/g, "[REDACTED]"],
|
|
7444
7482
|
[/\bAC[0-9a-f]{32}\b/g, "[REDACTED]"],
|
|
7483
|
+
[/\bSK[0-9a-fA-F]{32}\b/g, "[REDACTED]"],
|
|
7445
7484
|
[/\bSG\.[A-Za-z0-9_-]{16,}\.[A-Za-z0-9_-]{16,}\b/g, "[REDACTED]"],
|
|
7446
7485
|
[/\bkey-[0-9a-zA-Z]{32}\b/g, "[REDACTED]"],
|
|
7486
|
+
[/\bsk-ant-(?:api03|admin01)-[A-Za-z0-9_-]{20,}\b/g, "[REDACTED]"],
|
|
7487
|
+
[/\bsk-proj-[A-Za-z0-9_-]{20,}T3BlbkFJ[A-Za-z0-9_-]{20,}\b/g, "[REDACTED]"],
|
|
7488
|
+
[/\bsess-[A-Za-z0-9]{40}\b/g, "[REDACTED]"],
|
|
7489
|
+
[/\bhf_[A-Za-z0-9]{30,}\b/g, "[REDACTED]"],
|
|
7490
|
+
[/\bdop_v1_[a-f0-9]{64}\b/g, "[REDACTED]"],
|
|
7491
|
+
[/\bnpm_[A-Za-z0-9]{36}\b/g, "[REDACTED]"],
|
|
7492
|
+
[/\bpypi-AgENdGV[A-Za-z0-9_-]+\b/g, "[REDACTED]"],
|
|
7493
|
+
[/\bdckr_pat_[A-Za-z0-9_-]{27,}\b/g, "[REDACTED]"],
|
|
7494
|
+
[/\bATATT3xFfGF0[A-Za-z0-9_-]{20,}\b/g, "[REDACTED]"],
|
|
7495
|
+
[/\blin_api_[A-Za-z0-9]{40}\b/g, "[REDACTED]"],
|
|
7496
|
+
[/\b(?:NRAA|NRAK|NRBR)-[A-F0-9]{27}\b/g, "[REDACTED]"],
|
|
7497
|
+
[/\b\d{8,10}:[A-Za-z0-9_-]{35}\b/g, "[REDACTED]"],
|
|
7498
|
+
[/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{4,}/g, "[REDACTED]"],
|
|
7447
7499
|
[/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g, "[REDACTED]"]
|
|
7448
7500
|
];
|
|
7449
7501
|
});
|
|
@@ -16054,13 +16106,32 @@ function stripCommentsOnly(code) {
|
|
|
16054
16106
|
return out.join("");
|
|
16055
16107
|
}
|
|
16056
16108
|
function detectDeserialization(code, file, out) {
|
|
16057
|
-
if (!MAGIC_METHODS.test(code))
|
|
16058
|
-
return;
|
|
16059
16109
|
const ls = lines2(code);
|
|
16060
|
-
|
|
16061
|
-
|
|
16062
|
-
|
|
16063
|
-
|
|
16110
|
+
if (MAGIC_METHODS.test(code)) {
|
|
16111
|
+
const re = /\b(unserialize|maybe_unserialize)\s*\(/g;
|
|
16112
|
+
let m;
|
|
16113
|
+
while ((m = re.exec(code)) !== null) {
|
|
16114
|
+
const ln = lineNo2(code, m.index);
|
|
16115
|
+
const l = ls[ln - 1] ?? "";
|
|
16116
|
+
const scope = ls.slice(Math.max(0, ln - 4), ln).join(`
|
|
16117
|
+
`);
|
|
16118
|
+
if (!SOURCE_TOKENS3.test(l) && !SOURCE_TOKENS3.test(scope))
|
|
16119
|
+
continue;
|
|
16120
|
+
out.push({
|
|
16121
|
+
file,
|
|
16122
|
+
line: ln,
|
|
16123
|
+
type: "deserialization",
|
|
16124
|
+
category: "Deserialization → POP gadget chain",
|
|
16125
|
+
severity: "high",
|
|
16126
|
+
evidence: l.trim(),
|
|
16127
|
+
detail: `\`${m[1]}()\` of attacker-controlled data AND a magic method is present — object injection can pivot to RCE via the gadget chain.`
|
|
16128
|
+
});
|
|
16129
|
+
}
|
|
16130
|
+
}
|
|
16131
|
+
const unsafeRe = /\b(pickle\.loads?|yaml\.load|yaml\.unsafe_load|ObjectInputStream|\.readObject)\s*\(/g;
|
|
16132
|
+
let u;
|
|
16133
|
+
while ((u = unsafeRe.exec(code)) !== null) {
|
|
16134
|
+
const ln = lineNo2(code, u.index);
|
|
16064
16135
|
const l = ls[ln - 1] ?? "";
|
|
16065
16136
|
const scope = ls.slice(Math.max(0, ln - 4), ln).join(`
|
|
16066
16137
|
`);
|
|
@@ -16070,10 +16141,10 @@ function detectDeserialization(code, file, out) {
|
|
|
16070
16141
|
file,
|
|
16071
16142
|
line: ln,
|
|
16072
16143
|
type: "deserialization",
|
|
16073
|
-
category: "
|
|
16144
|
+
category: "Unsafe deserialization",
|
|
16074
16145
|
severity: "high",
|
|
16075
16146
|
evidence: l.trim(),
|
|
16076
|
-
detail: `\`${
|
|
16147
|
+
detail: `\`${u[1]}\` of attacker-controlled data — unsafe deserialization can execute arbitrary code directly (pickle/yaml/Java object streams).`
|
|
16077
16148
|
});
|
|
16078
16149
|
}
|
|
16079
16150
|
}
|
|
@@ -16087,7 +16158,7 @@ function detectTypeJuggling(code, file, out) {
|
|
|
16087
16158
|
const scope = ls.slice(Math.max(0, ln - 4), ln).join(`
|
|
16088
16159
|
`);
|
|
16089
16160
|
const hasSource = SOURCE_TOKENS3.test(l) || SOURCE_TOKENS3.test(scope);
|
|
16090
|
-
const hasHash = /\b(md5|sha1|sha256|hash|crc32|crypt|password_verify|strcmp|hash_equals|secret|token|nonce)\s*\(?/i.test(l) ||
|
|
16161
|
+
const hasHash = /\b(md5|sha1|sha256|hash|crc32|crypt|password_verify|strcmp|hash_equals|secret|token|nonce)\s*\(?/i.test(l) || /(secret|token|nonce|hash)\b/i.test(l);
|
|
16091
16162
|
if (!hasSource || !hasHash)
|
|
16092
16163
|
continue;
|
|
16093
16164
|
out.push({
|
|
@@ -16138,6 +16209,34 @@ function detectMassAssignment(code, file, out) {
|
|
|
16138
16209
|
detail: "`parse_str()` of user input into the symbol table — variable injection."
|
|
16139
16210
|
});
|
|
16140
16211
|
}
|
|
16212
|
+
const bindRe = /foreach\s*\(\s*\$_(POST|GET|REQUEST|COOKIE)\b[^)]*\)\s*\{[^}]*\$this->\$[A-Za-z_]\w*\s*=/g;
|
|
16213
|
+
while ((m = bindRe.exec(code)) !== null) {
|
|
16214
|
+
const ln = lineNo2(code, m.index);
|
|
16215
|
+
const l = ls[ln - 1] ?? "";
|
|
16216
|
+
out.push({
|
|
16217
|
+
file,
|
|
16218
|
+
line: ln,
|
|
16219
|
+
type: "mass_assignment",
|
|
16220
|
+
category: "Mass assignment (dynamic field binding)",
|
|
16221
|
+
severity: "high",
|
|
16222
|
+
evidence: l.trim(),
|
|
16223
|
+
detail: "Request keys are bound to object properties without an allowlist — attacker can set privileged fields (role, is_admin)."
|
|
16224
|
+
});
|
|
16225
|
+
}
|
|
16226
|
+
const createRe = /\.create\s*\(\s*(req\.body|req\.query|request\.body|request\.data|\$_(POST|REQUEST))\b/g;
|
|
16227
|
+
while ((m = createRe.exec(code)) !== null) {
|
|
16228
|
+
const ln = lineNo2(code, m.index);
|
|
16229
|
+
const l = ls[ln - 1] ?? "";
|
|
16230
|
+
out.push({
|
|
16231
|
+
file,
|
|
16232
|
+
line: ln,
|
|
16233
|
+
type: "mass_assignment",
|
|
16234
|
+
category: "Mass assignment (unrestricted model create)",
|
|
16235
|
+
severity: "high",
|
|
16236
|
+
evidence: l.trim(),
|
|
16237
|
+
detail: "A model is created directly from request data without an allowlist — attacker can set privileged fields."
|
|
16238
|
+
});
|
|
16239
|
+
}
|
|
16141
16240
|
}
|
|
16142
16241
|
function detectComplexBugs(code, file) {
|
|
16143
16242
|
const out = [];
|
|
@@ -16171,7 +16270,7 @@ function detectComplexBugs(code, file) {
|
|
|
16171
16270
|
}
|
|
16172
16271
|
function detectPrototypePollution(code, file, out) {
|
|
16173
16272
|
const ls = lines2(code);
|
|
16174
|
-
const mergeRe =
|
|
16273
|
+
const mergeRe = /(Object\.assign|_\.merge|_\.defaultsDeep|\.extend|\.merge|\.defaultsDeep|mergeDeep|deepMerge|_\.set)\s*\(/g;
|
|
16175
16274
|
let m;
|
|
16176
16275
|
while ((m = mergeRe.exec(code)) !== null) {
|
|
16177
16276
|
const ln = lineNo2(code, m.index);
|
|
@@ -16193,7 +16292,7 @@ function detectPrototypePollution(code, file, out) {
|
|
|
16193
16292
|
}
|
|
16194
16293
|
function detectCrlfInjection(code, file, out) {
|
|
16195
16294
|
const ls = lines2(code);
|
|
16196
|
-
const headerRe = /\b(header|setHeader|addHeader|writeHead|appendHeader)\s*\(/g;
|
|
16295
|
+
const headerRe = /\b(header|setHeader|addHeader|writeHead|appendHeader|setcookie|setCookie|set_cookie)\s*\(/g;
|
|
16197
16296
|
let m;
|
|
16198
16297
|
while ((m = headerRe.exec(code)) !== null) {
|
|
16199
16298
|
const ln = lineNo2(code, m.index);
|
|
@@ -16246,7 +16345,7 @@ function detectPathConfusion(code, file, out) {
|
|
|
16246
16345
|
}
|
|
16247
16346
|
function detectSsrF(code, file, out) {
|
|
16248
16347
|
const ls = lines2(code);
|
|
16249
|
-
const re = /\b(file_get_contents|fopen|file|readfile|curl_setopt|curl_init|fetch|axios|requests\.(get|post|put)|urllib\.request|http_get|wp_remote_(get|post)|new\s+URL\s*\(|got\(|http\.(get|request))\s*\(/g;
|
|
16348
|
+
const re = /\b(file_get_contents|fopen|file|readfile|curl_setopt|curl_init|fetch|axios\.(get|post|put|request|delete|head)|requests\.(get|post|put)|urllib\.request|http_get|wp_remote_(get|post)|new\s+URL\s*\(|got\(|http\.(get|request))\s*\(/g;
|
|
16250
16349
|
let m;
|
|
16251
16350
|
while ((m = re.exec(code)) !== null) {
|
|
16252
16351
|
const ln = lineNo2(code, m.index);
|
|
@@ -16274,7 +16373,7 @@ function detectSsrF(code, file, out) {
|
|
|
16274
16373
|
}
|
|
16275
16374
|
function detectXxe(code, file, out) {
|
|
16276
16375
|
const ls = lines2(code);
|
|
16277
|
-
const re = /\b(simplexml_load_string|simplexml_load_file|new\s+SimpleXMLElement|->loadXML\s*\(|->load\s*\(|XMLReader\s*->\s*XML\s*\(|libxml_parse)\s*\(?/g;
|
|
16376
|
+
const re = /\b(simplexml_load_string|simplexml_load_file|new\s+SimpleXMLElement|->loadXML\s*\(|->load\s*\(|XMLReader\s*->\s*XML\s*\(|libxml_parse|DocumentBuilderFactory|SAXParserFactory|SAXReader)\s*\(?/g;
|
|
16278
16377
|
let m;
|
|
16279
16378
|
while ((m = re.exec(code)) !== null) {
|
|
16280
16379
|
const ln = lineNo2(code, m.index);
|
|
@@ -16299,7 +16398,7 @@ function detectXxe(code, file, out) {
|
|
|
16299
16398
|
}
|
|
16300
16399
|
function detectSsti(code, file, out) {
|
|
16301
16400
|
const ls = lines2(code);
|
|
16302
|
-
const re =
|
|
16401
|
+
const re = /(render_template_string|Template\s*\(|res\.render\s*\(|ejs\.(render|compile)\s*\(|_\.template\s*\(|render_string|twig->render|createTemplate\s*\(|Jinja2\(|jinja2\.Template|jinja2\.from_string|jinja2\.Environment)\s*\(?/g;
|
|
16303
16402
|
let m;
|
|
16304
16403
|
while ((m = re.exec(code)) !== null) {
|
|
16305
16404
|
const ln = lineNo2(code, m.index);
|
|
@@ -16322,14 +16421,14 @@ function detectSsti(code, file, out) {
|
|
|
16322
16421
|
function detectFileUploadRce(code, file, out) {
|
|
16323
16422
|
code = stripCommentsOnly(code);
|
|
16324
16423
|
const ls = lines2(code);
|
|
16325
|
-
const re = /\b(move_uploaded_file|wp_upload_bits|->move
|
|
16424
|
+
const re = /\b(move_uploaded_file|wp_upload_bits|->move|storeAs|->storeAs|putFile|\.save|uploadFile)\s*\(/g;
|
|
16326
16425
|
let m;
|
|
16327
16426
|
while ((m = re.exec(code)) !== null) {
|
|
16328
16427
|
const ln = lineNo2(code, m.index);
|
|
16329
16428
|
const l = ls[ln - 1] ?? "";
|
|
16330
16429
|
const scope = ls.slice(Math.max(0, ln - 30), ln + 3).join(`
|
|
16331
16430
|
`);
|
|
16332
|
-
if (!/\$_FILES\b|tmp_name|getUploadedFile|uploadedFile|\['name'\]/i.test(scope))
|
|
16431
|
+
if (!/\$_FILES\b|tmp_name|getUploadedFile|uploadedFile|req\.files|\['name'\]|\.name/i.test(scope))
|
|
16333
16432
|
continue;
|
|
16334
16433
|
if (/(wp_check_filetype|PATHINFO_EXTENSION|wp_get_mime_types|allowed_?(types|extensions|exts)|mime_?(types|extensions)|in_array\s*\([^)]*\$(?:allowed|whitelist|ext)|wp_handle_upload\s*\(\s*[^)]*test_form\s*=>\s*true)/i.test(scope))
|
|
16335
16434
|
continue;
|
|
@@ -16367,7 +16466,7 @@ function detectUnrestrictedUpload(code, file, out) {
|
|
|
16367
16466
|
}
|
|
16368
16467
|
function detectSqlInjection(code, file, out) {
|
|
16369
16468
|
const ls = lines2(code);
|
|
16370
|
-
const sinkRe = /\$wpdb->(get_results|get_col|get_var|get_row|query)\s*\(|->query\s*\(|DB::unprepared\s*\(
|
|
16469
|
+
const sinkRe = /\$wpdb->(get_results|get_col|get_var|get_row|query)\s*\(|->query\s*\(|->execute\s*\(|mysqli_query\s*\(|pg_query\s*\(|DB::unprepared\s*\(|[->.]whereRaw\s*\(|[->.]selectRaw\s*\(/g;
|
|
16371
16470
|
let m;
|
|
16372
16471
|
while ((m = sinkRe.exec(code)) !== null) {
|
|
16373
16472
|
const ln = lineNo2(code, m.index);
|
|
@@ -16378,7 +16477,7 @@ function detectSqlInjection(code, file, out) {
|
|
|
16378
16477
|
continue;
|
|
16379
16478
|
if (SOURCE_TOKENS3.test(scope))
|
|
16380
16479
|
continue;
|
|
16381
|
-
const inlineConcat =
|
|
16480
|
+
const inlineConcat = /(\.\s*\$[A-Za-z_]\w*|\+\s*[A-Za-z_$]\w*)/.test(l);
|
|
16382
16481
|
const assignConcat = /(?:^|\n)\s*\$[A-Za-z_]\w*\s*(?:\.=|=)\s*[^;\n]*["'][^"']*["']\s*\.\s*\$[A-Za-z_]\w*/.test(scope);
|
|
16383
16482
|
if (!inlineConcat && !assignConcat)
|
|
16384
16483
|
continue;
|
|
@@ -16440,10 +16539,10 @@ function detectHardcodedSecret(code, file, out) {
|
|
|
16440
16539
|
file,
|
|
16441
16540
|
line: ln,
|
|
16442
16541
|
type: "hardcoded_secret",
|
|
16443
|
-
category:
|
|
16444
|
-
severity:
|
|
16542
|
+
category: `Hardcoded secret (${fmt.category}: ${fmt.name})`,
|
|
16543
|
+
severity: fmt.severity,
|
|
16445
16544
|
evidence: (ls[ln - 1] ?? "").trim(),
|
|
16446
|
-
detail:
|
|
16545
|
+
detail: `${fmt.name} was found hardcoded in source — the credential is exposed to anyone with code access (CWE-798, severity ${fmt.severity}). Rotate it and load from the environment instead.`
|
|
16447
16546
|
});
|
|
16448
16547
|
}
|
|
16449
16548
|
}
|
|
@@ -16547,7 +16646,7 @@ function detectOauthMisconfig(code, file, out) {
|
|
|
16547
16646
|
function detectGrpcReflection(code, file, out) {
|
|
16548
16647
|
const ls = lines2(code);
|
|
16549
16648
|
const clean = stripCommentsOnly(code);
|
|
16550
|
-
const re =
|
|
16649
|
+
const re = /grpc_reflection|enable_server_reflection|RegisterReflectionService|reflection\.enable|ServerReflection|ReflectionServicer|reflection\.Register/gi;
|
|
16551
16650
|
let m;
|
|
16552
16651
|
while ((m = re.exec(clean)) !== null) {
|
|
16553
16652
|
const ln = lineNo2(code, m.index);
|
|
@@ -16567,7 +16666,7 @@ var init_complex_bugs = __esm(() => {
|
|
|
16567
16666
|
init_security_state();
|
|
16568
16667
|
init_framework_security();
|
|
16569
16668
|
init_secrets();
|
|
16570
|
-
SOURCE_TOKENS3 = /\$_(GET|POST|REQUEST|COOKIE|FILES|SERVER)\b|\$request->|\$req->|request\.(get|input|query|post|data|body|headers|cookies|params)|getParameter\(|req\.(query|body|params|headers|cookies)/;
|
|
16669
|
+
SOURCE_TOKENS3 = /\$_(GET|POST|REQUEST|COOKIE|FILES|SERVER)\b|\$request->|\$req->|request\.(get|input|query|post|data|body|headers|cookies|params|args|form|values|json)|getParameter\(|req\.(query|body|params|headers|cookies|args|form)|php:\/\/input/;
|
|
16571
16670
|
MAGIC_METHODS = /\b(__destruct|__wakeup|__toString|__invoke|__call|__get|__set|__isset|__unset|__sleep)\s*\(/;
|
|
16572
16671
|
SECRET_FIELD_RE = new RegExp(`\\b(${SECRET_FIELDS})\\s*(?:::|=>|=|:)\\s*`, "gi");
|
|
16573
16672
|
SECRET_PLACEHOLDER_RE = /^(null|true|false|undefined|your_|xxx+|changeme|example|placeholder|test|secret|password|token|key|api|smtp|localhost|root|admin|pass|change|me|none|na|foo|bar|dummy)$/i;
|
|
@@ -16747,11 +16846,75 @@ $r = openai.chat.completions.create(['messages' => [['role' => 'user', 'content'
|
|
|
16747
16846
|
];
|
|
16748
16847
|
});
|
|
16749
16848
|
|
|
16849
|
+
// src/variants.ts
|
|
16850
|
+
import { readFileSync as readFileSync19 } from "node:fs";
|
|
16851
|
+
import { join as join18, dirname as dirname4 } from "node:path";
|
|
16852
|
+
import { fileURLToPath as fileURLToPath10 } from "node:url";
|
|
16853
|
+
function loadVariants() {
|
|
16854
|
+
try {
|
|
16855
|
+
const doc = JSON.parse(readFileSync19(join18(__dirname4, "..", "intelligence", "variants.json"), "utf8"));
|
|
16856
|
+
return doc.variants ?? [];
|
|
16857
|
+
} catch {
|
|
16858
|
+
return [];
|
|
16859
|
+
}
|
|
16860
|
+
}
|
|
16861
|
+
function scanVariants() {
|
|
16862
|
+
const variants = loadVariants().filter((v) => !CROSS_FILE_ONLY.has(v.class));
|
|
16863
|
+
const results = variants.map((v, i) => {
|
|
16864
|
+
const findings = detectComplexBugs(v.code, `variant-${i}.php`).filter((f) => f.type === v.class);
|
|
16865
|
+
return { id: `variant-${i}`, class: v.class, fired: findings.length > 0, note: v.note };
|
|
16866
|
+
});
|
|
16867
|
+
const per_class = {};
|
|
16868
|
+
for (const r of results) {
|
|
16869
|
+
const c = per_class[r.class] ??= { total: 0, fired: 0, missed: 0, coverage: 0 };
|
|
16870
|
+
c.total++;
|
|
16871
|
+
if (r.fired)
|
|
16872
|
+
c.fired++;
|
|
16873
|
+
else
|
|
16874
|
+
c.missed++;
|
|
16875
|
+
c.coverage = c.fired / c.total;
|
|
16876
|
+
}
|
|
16877
|
+
const fired = results.filter((r) => r.fired).length;
|
|
16878
|
+
return {
|
|
16879
|
+
total: results.length,
|
|
16880
|
+
fired,
|
|
16881
|
+
missed: results.length - fired,
|
|
16882
|
+
coverage: results.length > 0 ? fired / results.length : 0,
|
|
16883
|
+
per_class,
|
|
16884
|
+
results
|
|
16885
|
+
};
|
|
16886
|
+
}
|
|
16887
|
+
function variantCoverageText() {
|
|
16888
|
+
const r = scanVariants();
|
|
16889
|
+
const lines = [];
|
|
16890
|
+
lines.push(`Blitz Strike variant corpus`);
|
|
16891
|
+
lines.push(` ${r.fired}/${r.total} shapes detected (${(r.coverage * 100).toFixed(0)}%) · ${r.missed} missed`);
|
|
16892
|
+
lines.push(``);
|
|
16893
|
+
for (const [cls, c] of Object.entries(r.per_class)) {
|
|
16894
|
+
const mark = c.missed === 0 ? "OK " : "GAP";
|
|
16895
|
+
lines.push(` [${mark}] ${cls.padEnd(20)} ${c.fired}/${c.total}`);
|
|
16896
|
+
}
|
|
16897
|
+
if (r.missed > 0) {
|
|
16898
|
+
lines.push(``);
|
|
16899
|
+
for (const res of r.results.filter((x) => !x.fired)) {
|
|
16900
|
+
lines.push(` missed: ${res.class} — ${res.note}`);
|
|
16901
|
+
}
|
|
16902
|
+
}
|
|
16903
|
+
return lines.join(`
|
|
16904
|
+
`);
|
|
16905
|
+
}
|
|
16906
|
+
var __dirname4, CROSS_FILE_ONLY;
|
|
16907
|
+
var init_variants = __esm(() => {
|
|
16908
|
+
init_complex_bugs();
|
|
16909
|
+
__dirname4 = dirname4(fileURLToPath10(import.meta.url));
|
|
16910
|
+
CROSS_FILE_ONLY = new Set(["priv_esc"]);
|
|
16911
|
+
});
|
|
16912
|
+
|
|
16750
16913
|
// src/sync.ts
|
|
16751
|
-
import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync8, readFileSync as
|
|
16752
|
-
import { join as
|
|
16914
|
+
import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync8, readFileSync as readFileSync25, readdirSync as readdirSync7, statSync as statSync4, rmSync as rmSync4 } from "node:fs";
|
|
16915
|
+
import { join as join22 } from "node:path";
|
|
16753
16916
|
import { homedir as homedir10 } from "node:os";
|
|
16754
|
-
import { fileURLToPath as
|
|
16917
|
+
import { fileURLToPath as fileURLToPath12 } from "node:url";
|
|
16755
16918
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
16756
16919
|
function dirExists(p) {
|
|
16757
16920
|
try {
|
|
@@ -16766,7 +16929,7 @@ function countFiles(dir) {
|
|
|
16766
16929
|
const walk = (d) => {
|
|
16767
16930
|
for (const e of readdirSync7(d, { withFileTypes: true })) {
|
|
16768
16931
|
if (e.isDirectory())
|
|
16769
|
-
walk(
|
|
16932
|
+
walk(join22(d, e.name));
|
|
16770
16933
|
else
|
|
16771
16934
|
n++;
|
|
16772
16935
|
}
|
|
@@ -16780,8 +16943,8 @@ function countFiles(dir) {
|
|
|
16780
16943
|
function syncData() {
|
|
16781
16944
|
if (!dirExists(DATA_ROOT2))
|
|
16782
16945
|
mkdirSync9(DATA_ROOT2, { recursive: true });
|
|
16783
|
-
const payloadsPath =
|
|
16784
|
-
const templatesPath =
|
|
16946
|
+
const payloadsPath = join22(DATA_ROOT2, "payloads");
|
|
16947
|
+
const templatesPath = join22(DATA_ROOT2, "templates");
|
|
16785
16948
|
const hasPayloads = dirExists(payloadsPath) && countFiles(payloadsPath) > 0;
|
|
16786
16949
|
const hasTemplates = dirExists(templatesPath) && countFiles(templatesPath) > 0;
|
|
16787
16950
|
if (hasPayloads && hasTemplates) {
|
|
@@ -16791,8 +16954,8 @@ function syncData() {
|
|
|
16791
16954
|
data_root: DATA_ROOT2
|
|
16792
16955
|
};
|
|
16793
16956
|
}
|
|
16794
|
-
const localPayloads =
|
|
16795
|
-
const localTemplates =
|
|
16957
|
+
const localPayloads = join22(ROOT7, "payloads");
|
|
16958
|
+
const localTemplates = join22(ROOT7, "templates");
|
|
16796
16959
|
let payloadsSynced = false;
|
|
16797
16960
|
let templatesSynced = false;
|
|
16798
16961
|
if (!hasPayloads && dirExists(localPayloads)) {
|
|
@@ -16805,7 +16968,7 @@ function syncData() {
|
|
|
16805
16968
|
}
|
|
16806
16969
|
const gitOk = spawnSync4("git", ["--version"]).status === 0;
|
|
16807
16970
|
if (gitOk && (!dirExists(payloadsPath) || countFiles(payloadsPath) === 0 || !dirExists(templatesPath) || countFiles(templatesPath) === 0)) {
|
|
16808
|
-
const tmp =
|
|
16971
|
+
const tmp = join22(DATA_ROOT2, ".tmp-clone");
|
|
16809
16972
|
if (dirExists(tmp))
|
|
16810
16973
|
rmSync4(tmp, { recursive: true, force: true });
|
|
16811
16974
|
const r = spawnSync4("git", ["clone", "--depth", "1", "--filter=blob:none", "--sparse", GITHUB_REPO, tmp], { timeout: 120000 });
|
|
@@ -16813,11 +16976,11 @@ function syncData() {
|
|
|
16813
16976
|
const sparse = spawnSync4("git", ["-C", tmp, "sparse-checkout", "set", "payloads", "templates"], { timeout: 120000 });
|
|
16814
16977
|
if (sparse.status === 0) {
|
|
16815
16978
|
if (!dirExists(payloadsPath) || countFiles(payloadsPath) === 0) {
|
|
16816
|
-
copyDir(
|
|
16979
|
+
copyDir(join22(tmp, "payloads"), payloadsPath);
|
|
16817
16980
|
payloadsSynced = true;
|
|
16818
16981
|
}
|
|
16819
16982
|
if (!dirExists(templatesPath) || countFiles(templatesPath) === 0) {
|
|
16820
|
-
copyDir(
|
|
16983
|
+
copyDir(join22(tmp, "templates"), templatesPath);
|
|
16821
16984
|
templatesSynced = true;
|
|
16822
16985
|
}
|
|
16823
16986
|
}
|
|
@@ -16839,18 +17002,18 @@ function copyDir(src, dst) {
|
|
|
16839
17002
|
function manualCopy(src, dst) {
|
|
16840
17003
|
mkdirSync9(dst, { recursive: true });
|
|
16841
17004
|
for (const e of readdirSync7(src, { withFileTypes: true })) {
|
|
16842
|
-
const s =
|
|
16843
|
-
const d =
|
|
17005
|
+
const s = join22(src, e.name);
|
|
17006
|
+
const d = join22(dst, e.name);
|
|
16844
17007
|
if (e.isDirectory())
|
|
16845
17008
|
manualCopy(s, d);
|
|
16846
17009
|
else
|
|
16847
|
-
writeFileSync8(d,
|
|
17010
|
+
writeFileSync8(d, readFileSync25(s));
|
|
16848
17011
|
}
|
|
16849
17012
|
}
|
|
16850
17013
|
var ROOT7, DATA_ROOT2, GITHUB_REPO = "https://github.com/shinthink/blitzstrike.git";
|
|
16851
17014
|
var init_sync = __esm(() => {
|
|
16852
|
-
ROOT7 =
|
|
16853
|
-
DATA_ROOT2 = process.env.BLITZSTRIKE_DATA ??
|
|
17015
|
+
ROOT7 = join22(fileURLToPath12(new URL(".", import.meta.url)), "..");
|
|
17016
|
+
DATA_ROOT2 = process.env.BLITZSTRIKE_DATA ?? join22(homedir10(), ".blitzstrike", "data");
|
|
16854
17017
|
});
|
|
16855
17018
|
|
|
16856
17019
|
// src/update.ts
|
|
@@ -16895,15 +17058,15 @@ var init_update = __esm(() => {
|
|
|
16895
17058
|
});
|
|
16896
17059
|
|
|
16897
17060
|
// src/release.ts
|
|
16898
|
-
import { readFileSync as
|
|
16899
|
-
import { join as
|
|
16900
|
-
import { fileURLToPath as
|
|
17061
|
+
import { readFileSync as readFileSync27, existsSync as existsSync12 } from "node:fs";
|
|
17062
|
+
import { join as join23 } from "node:path";
|
|
17063
|
+
import { fileURLToPath as fileURLToPath13 } from "node:url";
|
|
16901
17064
|
import { execSync as execSync2 } from "node:child_process";
|
|
16902
17065
|
function validateRelease() {
|
|
16903
17066
|
const checks = [];
|
|
16904
17067
|
checks.push({ name: "package.json version", ok: true, detail: VERSION });
|
|
16905
17068
|
try {
|
|
16906
|
-
const changelog =
|
|
17069
|
+
const changelog = readFileSync27(join23(ROOT8, "CHANGELOG.md"), "utf8");
|
|
16907
17070
|
const m = changelog.match(/^##\s+\[([0-9]+\.[0-9]+\.[0-9]+)\]/m);
|
|
16908
17071
|
const changelogVersion = m?.[1] ?? null;
|
|
16909
17072
|
checks.push({
|
|
@@ -16935,22 +17098,22 @@ function validateRelease() {
|
|
|
16935
17098
|
return { version: VERSION, checks, consistent: checks.filter((c) => !c.soft).every((c) => c.ok) };
|
|
16936
17099
|
}
|
|
16937
17100
|
function lockfilePresent() {
|
|
16938
|
-
return existsSync12(
|
|
17101
|
+
return existsSync12(join23(ROOT8, "package-lock.json")) || existsSync12(join23(ROOT8, "bun.lock")) || existsSync12(join23(ROOT8, "bun.lockb"));
|
|
16939
17102
|
}
|
|
16940
17103
|
var ROOT8;
|
|
16941
17104
|
var init_release = __esm(() => {
|
|
16942
17105
|
init_version();
|
|
16943
|
-
ROOT8 =
|
|
17106
|
+
ROOT8 = join23(fileURLToPath13(new URL(".", import.meta.url)), "..");
|
|
16944
17107
|
});
|
|
16945
17108
|
|
|
16946
17109
|
// src/dependency.ts
|
|
16947
|
-
import { readFileSync as
|
|
16948
|
-
import { join as
|
|
16949
|
-
import { fileURLToPath as
|
|
17110
|
+
import { readFileSync as readFileSync28 } from "node:fs";
|
|
17111
|
+
import { join as join24 } from "node:path";
|
|
17112
|
+
import { fileURLToPath as fileURLToPath14 } from "node:url";
|
|
16950
17113
|
function checkDependencies() {
|
|
16951
17114
|
let pkg = {};
|
|
16952
17115
|
try {
|
|
16953
|
-
pkg = JSON.parse(
|
|
17116
|
+
pkg = JSON.parse(readFileSync28(join24(ROOT9, "package.json"), "utf8"));
|
|
16954
17117
|
} catch {
|
|
16955
17118
|
return { install_scripts: [], git_dependencies: [], total_dependencies: 0, safe: false };
|
|
16956
17119
|
}
|
|
@@ -16973,14 +17136,14 @@ function checkDependencies() {
|
|
|
16973
17136
|
}
|
|
16974
17137
|
var ROOT9;
|
|
16975
17138
|
var init_dependency = __esm(() => {
|
|
16976
|
-
ROOT9 =
|
|
17139
|
+
ROOT9 = join24(fileURLToPath14(new URL(".", import.meta.url)), "..");
|
|
16977
17140
|
});
|
|
16978
17141
|
|
|
16979
17142
|
// src/cli.ts
|
|
16980
|
-
import { readFileSync as
|
|
16981
|
-
import { join as
|
|
17143
|
+
import { readFileSync as readFileSync29, existsSync as existsSync13, writeFileSync as writeFileSync9, mkdirSync as mkdirSync10 } from "node:fs";
|
|
17144
|
+
import { join as join25, dirname as dirname5 } from "node:path";
|
|
16982
17145
|
import { homedir as homedir11 } from "node:os";
|
|
16983
|
-
import { fileURLToPath as
|
|
17146
|
+
import { fileURLToPath as fileURLToPath15 } from "node:url";
|
|
16984
17147
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
16985
17148
|
function which(cmd) {
|
|
16986
17149
|
return spawnSync5("sh", ["-c", 'command -v "$1" >/dev/null 2>&1', "sh", cmd]).status === 0;
|
|
@@ -17023,7 +17186,7 @@ async function runDoctor() {
|
|
|
17023
17186
|
detail: h1 ? `X-HackerOne-Research: ${h1}` : "H1_USERNAME not set",
|
|
17024
17187
|
fix: h1 ? undefined : "export H1_USERNAME=<your-hackerone-username> (adds X-HackerOne-Research to outbound requests)"
|
|
17025
17188
|
});
|
|
17026
|
-
const dataOk = existsSync13(
|
|
17189
|
+
const dataOk = existsSync13(join25(ROOT10, "chains.json")) && existsSync13(join25(ROOT10, "tools-catalog.json"));
|
|
17027
17190
|
issues.push({
|
|
17028
17191
|
name: "Data layers (chains + tools-catalog)",
|
|
17029
17192
|
status: dataOk ? "ok" : "fail",
|
|
@@ -17074,28 +17237,28 @@ BlitzStrike — ${verdict}`);
|
|
|
17074
17237
|
function resolveCommand() {
|
|
17075
17238
|
if (which("blitzstrike"))
|
|
17076
17239
|
return { command: "blitzstrike", args: ["serve", "--mcp"] };
|
|
17077
|
-
const src =
|
|
17240
|
+
const src = join25(ROOT10, "src", "index.ts");
|
|
17078
17241
|
if (which("bun") && existsSync13(src))
|
|
17079
17242
|
return { command: "bun", args: ["run", src, "serve", "--mcp"] };
|
|
17080
17243
|
if (which("npx"))
|
|
17081
17244
|
return { command: "npx", args: ["-y", "blitzstrike", "serve", "--mcp"] };
|
|
17082
17245
|
if (which("bunx"))
|
|
17083
17246
|
return { command: "bunx", args: ["blitzstrike", "serve", "--mcp"] };
|
|
17084
|
-
const dist =
|
|
17247
|
+
const dist = join25(ROOT10, "dist", "index.js");
|
|
17085
17248
|
if (existsSync13(dist))
|
|
17086
17249
|
return { command: "bun", args: [dist, "serve", "--mcp"] };
|
|
17087
17250
|
return { command: "npx", args: ["-y", "blitzstrike", "serve", "--mcp"] };
|
|
17088
17251
|
}
|
|
17089
17252
|
function readJson(p) {
|
|
17090
17253
|
try {
|
|
17091
|
-
return JSON.parse(
|
|
17254
|
+
return JSON.parse(readFileSync29(p, "utf8"));
|
|
17092
17255
|
} catch {
|
|
17093
17256
|
return null;
|
|
17094
17257
|
}
|
|
17095
17258
|
}
|
|
17096
17259
|
function jsonMcpServersWrite(p) {
|
|
17097
17260
|
return (command, args) => {
|
|
17098
|
-
const dir =
|
|
17261
|
+
const dir = dirname5(p);
|
|
17099
17262
|
if (!existsSync13(dir))
|
|
17100
17263
|
mkdirSync10(dir, { recursive: true });
|
|
17101
17264
|
const existing = readJson(p) ?? {};
|
|
@@ -17108,7 +17271,7 @@ function jsonMcpServersWrite(p) {
|
|
|
17108
17271
|
}
|
|
17109
17272
|
function opencodeWrite(p) {
|
|
17110
17273
|
return (command, args) => {
|
|
17111
|
-
const dir =
|
|
17274
|
+
const dir = dirname5(p);
|
|
17112
17275
|
if (!existsSync13(dir))
|
|
17113
17276
|
mkdirSync10(dir, { recursive: true });
|
|
17114
17277
|
const existing = readJson(p) ?? {};
|
|
@@ -17121,26 +17284,26 @@ function opencodeWrite(p) {
|
|
|
17121
17284
|
};
|
|
17122
17285
|
}
|
|
17123
17286
|
function copyOpenCodeAgents() {
|
|
17124
|
-
const srcDir =
|
|
17125
|
-
const dstDir =
|
|
17287
|
+
const srcDir = join25(ROOT10, "opencode-agents");
|
|
17288
|
+
const dstDir = join25(homedir11(), ".config", "opencode", "agents");
|
|
17126
17289
|
if (!existsSync13(srcDir))
|
|
17127
17290
|
return;
|
|
17128
17291
|
if (!existsSync13(dstDir))
|
|
17129
17292
|
mkdirSync10(dstDir, { recursive: true });
|
|
17130
17293
|
for (const f of ["Blitz Strike.md", "Blitz.md", "Eagle Eye.md", "Strike.md"]) {
|
|
17131
|
-
const src =
|
|
17132
|
-
const dst =
|
|
17294
|
+
const src = join25(srcDir, f);
|
|
17295
|
+
const dst = join25(dstDir, f);
|
|
17133
17296
|
if (existsSync13(src)) {
|
|
17134
|
-
writeFileSync9(dst,
|
|
17297
|
+
writeFileSync9(dst, readFileSync29(src, "utf8"));
|
|
17135
17298
|
}
|
|
17136
17299
|
}
|
|
17137
17300
|
}
|
|
17138
17301
|
function codexWrite(p) {
|
|
17139
17302
|
return (command, args) => {
|
|
17140
|
-
const dir =
|
|
17303
|
+
const dir = dirname5(p);
|
|
17141
17304
|
if (!existsSync13(dir))
|
|
17142
17305
|
mkdirSync10(dir, { recursive: true });
|
|
17143
|
-
let existing = existsSync13(p) ?
|
|
17306
|
+
let existing = existsSync13(p) ? readFileSync29(p, "utf8") : "";
|
|
17144
17307
|
if (!existing.trimEnd().endsWith(`
|
|
17145
17308
|
`))
|
|
17146
17309
|
existing += `
|
|
@@ -17156,10 +17319,10 @@ args = ${JSON.stringify(args)}
|
|
|
17156
17319
|
}
|
|
17157
17320
|
function hermesWrite(p) {
|
|
17158
17321
|
return (command, args) => {
|
|
17159
|
-
const dir =
|
|
17322
|
+
const dir = dirname5(p);
|
|
17160
17323
|
if (!existsSync13(dir))
|
|
17161
17324
|
mkdirSync10(dir, { recursive: true });
|
|
17162
|
-
let existing = existsSync13(p) ?
|
|
17325
|
+
let existing = existsSync13(p) ? readFileSync29(p, "utf8") : "";
|
|
17163
17326
|
existing = existing.replace(/^ blitzstrike:\n(?: .*\n?)*/m, "");
|
|
17164
17327
|
if (!existing.trimEnd().endsWith(`
|
|
17165
17328
|
`))
|
|
@@ -17186,74 +17349,74 @@ mcp_servers:
|
|
|
17186
17349
|
function detectAgents() {
|
|
17187
17350
|
const home = homedir11();
|
|
17188
17351
|
const agents = [];
|
|
17189
|
-
const claudeJson =
|
|
17352
|
+
const claudeJson = join25(home, ".claude.json");
|
|
17190
17353
|
agents.push({
|
|
17191
17354
|
name: "Claude Code",
|
|
17192
17355
|
detectPath: claudeJson,
|
|
17193
17356
|
installed: () => existsSync13(claudeJson) || which("claude"),
|
|
17194
17357
|
write: jsonMcpServersWrite(claudeJson)
|
|
17195
17358
|
});
|
|
17196
|
-
const claudeDesktop =
|
|
17359
|
+
const claudeDesktop = join25(home, ".config", "Claude", "claude_desktop_config.json");
|
|
17197
17360
|
agents.push({
|
|
17198
17361
|
name: "Claude Desktop",
|
|
17199
17362
|
detectPath: claudeDesktop,
|
|
17200
17363
|
installed: () => existsSync13(claudeDesktop),
|
|
17201
17364
|
write: jsonMcpServersWrite(claudeDesktop)
|
|
17202
17365
|
});
|
|
17203
|
-
const cursor =
|
|
17366
|
+
const cursor = join25(home, ".cursor", "mcp.json");
|
|
17204
17367
|
agents.push({
|
|
17205
17368
|
name: "Cursor",
|
|
17206
17369
|
detectPath: cursor,
|
|
17207
|
-
installed: () => existsSync13(
|
|
17370
|
+
installed: () => existsSync13(join25(home, ".cursor")) || which("cursor"),
|
|
17208
17371
|
write: jsonMcpServersWrite(cursor)
|
|
17209
17372
|
});
|
|
17210
|
-
const opencode =
|
|
17373
|
+
const opencode = join25(home, ".config", "opencode", "opencode.jsonc");
|
|
17211
17374
|
agents.push({
|
|
17212
17375
|
name: "OpenCode",
|
|
17213
17376
|
detectPath: opencode,
|
|
17214
|
-
installed: () => existsSync13(
|
|
17377
|
+
installed: () => existsSync13(join25(home, ".config", "opencode")) || which("opencode"),
|
|
17215
17378
|
write: opencodeWrite(opencode)
|
|
17216
17379
|
});
|
|
17217
|
-
const codex =
|
|
17380
|
+
const codex = join25(home, ".codex", "config.toml");
|
|
17218
17381
|
agents.push({
|
|
17219
17382
|
name: "Codex",
|
|
17220
17383
|
detectPath: codex,
|
|
17221
|
-
installed: () => existsSync13(
|
|
17384
|
+
installed: () => existsSync13(join25(home, ".codex")) || which("codex"),
|
|
17222
17385
|
write: codexWrite(codex)
|
|
17223
17386
|
});
|
|
17224
|
-
const hermes =
|
|
17387
|
+
const hermes = join25(home, ".hermes", "config.yaml");
|
|
17225
17388
|
agents.push({
|
|
17226
17389
|
name: "Hermes",
|
|
17227
17390
|
detectPath: hermes,
|
|
17228
|
-
installed: () => existsSync13(
|
|
17391
|
+
installed: () => existsSync13(join25(home, ".hermes")) || which("hermes"),
|
|
17229
17392
|
write: hermesWrite(hermes)
|
|
17230
17393
|
});
|
|
17231
|
-
const gemini =
|
|
17394
|
+
const gemini = join25(home, ".gemini", "settings.json");
|
|
17232
17395
|
agents.push({
|
|
17233
17396
|
name: "Gemini CLI",
|
|
17234
17397
|
detectPath: gemini,
|
|
17235
|
-
installed: () => existsSync13(
|
|
17398
|
+
installed: () => existsSync13(join25(home, ".gemini")) || which("gemini"),
|
|
17236
17399
|
write: jsonMcpServersWrite(gemini)
|
|
17237
17400
|
});
|
|
17238
|
-
const windsurf =
|
|
17401
|
+
const windsurf = join25(home, ".codeium", "windsurf", "mcp_config.json");
|
|
17239
17402
|
agents.push({
|
|
17240
17403
|
name: "Windsurf",
|
|
17241
17404
|
detectPath: windsurf,
|
|
17242
|
-
installed: () => existsSync13(
|
|
17405
|
+
installed: () => existsSync13(join25(home, ".codeium")) || which("windsurf"),
|
|
17243
17406
|
write: jsonMcpServersWrite(windsurf)
|
|
17244
17407
|
});
|
|
17245
|
-
const copilot =
|
|
17408
|
+
const copilot = join25(home, ".copilot", "mcp.json");
|
|
17246
17409
|
agents.push({
|
|
17247
17410
|
name: "Copilot",
|
|
17248
17411
|
detectPath: copilot,
|
|
17249
|
-
installed: () => existsSync13(
|
|
17412
|
+
installed: () => existsSync13(join25(home, ".copilot")),
|
|
17250
17413
|
write: jsonMcpServersWrite(copilot)
|
|
17251
17414
|
});
|
|
17252
|
-
const cline =
|
|
17415
|
+
const cline = join25(home, ".cline", "mcp_settings.json");
|
|
17253
17416
|
agents.push({
|
|
17254
17417
|
name: "Cline",
|
|
17255
17418
|
detectPath: cline,
|
|
17256
|
-
installed: () => existsSync13(
|
|
17419
|
+
installed: () => existsSync13(join25(home, ".cline")),
|
|
17257
17420
|
write: jsonMcpServersWrite(cline)
|
|
17258
17421
|
});
|
|
17259
17422
|
return agents;
|
|
@@ -17371,7 +17534,7 @@ var init_cli = __esm(() => {
|
|
|
17371
17534
|
init_release();
|
|
17372
17535
|
init_dependency();
|
|
17373
17536
|
init_mcp_status();
|
|
17374
|
-
ROOT10 =
|
|
17537
|
+
ROOT10 = join25(fileURLToPath15(new URL(".", import.meta.url)), "..");
|
|
17375
17538
|
});
|
|
17376
17539
|
|
|
17377
17540
|
// node_modules/zod/v3/helpers/util.js
|
|
@@ -32009,7 +32172,7 @@ class StdioServerTransport {
|
|
|
32009
32172
|
|
|
32010
32173
|
// src/server.ts
|
|
32011
32174
|
init_scanner();
|
|
32012
|
-
import { readFileSync as
|
|
32175
|
+
import { readFileSync as readFileSync26 } from "node:fs";
|
|
32013
32176
|
|
|
32014
32177
|
// src/recon.ts
|
|
32015
32178
|
var TIMEOUT_MS = 25000;
|
|
@@ -57675,20 +57838,21 @@ function dataRefresh() {
|
|
|
57675
57838
|
|
|
57676
57839
|
// src/server.ts
|
|
57677
57840
|
init_verify_harness();
|
|
57841
|
+
init_variants();
|
|
57678
57842
|
|
|
57679
57843
|
// src/benchmark.ts
|
|
57680
|
-
import { readFileSync as
|
|
57681
|
-
import { join as
|
|
57682
|
-
import { fileURLToPath as
|
|
57844
|
+
import { readFileSync as readFileSync20, readdirSync as readdirSync5, writeFileSync as writeFileSync6, rmSync as rmSync3, mkdirSync as mkdirSync7 } from "node:fs";
|
|
57845
|
+
import { join as join19 } from "node:path";
|
|
57846
|
+
import { fileURLToPath as fileURLToPath11 } from "node:url";
|
|
57683
57847
|
import { tmpdir as tmpdir3, homedir as homedir8 } from "node:os";
|
|
57684
57848
|
init_complex_bugs();
|
|
57685
|
-
var ROOT5 =
|
|
57686
|
-
var CORPUS =
|
|
57687
|
-
var CAPTURED_CORPUS_DIR = process.env.BLITZSTRIKE_CORPUS_DIR ??
|
|
57849
|
+
var ROOT5 = join19(fileURLToPath11(new URL(".", import.meta.url)), "..");
|
|
57850
|
+
var CORPUS = join19(ROOT5, "bench", "corpus");
|
|
57851
|
+
var CAPTURED_CORPUS_DIR = process.env.BLITZSTRIKE_CORPUS_DIR ?? join19(homedir8(), ".blitzstrike", "corpus");
|
|
57688
57852
|
function parseCorpusFile(path) {
|
|
57689
57853
|
let text;
|
|
57690
57854
|
try {
|
|
57691
|
-
text =
|
|
57855
|
+
text = readFileSync20(path, "utf8");
|
|
57692
57856
|
} catch {
|
|
57693
57857
|
return null;
|
|
57694
57858
|
}
|
|
@@ -57744,7 +57908,7 @@ function loadDir(dir) {
|
|
|
57744
57908
|
for (const f of readdirSync5(dir)) {
|
|
57745
57909
|
if (!f.endsWith(".md"))
|
|
57746
57910
|
continue;
|
|
57747
|
-
const e = parseCorpusFile(
|
|
57911
|
+
const e = parseCorpusFile(join19(dir, f));
|
|
57748
57912
|
if (e)
|
|
57749
57913
|
entries.push(e);
|
|
57750
57914
|
}
|
|
@@ -57771,7 +57935,7 @@ function captureFalsePositive(input) {
|
|
|
57771
57935
|
input.code,
|
|
57772
57936
|
"```"
|
|
57773
57937
|
].filter((l) => l !== null);
|
|
57774
|
-
const path =
|
|
57938
|
+
const path = join19(CAPTURED_CORPUS_DIR, `${id}.md`);
|
|
57775
57939
|
writeFileSync6(path, lines.join(`
|
|
57776
57940
|
`) + `
|
|
57777
57941
|
`, "utf8");
|
|
@@ -57793,7 +57957,7 @@ function detect(entry) {
|
|
|
57793
57957
|
}
|
|
57794
57958
|
const lang = entry.language;
|
|
57795
57959
|
if (lang === "php") {
|
|
57796
|
-
const tmp =
|
|
57960
|
+
const tmp = join19(tmpdir3(), `blitzstrike-bench-${entry.id}-${process.pid}.php`);
|
|
57797
57961
|
writeFileSync6(tmp, entry.code);
|
|
57798
57962
|
const r = analyzeDataFlow2(tmp);
|
|
57799
57963
|
rmSync3(tmp, { force: true });
|
|
@@ -57862,12 +58026,12 @@ function runBenchmark() {
|
|
|
57862
58026
|
}
|
|
57863
58027
|
|
|
57864
58028
|
// src/obligations.ts
|
|
57865
|
-
import { readFileSync as
|
|
57866
|
-
import { join as
|
|
58029
|
+
import { readFileSync as readFileSync21, appendFileSync as appendFileSync4, mkdirSync as mkdirSync8, existsSync as existsSync10, writeFileSync as writeFileSync7 } from "node:fs";
|
|
58030
|
+
import { join as join20 } from "node:path";
|
|
57867
58031
|
import { createHash as createHash6 } from "node:crypto";
|
|
57868
58032
|
import { homedir as homedir9 } from "node:os";
|
|
57869
|
-
var HOME_DIR4 = process.env.BLITZSTRIKE_HOME ??
|
|
57870
|
-
var OBLIGATION_PATH =
|
|
58033
|
+
var HOME_DIR4 = process.env.BLITZSTRIKE_HOME ?? join20(homedir9(), ".blitzstrike");
|
|
58034
|
+
var OBLIGATION_PATH = join20(HOME_DIR4, "obligations.jsonl");
|
|
57871
58035
|
function ensureDir3() {
|
|
57872
58036
|
if (!existsSync10(HOME_DIR4))
|
|
57873
58037
|
mkdirSync8(HOME_DIR4, { recursive: true });
|
|
@@ -57880,7 +58044,7 @@ function loadObligations() {
|
|
|
57880
58044
|
return [];
|
|
57881
58045
|
try {
|
|
57882
58046
|
const out = [];
|
|
57883
|
-
for (const line of
|
|
58047
|
+
for (const line of readFileSync21(OBLIGATION_PATH, "utf8").split(`
|
|
57884
58048
|
`)) {
|
|
57885
58049
|
const t = line.trim();
|
|
57886
58050
|
if (!t)
|
|
@@ -57984,11 +58148,11 @@ init_framework_security();
|
|
|
57984
58148
|
// src/variant-scan.ts
|
|
57985
58149
|
init_scanner();
|
|
57986
58150
|
init_complex_bugs();
|
|
57987
|
-
import { readFileSync as
|
|
58151
|
+
import { readFileSync as readFileSync23 } from "node:fs";
|
|
57988
58152
|
|
|
57989
58153
|
// src/cross-file.ts
|
|
57990
58154
|
init_scanner();
|
|
57991
|
-
import { readFileSync as
|
|
58155
|
+
import { readFileSync as readFileSync22 } from "node:fs";
|
|
57992
58156
|
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)/;
|
|
57993
58157
|
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*\(/;
|
|
57994
58158
|
var ROLE_META_RE = /update_user_meta\s*\(\s*[^,]+,\s*['"](wp_capabilities|role|roles|capabilities|wp_user_level)['"]/;
|
|
@@ -58040,7 +58204,7 @@ function detectCrossFilePrivesc(root) {
|
|
|
58040
58204
|
for (const file of files) {
|
|
58041
58205
|
let code;
|
|
58042
58206
|
try {
|
|
58043
|
-
code = stripComments(
|
|
58207
|
+
code = stripComments(readFileSync22(file, "utf8"));
|
|
58044
58208
|
} catch {
|
|
58045
58209
|
continue;
|
|
58046
58210
|
}
|
|
@@ -58081,7 +58245,7 @@ function detectCrossFilePrivesc(root) {
|
|
|
58081
58245
|
for (const file of files) {
|
|
58082
58246
|
let code;
|
|
58083
58247
|
try {
|
|
58084
|
-
code = stripComments(
|
|
58248
|
+
code = stripComments(readFileSync22(file, "utf8"));
|
|
58085
58249
|
} catch {
|
|
58086
58250
|
continue;
|
|
58087
58251
|
}
|
|
@@ -58104,7 +58268,7 @@ function detectCrossFilePrivesc(root) {
|
|
|
58104
58268
|
for (const file of files) {
|
|
58105
58269
|
let code;
|
|
58106
58270
|
try {
|
|
58107
|
-
code = stripComments(
|
|
58271
|
+
code = stripComments(readFileSync22(file, "utf8"));
|
|
58108
58272
|
} catch {
|
|
58109
58273
|
continue;
|
|
58110
58274
|
}
|
|
@@ -58219,7 +58383,7 @@ function variantScan(root, opts = {}) {
|
|
|
58219
58383
|
for (const file of files) {
|
|
58220
58384
|
let code;
|
|
58221
58385
|
try {
|
|
58222
|
-
code =
|
|
58386
|
+
code = readFileSync23(file, "utf8");
|
|
58223
58387
|
} catch {
|
|
58224
58388
|
continue;
|
|
58225
58389
|
}
|
|
@@ -58879,17 +59043,17 @@ function analyzeJwt(token, opts = {}) {
|
|
|
58879
59043
|
}
|
|
58880
59044
|
|
|
58881
59045
|
// src/enterprise-benchmark.ts
|
|
58882
|
-
import { existsSync as existsSync11, readFileSync as
|
|
58883
|
-
import { join as
|
|
59046
|
+
import { existsSync as existsSync11, readFileSync as readFileSync24, readdirSync as readdirSync6, statSync as statSync3 } from "node:fs";
|
|
59047
|
+
import { join as join21, resolve } from "node:path";
|
|
58884
59048
|
init_complex_bugs();
|
|
58885
59049
|
var ROOT6 = resolve(process.cwd(), "bench", "enterprise");
|
|
58886
59050
|
var ENTERPRISE_FIXTURES = [
|
|
58887
|
-
{ id: "php-laravel", dir:
|
|
58888
|
-
{ id: "js-express", dir:
|
|
58889
|
-
{ id: "py-django", dir:
|
|
58890
|
-
{ id: "java-spring", dir:
|
|
58891
|
-
{ id: "wp-batch-route", dir:
|
|
58892
|
-
{ id: "php-complex", dir:
|
|
59051
|
+
{ id: "php-laravel", dir: join21(ROOT6, "php-laravel"), expected_vulns: 4 },
|
|
59052
|
+
{ id: "js-express", dir: join21(ROOT6, "js-express"), expected_vulns: 2 },
|
|
59053
|
+
{ id: "py-django", dir: join21(ROOT6, "py-django"), expected_vulns: 2 },
|
|
59054
|
+
{ id: "java-spring", dir: join21(ROOT6, "java-spring"), expected_vulns: 2 },
|
|
59055
|
+
{ id: "wp-batch-route", dir: join21(ROOT6, "wp-batch-route"), expected_vulns: 3 },
|
|
59056
|
+
{ id: "php-complex", dir: join21(ROOT6, "php-complex"), expected_vulns: 4 }
|
|
58893
59057
|
];
|
|
58894
59058
|
function sourceFiles(root) {
|
|
58895
59059
|
const out = [];
|
|
@@ -58901,7 +59065,7 @@ function sourceFiles(root) {
|
|
|
58901
59065
|
return;
|
|
58902
59066
|
}
|
|
58903
59067
|
for (const e of entries) {
|
|
58904
|
-
const p =
|
|
59068
|
+
const p = join21(dir, e);
|
|
58905
59069
|
let st;
|
|
58906
59070
|
try {
|
|
58907
59071
|
st = statSync3(p);
|
|
@@ -58922,7 +59086,7 @@ function detectFixture(dir) {
|
|
|
58922
59086
|
for (const f of sourceFiles(dir)) {
|
|
58923
59087
|
let code;
|
|
58924
59088
|
try {
|
|
58925
|
-
code =
|
|
59089
|
+
code = readFileSync24(f, "utf8");
|
|
58926
59090
|
} catch {
|
|
58927
59091
|
continue;
|
|
58928
59092
|
}
|
|
@@ -59542,6 +59706,13 @@ ${statusLine}` : statusLine },
|
|
|
59542
59706
|
}, async () => {
|
|
59543
59707
|
return { content: [{ type: "text", text: JSON.stringify(runVerificationHarness()) }] };
|
|
59544
59708
|
});
|
|
59709
|
+
server.registerTool("scan_variants", {
|
|
59710
|
+
title: "Variant corpus coverage scan",
|
|
59711
|
+
description: "VERIFY: sweep every real-world code shape (intelligence/variants.json) against its class's detector and report per-class coverage. A shape that does not fire is a coverage gap (false negative) — use this to find detector blind spots, then fix the detector.",
|
|
59712
|
+
inputSchema: {}
|
|
59713
|
+
}, async () => {
|
|
59714
|
+
return { content: [{ type: "text", text: JSON.stringify(scanVariants()) }] };
|
|
59715
|
+
});
|
|
59545
59716
|
server.registerTool("fofa_search", {
|
|
59546
59717
|
title: "FOFA asset search",
|
|
59547
59718
|
description: "STRIKE: search the FOFA asset index (needs FOFA_EMAIL + FOFA_KEY).",
|
|
@@ -59926,7 +60097,7 @@ ${statusLine}` : statusLine },
|
|
|
59926
60097
|
let src = code;
|
|
59927
60098
|
if (!src && path) {
|
|
59928
60099
|
try {
|
|
59929
|
-
src =
|
|
60100
|
+
src = readFileSync26(path, "utf8");
|
|
59930
60101
|
} catch {
|
|
59931
60102
|
return { content: [{ type: "text", text: JSON.stringify({ error: "unreadable path" }) }] };
|
|
59932
60103
|
}
|
|
@@ -60544,7 +60715,7 @@ ${statusLine}` : statusLine },
|
|
|
60544
60715
|
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.",
|
|
60545
60716
|
inputSchema: { path: string2().describe("Source file path (PHP)") }
|
|
60546
60717
|
}, async ({ path }) => {
|
|
60547
|
-
const code =
|
|
60718
|
+
const code = readFileSync26(path, "utf8");
|
|
60548
60719
|
const findings = detectRouteConfusion(code, path);
|
|
60549
60720
|
return {
|
|
60550
60721
|
content: [{
|
|
@@ -60558,7 +60729,7 @@ ${statusLine}` : statusLine },
|
|
|
60558
60729
|
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).",
|
|
60559
60730
|
inputSchema: { path: string2().describe("Source file path") }
|
|
60560
60731
|
}, async ({ path }) => {
|
|
60561
|
-
const code =
|
|
60732
|
+
const code = readFileSync26(path, "utf8");
|
|
60562
60733
|
const findings = detectComplexBugs(code, path);
|
|
60563
60734
|
return {
|
|
60564
60735
|
content: [{
|
|
@@ -60644,7 +60815,7 @@ ${statusLine}` : statusLine },
|
|
|
60644
60815
|
let lang = language;
|
|
60645
60816
|
if (path && !code) {
|
|
60646
60817
|
try {
|
|
60647
|
-
src =
|
|
60818
|
+
src = readFileSync26(path, "utf8");
|
|
60648
60819
|
} catch {
|
|
60649
60820
|
return { content: [{ type: "text", text: JSON.stringify({ error: `cannot read ${path}` }) }] };
|
|
60650
60821
|
}
|
|
@@ -60885,15 +61056,15 @@ async function serve() {
|
|
|
60885
61056
|
|
|
60886
61057
|
// src/index.ts
|
|
60887
61058
|
init_cli();
|
|
60888
|
-
import { readFileSync as
|
|
60889
|
-
import { join as
|
|
60890
|
-
import { fileURLToPath as
|
|
60891
|
-
var ROOT11 =
|
|
61059
|
+
import { readFileSync as readFileSync30, existsSync as existsSync14 } from "node:fs";
|
|
61060
|
+
import { join as join26 } from "node:path";
|
|
61061
|
+
import { fileURLToPath as fileURLToPath16 } from "node:url";
|
|
61062
|
+
var ROOT11 = join26(fileURLToPath16(new URL(".", import.meta.url)), "..");
|
|
60892
61063
|
function readVersion() {
|
|
60893
61064
|
try {
|
|
60894
|
-
const p =
|
|
61065
|
+
const p = join26(ROOT11, "package.json");
|
|
60895
61066
|
if (existsSync14(p))
|
|
60896
|
-
return JSON.parse(
|
|
61067
|
+
return JSON.parse(readFileSync30(p, "utf8")).version ?? "1.0.0";
|
|
60897
61068
|
} catch {}
|
|
60898
61069
|
return "1.0.0";
|
|
60899
61070
|
}
|
|
@@ -60964,9 +61135,13 @@ async function main() {
|
|
|
60964
61135
|
}
|
|
60965
61136
|
if (args[0] === "verify") {
|
|
60966
61137
|
await Promise.resolve().then(() => init_verify_harness());
|
|
61138
|
+
await Promise.resolve().then(() => init_variants());
|
|
60967
61139
|
console.log(verificationReportText());
|
|
61140
|
+
console.log(`
|
|
61141
|
+
` + variantCoverageText());
|
|
60968
61142
|
const r = runVerificationHarness();
|
|
60969
|
-
|
|
61143
|
+
const v = scanVariants();
|
|
61144
|
+
if (r.failed > 0 || v.missed > 0)
|
|
60970
61145
|
process.exit(1);
|
|
60971
61146
|
return;
|
|
60972
61147
|
}
|