muaddib-scanner 2.10.85 → 2.10.86
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 +1 -1
- package/src/monitor/queue.js +22 -5
- package/src/sandbox/index.js +5 -2
- package/src/shared/http-limiter.js +1 -1
package/package.json
CHANGED
package/src/monitor/queue.js
CHANGED
|
@@ -285,6 +285,16 @@ async function scanPackage(name, version, ecosystem, tarballUrl, registryMeta, s
|
|
|
285
285
|
const cacheTrigger = meta._cacheTrigger || null;
|
|
286
286
|
|
|
287
287
|
try {
|
|
288
|
+
// Pre-download size check: reject packages known to exceed MAX_TARBALL_SIZE
|
|
289
|
+
// from registry metadata, without wasting a download + 300s timeout.
|
|
290
|
+
// unpackedSize is available from getNpmLatestTarball() after lazy resolution.
|
|
291
|
+
const metaSize = meta.unpackedSize || 0;
|
|
292
|
+
if (metaSize > MAX_TARBALL_SIZE) {
|
|
293
|
+
console.log(`[MONITOR] SIZE_REJECT: ${name}@${version} — metadata size ${(metaSize / 1024 / 1024).toFixed(1)}MB exceeds ${(MAX_TARBALL_SIZE / 1024 / 1024).toFixed(0)}MB limit (skipped without download)`);
|
|
294
|
+
stats.scanned++;
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
|
|
288
298
|
const tgzPath = path.join(tmpDir, 'package.tar.gz');
|
|
289
299
|
|
|
290
300
|
// Layer 3: Check tarball cache before downloading
|
|
@@ -729,7 +739,10 @@ async function scanPackage(name, version, ecosystem, tarballUrl, registryMeta, s
|
|
|
729
739
|
const canary = isCanaryEnabled();
|
|
730
740
|
const reason = tier === 2 ? ' (T2, queue low)' : tier === '1b' ? ' (T1b, conditional)' : '';
|
|
731
741
|
console.log(`[MONITOR] SANDBOX${reason}: launching for ${name}@${version}${canary ? ' (canary: on)' : ''}...`);
|
|
732
|
-
|
|
742
|
+
// T1a: 3 runs (time bomb detection via libfaketime — mandatory for high-confidence threats)
|
|
743
|
+
// T1b/T2: 1 run (270s→90s — time bombs are rare, throughput matters more under load)
|
|
744
|
+
const maxRuns = tier === '1a' ? undefined : 1;
|
|
745
|
+
sandboxResult = await runSandbox(name, { canary, maxRuns });
|
|
733
746
|
console.log(`[MONITOR] SANDBOX: ${name}@${version} → score: ${sandboxResult.score}, severity: ${sandboxResult.severity}`);
|
|
734
747
|
|
|
735
748
|
// Check for canary exfiltration findings and send dedicated alert
|
|
@@ -1153,11 +1166,13 @@ async function resolveTarballAndScan(item, stats, dailyAlerts, recentlyScanned,
|
|
|
1153
1166
|
let publishResult = null;
|
|
1154
1167
|
let maintainerResult = null;
|
|
1155
1168
|
|
|
1156
|
-
|
|
1169
|
+
const TEMPORAL_LOAD_SHED_THRESHOLD = 2000;
|
|
1170
|
+
const skipTemporal = item.fastTrack || scanQueue.length > TEMPORAL_LOAD_SHED_THRESHOLD;
|
|
1171
|
+
if (item.ecosystem === 'npm' && !skipTemporal) {
|
|
1157
1172
|
// Run all 4 temporal checks in parallel — each is independent.
|
|
1158
|
-
//
|
|
1159
|
-
//
|
|
1160
|
-
//
|
|
1173
|
+
// AST diff alone consumes 5 HTTP semaphore slots per package (2 tarball downloads + 3 metadata).
|
|
1174
|
+
// With 16 workers that's 80 slot requests for 10 slots → workers blocked 80% of the time.
|
|
1175
|
+
// Load-shed when queue > 2000: temporal analysis is a luxury during catch-up.
|
|
1161
1176
|
const [tempRes, astRes, pubRes, maintRes] = await Promise.allSettled([
|
|
1162
1177
|
runTemporalCheck(item.name, dailyAlerts),
|
|
1163
1178
|
runTemporalAstCheck(item.name, dailyAlerts),
|
|
@@ -1168,6 +1183,8 @@ async function resolveTarballAndScan(item, stats, dailyAlerts, recentlyScanned,
|
|
|
1168
1183
|
astResult = astRes.status === 'fulfilled' ? astRes.value : null;
|
|
1169
1184
|
publishResult = pubRes.status === 'fulfilled' ? pubRes.value : null;
|
|
1170
1185
|
maintainerResult = maintRes.status === 'fulfilled' ? maintRes.value : null;
|
|
1186
|
+
} else if (skipTemporal && item.ecosystem === 'npm' && !item.fastTrack) {
|
|
1187
|
+
console.log(`[MONITOR] TEMPORAL LOAD-SHED: ${item.name}@${item.version} (queue=${scanQueue.length} > ${TEMPORAL_LOAD_SHED_THRESHOLD})`);
|
|
1171
1188
|
}
|
|
1172
1189
|
|
|
1173
1190
|
// Abort check: if timeout fired during temporal checks, skip the expensive scan
|
package/src/sandbox/index.js
CHANGED
|
@@ -641,12 +641,15 @@ async function runSandbox(packageName, options = {}) {
|
|
|
641
641
|
try {
|
|
642
642
|
const runtimeLabel = useGvisor ? 'gvisor' : 'docker';
|
|
643
643
|
const slotInfo = skipSem ? 'deferred-slot' : `${_sandboxSemaphore.active}/${SANDBOX_CONCURRENCY_MAX}`;
|
|
644
|
-
|
|
644
|
+
// maxRuns: cap number of time-offset runs. Default: all TIME_OFFSETS (3 runs).
|
|
645
|
+
// T1b/T2 use maxRuns=1 to reduce 270s→90s — time bomb detection is a luxury under load.
|
|
646
|
+
const effectiveRuns = Math.min(options.maxRuns || TIME_OFFSETS.length, TIME_OFFSETS.length);
|
|
647
|
+
console.log(`[SANDBOX] Analyzing "${displayName}" in isolated container (mode: ${mode}, runtime: ${runtimeLabel}${canaryEnabled ? ', canary: on' : ''}${local ? ', local' : ''}, runs: ${effectiveRuns}, slots: ${slotInfo})...`);
|
|
645
648
|
|
|
646
649
|
const allRuns = [];
|
|
647
650
|
let bestResult = cleanResult;
|
|
648
651
|
|
|
649
|
-
for (let i = 0; i <
|
|
652
|
+
for (let i = 0; i < effectiveRuns; i++) {
|
|
650
653
|
const { offset, label } = TIME_OFFSETS[i];
|
|
651
654
|
console.log(`[SANDBOX] Run ${i + 1}/${TIME_OFFSETS.length} (${label})...`);
|
|
652
655
|
|