muaddib-scanner 2.11.87 → 2.11.89
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
|
@@ -1090,7 +1090,11 @@ const CASCADE_TYPES = new Set([
|
|
|
1090
1090
|
'proxy_data_intercept', // MUADDIB-AST-043
|
|
1091
1091
|
'remote_code_load', // MUADDIB-AST-040
|
|
1092
1092
|
'obfuscation_detected', // src/scanner/obfuscation.js
|
|
1093
|
-
'js_obfuscation_pattern'
|
|
1093
|
+
'js_obfuscation_pattern',
|
|
1094
|
+
// FPR audit 2026-06: these two also fire on legitimate minified vendor bundles
|
|
1095
|
+
// (string-rewrite tables, base64 blobs) and were escaping the bundle cap.
|
|
1096
|
+
'string_mutation_obfuscation',
|
|
1097
|
+
'high_entropy_string'
|
|
1094
1098
|
]);
|
|
1095
1099
|
const CASCADE_MIN_TYPES = 3;
|
|
1096
1100
|
const CASCADE_MIN_FILE_BYTES = 20 * 1024;
|
package/src/monitor/queue.js
CHANGED
|
@@ -150,10 +150,14 @@ const BURST_PREALERT_MIN_VERSIONS = (() => {
|
|
|
150
150
|
const n = parseInt(process.env.MUADDIB_BURST_MIN_VERSIONS, 10);
|
|
151
151
|
return Number.isFinite(n) && n >= 2 ? n : 10;
|
|
152
152
|
})();
|
|
153
|
-
//
|
|
154
|
-
//
|
|
155
|
-
|
|
153
|
+
// Burst ping throttle (FPR/notif audit 2026-06): name -> last burst-alert timestamp.
|
|
154
|
+
// Was a lifetime Set (dedup once per process), which both (a) silenced a genuine
|
|
155
|
+
// re-burst days later and (b) on a process that runs for weeks accumulated spam from
|
|
156
|
+
// every monorepo/CI nightly that re-bursts. Now a 24h-cooldown Map: one alert per
|
|
157
|
+
// package per day max. Bounded — cleared at the cap so it can never grow without limit.
|
|
158
|
+
const _burstAlerted = new Map();
|
|
156
159
|
const BURST_ALERTED_MAX = 20_000;
|
|
160
|
+
const BURST_ALERT_COOLDOWN_MS = 24 * 60 * 60 * 1000; // 24h
|
|
157
161
|
|
|
158
162
|
// Stage 3 — sandbox gate. Static-score threshold below which T1b/T2 packages
|
|
159
163
|
// are NOT sandboxed (static result alone is authoritative). Tightens the prior
|
|
@@ -1530,9 +1534,22 @@ async function resolveTarballAndScan(item, stats, dailyAlerts, recentlyScanned,
|
|
|
1530
1534
|
const isBurst = burstCount >= BURST_PREALERT_MIN_VERSIONS;
|
|
1531
1535
|
if (isBurst) {
|
|
1532
1536
|
item.isBurst = true;
|
|
1533
|
-
|
|
1537
|
+
// Anti-flood (notification only — the burst versions are STILL queued and scanned
|
|
1538
|
+
// below regardless; muting the heads-up never weakens detection):
|
|
1539
|
+
// 1) Established packages (mature + many versions) bursting are monorepo / CI
|
|
1540
|
+
// nightly churn, not the Shai-Hulud account-takeover signal (that is a NEW /
|
|
1541
|
+
// low-reputation package suddenly bursting). A real takeover of an established
|
|
1542
|
+
// package is still caught by the per-version scan + the atoSignal above.
|
|
1543
|
+
// 2) 24h cooldown per package so a package re-bursting all day pings at most once.
|
|
1544
|
+
const _np = item._npmInfo || npmInfo || {};
|
|
1545
|
+
const _established = Number.isFinite(_np.age_days) && _np.age_days > 730 &&
|
|
1546
|
+
Number.isFinite(_np.version_count) && _np.version_count > 100;
|
|
1547
|
+
const _now = Date.now();
|
|
1548
|
+
const _last = _burstAlerted.get(item.name);
|
|
1549
|
+
const _onCooldown = _last && (_now - _last) < BURST_ALERT_COOLDOWN_MS;
|
|
1550
|
+
if (!_established && !_onCooldown) {
|
|
1534
1551
|
if (_burstAlerted.size >= BURST_ALERTED_MAX) _burstAlerted.clear();
|
|
1535
|
-
_burstAlerted.
|
|
1552
|
+
_burstAlerted.set(item.name, _now);
|
|
1536
1553
|
stats.burstPreAlerts = (stats.burstPreAlerts || 0) + 1;
|
|
1537
1554
|
console.log(`[MONITOR] BURST PRE-ALERT: ${item.name} — ${burstCount} versions in the recent window`);
|
|
1538
1555
|
sendBurstPreAlert(item.name, burstCount, item.ecosystem).catch(err => {
|
package/src/rules/index.js
CHANGED
|
@@ -3348,7 +3348,7 @@ const RULES = {
|
|
|
3348
3348
|
trusted_new_dependency: {
|
|
3349
3349
|
id: 'MUADDIB-TRUSTED-002',
|
|
3350
3350
|
name: 'Trusted Package Added New Dependency',
|
|
3351
|
-
severity: '
|
|
3351
|
+
severity: 'MEDIUM',
|
|
3352
3352
|
confidence: 'medium',
|
|
3353
3353
|
domain: 'malware',
|
|
3354
3354
|
description: 'Un package TRUSTED (>50k downloads/semaine) a ajoute une nouvelle dependance connue (>7 jours) dans un bump de version — changement de surface d\'attaque a verifier.',
|
|
@@ -154,7 +154,12 @@ async function checkDepDiff(name, newVersion) {
|
|
|
154
154
|
const ageDays = Math.floor(ageMs / 86400000);
|
|
155
155
|
findings.push({
|
|
156
156
|
type: 'trusted_new_dependency',
|
|
157
|
-
|
|
157
|
+
// FPR audit 2026-06: a trusted package adding an ESTABLISHED (>=7d) dependency
|
|
158
|
+
// is an audit/surface-change signal ("a verifier"), not malice — it produced
|
|
159
|
+
// ~169 FPs. Downgraded HIGH->MEDIUM so it no longer alone meets the tier-1b
|
|
160
|
+
// corroboration bar. The real account-takeover case (new/unknown dep <7d) is
|
|
161
|
+
// the separate CRITICAL `trusted_new_unknown_dependency` (HC type) and is intact.
|
|
162
|
+
severity: 'MEDIUM',
|
|
158
163
|
confidence: 'medium',
|
|
159
164
|
file: 'package.json',
|
|
160
165
|
message: `TRUSTED package ${name} added new dependency ${dep} (age: ${ageDays}d) in version ${prevVersion} → ${newVersion}`,
|