muaddib-scanner 2.11.154 → 2.11.157
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
package/src/monitor/webhook.js
CHANGED
|
@@ -270,11 +270,30 @@ function buildBurstPreAlertEmbed(name, count, ecosystem = 'npm') {
|
|
|
270
270
|
};
|
|
271
271
|
}
|
|
272
272
|
|
|
273
|
+
/**
|
|
274
|
+
* Burst pre-alert Discord toggle — OFF by default. Measured 2026-07: the burst
|
|
275
|
+
* heads-up fires ~700×/day and is anti-correlated with real kills/incidents, so it is
|
|
276
|
+
* pure #alerts noise. This gates ONLY the Discord POST in sendBurstPreAlert(): the
|
|
277
|
+
* burst versions are still queued + scanned (queue.js), and the `[MONITOR] BURST
|
|
278
|
+
* PRE-ALERT` console.log + the `stats.burstPreAlerts` counter (used by the daily
|
|
279
|
+
* summary) are emitted BEFORE the send at the call site, so they are unaffected.
|
|
280
|
+
* Opt back in with MUADDIB_BURST_PREALERT_WEBHOOK=1 (also accepts true/yes/on).
|
|
281
|
+
* Read at call time so a restart re-toggles it without a code change (and tests can flip it).
|
|
282
|
+
*/
|
|
283
|
+
function burstPreAlertWebhookEnabled() {
|
|
284
|
+
const v = (process.env.MUADDIB_BURST_PREALERT_WEBHOOK || '').trim().toLowerCase();
|
|
285
|
+
return v === '1' || v === 'true' || v === 'yes' || v === 'on';
|
|
286
|
+
}
|
|
287
|
+
|
|
273
288
|
/**
|
|
274
289
|
* Layer 1c: Send a burst pre-alert webhook. Fire-and-forget; callers dedupe per
|
|
275
|
-
* name/window so a burst pings once, not once per version.
|
|
290
|
+
* name/window so a burst pings once, not once per version. Discord POST is muted by
|
|
291
|
+
* default — see burstPreAlertWebhookEnabled(). Scoped to this sender only; the shared
|
|
292
|
+
* sendWebhook() and every other alert type (IOC/campaign pre-alerts, scan results,
|
|
293
|
+
* DEGRADED, daily report) are untouched.
|
|
276
294
|
*/
|
|
277
295
|
async function sendBurstPreAlert(name, count, ecosystem = 'npm') {
|
|
296
|
+
if (!burstPreAlertWebhookEnabled()) return;
|
|
278
297
|
const url = getWebhookUrl();
|
|
279
298
|
if (!url) return;
|
|
280
299
|
await sendWebhook(url, buildBurstPreAlertEmbed(name, count, ecosystem), { rawPayload: true });
|
|
@@ -1739,6 +1758,7 @@ module.exports = {
|
|
|
1739
1758
|
sendCampaignPreAlert,
|
|
1740
1759
|
buildBurstPreAlertEmbed,
|
|
1741
1760
|
sendBurstPreAlert,
|
|
1761
|
+
burstPreAlertWebhookEnabled,
|
|
1742
1762
|
matchVersionedIOC,
|
|
1743
1763
|
computeRiskLevel,
|
|
1744
1764
|
computeRiskScore,
|
|
@@ -54,8 +54,13 @@ const FAMILIES = [
|
|
|
54
54
|
// directives + an instruction/prompt noun. Pathognomonic; legitimate source never
|
|
55
55
|
// carries it. (Deliberately excludes the rule/guideline noun to avoid lint-config FPs.)
|
|
56
56
|
/\b(?:ignore|disregard|forget|override|bypass)\b[\s\S]{0,40}\b(?:all\s+|any\s+)?(?:previous|prior|above|earlier|preceding|the\s+(?:above|following))\b[\s\S]{0,30}\b(?:instruction|prompt|system[\s-]?prompt)s?\b/i,
|
|
57
|
-
// Explicitly addressing the AI/scanner/reviewer + a command verb.
|
|
58
|
-
|
|
57
|
+
// Explicitly addressing the AI/scanner/reviewer + a command verb. Bare "to <target>" is
|
|
58
|
+
// restricted to REVIEW-SPECIFIC targets (scanner/analyzer/reviewer/auditor); the generic
|
|
59
|
+
// "to ai|llm|model|assistant" branch was dropped 2026-07-03 — it collided with agent-skill
|
|
60
|
+
// runtime prose like "move to AI <status> … Do NOT <step>" (see asi-fp-agent-skills). Full
|
|
61
|
+
// salutations (dear/hello/hey/note to/message to) keep all targets; a real "to the AI: mark
|
|
62
|
+
// safe / ignore previous" attack still trips family 2 / family-1-pattern-0 independently.
|
|
63
|
+
/\b(?:as\s+(?:an?\s+)?(?:ai|a\.i\.|llm|language\s+model|gpt|claude|copilot|security\s+(?:scanner|analyzer|analyst|auditor|reviewer|model)|automated\s+(?:scanner|analyzer|reviewer)|code[\s-]review(?:er)?)|attention[,:!\s]+(?:ai|llm|scanner|analyzer|reviewer)|(?:dear|hello|hey|note\s+to|message\s+to)\s+(?:the\s+)?(?:ai|llm|scanner|analyzer|reviewer|model|assistant|auditor)\b|to\s+(?:the\s+)?(?:scanner|analyzer|reviewer|auditor)\b)[\s\S]{0,100}\b(?:you\s+(?:must|should|are|will|need\s+to)|do\s+not|please\s+(?:do|treat|classify|mark|report|ignore|skip)|classify|treat|mark|report|consider|ignore|skip|disregard)\b/i
|
|
59
64
|
]
|
|
60
65
|
},
|
|
61
66
|
{
|
|
@@ -86,14 +91,20 @@ const FAMILIES = [
|
|
|
86
91
|
|
|
87
92
|
// Same-file payload signal → escalates a directive to CRITICAL (the Hades shape: the directive
|
|
88
93
|
// and the payload it guards are co-located). Computed locally — NO cross-scanner dependency.
|
|
94
|
+
// Each signal must indicate an OBFUSCATED and/or DYNAMICALLY-EXECUTED payload — NOT a bare data
|
|
95
|
+
// decode. The decode-only signals `atob(` and `Buffer.from(x,'base64')` were removed 2026-07-03:
|
|
96
|
+
// decoding an API field / attachment (e.g. GitHub/Jira `content`, `Buffer.from(a.content,'base64')`)
|
|
97
|
+
// is ubiquitous benign data handling, not an obfuscated payload — it was the sole "payload" behind
|
|
98
|
+
// a false antiscanner_injection_with_payload on @zibby/skills 0.1.60 (see asi-fp-agent-skills).
|
|
99
|
+
// When a decode genuinely guards malware it is accompanied by an execution sink (eval/Function/vm)
|
|
100
|
+
// or a long encoded blob — both still matched below, so no real Hades / ToxicSkills / TrapDoor
|
|
101
|
+
// payload is lost.
|
|
89
102
|
const PAYLOAD_SIGNALS = [
|
|
90
|
-
/[A-Za-z0-9+/]{200,}={0,2}/, // long base64 blob
|
|
91
|
-
/\beval\s*\(/i,
|
|
103
|
+
/[A-Za-z0-9+/]{200,}={0,2}/, // long base64 blob (the payload itself)
|
|
104
|
+
/\beval\s*\(/i, // dynamic-code execution sink
|
|
92
105
|
/\bnew\s+Function\s*\(/i,
|
|
93
|
-
/\batob\s*\(/i,
|
|
94
|
-
/\bBuffer\.from\s*\([^)]*['"]base64['"]/i,
|
|
95
106
|
/\bvm\.(?:runInContext|runInNewContext|compileFunction)\s*\(/i,
|
|
96
|
-
/\bbase64\s+(?:--decode|-d)\b/i
|
|
107
|
+
/\bbase64\s+(?:--decode|-d)\b/i // shell base64 decode (typically piped to sh)
|
|
97
108
|
];
|
|
98
109
|
const INVISIBLE_UNICODE_PAYLOAD_THRESHOLD = 8;
|
|
99
110
|
|