muaddib-scanner 2.11.81 → 2.11.82
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/package.json
CHANGED
|
@@ -751,6 +751,75 @@ function mcpServerEnvAccess(result, meta) {
|
|
|
751
751
|
return true;
|
|
752
752
|
}
|
|
753
753
|
|
|
754
|
+
// ============================================================================
|
|
755
|
+
// Feature 15 — mcp_server_benign_lifecycle (AUDIT 2, 2026-06)
|
|
756
|
+
// ============================================================================
|
|
757
|
+
//
|
|
758
|
+
// Like F9 (mcpServerEnvAccess) but TOLERATES a benign install lifecycle. F9
|
|
759
|
+
// vetoes on ANY preinstall/install/postinstall (its C3), which makes it
|
|
760
|
+
// inoperative for the ~77% of legitimate MCP installers that ship a build/setup
|
|
761
|
+
// hook (`husky install`, `node build.js`, `tsc`). Those packages stack
|
|
762
|
+
// mcp_config_injection (CRIT) + suspicious_dataflow (CRIT, env→first-party POST)
|
|
763
|
+
// + env_access (HIGH) + lifecycle_script (MEDIUM) and score ~150 on `muaddib
|
|
764
|
+
// scan` — the recurring @recapp/mcp-style false positives in the daily report.
|
|
765
|
+
//
|
|
766
|
+
// F15 instead allows a lifecycle that is only flagged as a plain MEDIUM/LOW
|
|
767
|
+
// `lifecycle_script`, and vetoes the moment the lifecycle does anything
|
|
768
|
+
// malicious. Ground-truth safety (verified by replay before/after):
|
|
769
|
+
// GT-060 mcp-config-inject → vetoed by lifecycle_file_exec (malicious postinstall)
|
|
770
|
+
// GT-088 defi-threat-scanner → vetoed by HARD exfil (suspicious_domain) + cred files
|
|
771
|
+
// GT-066 ai-agent-exploit → never emits mcp_config_injection (C2 excludes it)
|
|
772
|
+
// GT-097 / GT-099 → HARD exfil / not an mcp_config_injection JS package
|
|
773
|
+
// Same cap (30 = MEDIUM) and identity/provider-key machinery as F9.
|
|
774
|
+
const F15_LIFECYCLE_MALICE_TYPES = new Set([
|
|
775
|
+
'lifecycle_file_exec', // postinstall executes a file containing HIGH/CRIT threats
|
|
776
|
+
'lifecycle_dataflow', // install-time credential read + network send (compound)
|
|
777
|
+
'lifecycle_shell_pipe', // curl | sh during install
|
|
778
|
+
'lifecycle_missing_script', // phantom install script (payload injected later)
|
|
779
|
+
'intent_credential_exfil', // multi-file credential→network intent
|
|
780
|
+
'intent_command_exfil',
|
|
781
|
+
'detached_credential_exfil',
|
|
782
|
+
'staged_payload'
|
|
783
|
+
]);
|
|
784
|
+
|
|
785
|
+
function mcpServerBenignLifecycle(result, meta) {
|
|
786
|
+
// C1 — MCP identity (same as F9)
|
|
787
|
+
if (!_f9HasMcpIdentity(meta)) return false;
|
|
788
|
+
const threats = (result && result.threats) || [];
|
|
789
|
+
if (threats.length === 0) return false;
|
|
790
|
+
// C2 — mcp_config_injection present (proves real MCP work, not just a name claim)
|
|
791
|
+
if (!threats.some(t => t.type === 'mcp_config_injection')) return false;
|
|
792
|
+
// C3' (relaxed) — a lifecycle MAY exist, but it must be benign: no malicious
|
|
793
|
+
// lifecycle compound, and a plain lifecycle_script (if any) must not itself be
|
|
794
|
+
// HIGH/CRITICAL (a benign husky/build hook is MEDIUM/LOW).
|
|
795
|
+
for (const t of threats) {
|
|
796
|
+
if (F15_LIFECYCLE_MALICE_TYPES.has(t.type)) return false;
|
|
797
|
+
if (t.type === 'lifecycle_script' && (t.severity === 'HIGH' || t.severity === 'CRITICAL')) return false;
|
|
798
|
+
}
|
|
799
|
+
// C4 — env_access / credential threats cite ONLY known provider keys or infra
|
|
800
|
+
// vars; never credential file paths (same machinery as F9).
|
|
801
|
+
for (const t of threats) {
|
|
802
|
+
if (t.type !== 'env_access' && t.type !== 'credential_regex_harvest' &&
|
|
803
|
+
t.type !== 'env_charcode_reconstruction') continue;
|
|
804
|
+
const msg = String(t.message || '');
|
|
805
|
+
if (F9_CREDENTIAL_FILE_RE.test(msg)) return false;
|
|
806
|
+
const candidates = msg.match(/\b[A-Z][A-Z0-9_]{2,}\b/g);
|
|
807
|
+
if (!candidates) continue;
|
|
808
|
+
for (const v of candidates) {
|
|
809
|
+
if (KNOWN_PROVIDER_KEYS_LITERAL.has(v)) continue;
|
|
810
|
+
if (PROVIDER_KEY_SUFFIX_RE.test(v)) continue;
|
|
811
|
+
if (F9_INFRA_KEYS.has(v)) continue;
|
|
812
|
+
return false;
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
// C5 — no HARD third-party exfil capability (SOFT suspicious_dataflow to a
|
|
816
|
+
// first-party endpoint is intrinsic to MCP installers — see F9/F14)
|
|
817
|
+
for (const t of threats) {
|
|
818
|
+
if (HARD_EXFIL_TYPES.has(t.type)) return false;
|
|
819
|
+
}
|
|
820
|
+
return true;
|
|
821
|
+
}
|
|
822
|
+
|
|
754
823
|
// ============================================================================
|
|
755
824
|
// Feature 10 — vendor_cli_sdk (v2.11.23, audit week3 cluster, 96 FP)
|
|
756
825
|
// ============================================================================
|
|
@@ -1426,6 +1495,7 @@ module.exports = {
|
|
|
1426
1495
|
placeholderAntiDepConfusion,
|
|
1427
1496
|
installScriptNoNetworkEgress,
|
|
1428
1497
|
mcpServerEnvAccess,
|
|
1498
|
+
mcpServerBenignLifecycle,
|
|
1429
1499
|
vendorCliSdk,
|
|
1430
1500
|
aiAgentBot,
|
|
1431
1501
|
vendorMinifiedBundle,
|
package/src/scoring.js
CHANGED
|
@@ -1506,6 +1506,7 @@ const {
|
|
|
1506
1506
|
obfuscationWithoutVector,
|
|
1507
1507
|
placeholderAntiDepConfusion,
|
|
1508
1508
|
mcpServerEnvAccess,
|
|
1509
|
+
mcpServerBenignLifecycle,
|
|
1509
1510
|
vendorCliSdk,
|
|
1510
1511
|
aiAgentBot,
|
|
1511
1512
|
vendorMinifiedBundle,
|
|
@@ -1559,6 +1560,13 @@ function applyContextualFPCaps(result, pkgMeta) {
|
|
|
1559
1560
|
if (mcpServerEnvAccess(result, meta)) {
|
|
1560
1561
|
applied.push({ feature: 'mcp_server_env_access', cap: 30 });
|
|
1561
1562
|
}
|
|
1563
|
+
// F15: legit MCP installer/server WITH a benign install lifecycle (AUDIT 2) →
|
|
1564
|
+
// MAX 30. Extends F9 to the ~77% of MCP installers that ship a build/setup hook
|
|
1565
|
+
// (husky install, node build.js). Vetoes on malicious lifecycle (lifecycle_file_exec
|
|
1566
|
+
// etc.), HARD exfil, or credential-file access — so GT MCP malware stays uncapped.
|
|
1567
|
+
if (mcpServerBenignLifecycle(result, meta)) {
|
|
1568
|
+
applied.push({ feature: 'mcp_server_benign_lifecycle', cap: 30 });
|
|
1569
|
+
}
|
|
1562
1570
|
// F2: binary installer from GitHub Releases → MAX 35
|
|
1563
1571
|
if (installUrlGithubReleases(result)) {
|
|
1564
1572
|
applied.push({ feature: 'install_url_github_releases', cap: 35 });
|