muaddib-scanner 2.11.120 → 2.11.121
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
|
@@ -807,6 +807,13 @@ const PLAYBOOKS = {
|
|
|
807
807
|
'Vecteur classique de dependency confusion: le code s\'execute a l\'installation. ' +
|
|
808
808
|
'NE PAS installer. Verifier le nom exact du package. Signaler sur npm.',
|
|
809
809
|
|
|
810
|
+
lifecycle_version99:
|
|
811
|
+
'CRITIQUE: Version a major repdigit "win-semver" (99/999/9999) + hook lifecycle = ' +
|
|
812
|
+
'dependency confusion complete. La version elevee force npm a resoudre vers ce package ' +
|
|
813
|
+
'public au lieu du package interne prive, et le hook execute le payload a l\'installation. ' +
|
|
814
|
+
'NE PAS installer. Verifier si un package interne du meme nom existe. Regenerer les secrets ' +
|
|
815
|
+
'exposes. Signaler sur npm.',
|
|
816
|
+
|
|
810
817
|
lifecycle_inline_exec:
|
|
811
818
|
'CRITIQUE: Script lifecycle avec node -e (execution inline). Le code s\'execute automatiquement a npm install. ' +
|
|
812
819
|
'NE PAS installer. Si deja installe: considerer la machine compromise. ' +
|
package/src/rules/index.js
CHANGED
|
@@ -2699,6 +2699,19 @@ const RULES = {
|
|
|
2699
2699
|
],
|
|
2700
2700
|
mitre: 'T1195.002'
|
|
2701
2701
|
},
|
|
2702
|
+
lifecycle_version99: {
|
|
2703
|
+
id: 'MUADDIB-COMPOUND-018',
|
|
2704
|
+
name: 'Lifecycle Hook + Dependency-Confusion Version',
|
|
2705
|
+
severity: 'CRITICAL',
|
|
2706
|
+
confidence: 'high',
|
|
2707
|
+
domain: 'malware',
|
|
2708
|
+
description: 'Version a major repdigit "win-semver" (99/999/9999) AVEC hook lifecycle (preinstall/install/postinstall). Chaine complete de dependency confusion: la version elevee force la resolution npm vers le package public malveillant au lieu du package interne prive, et le hook execute le payload a l\'installation. Compound: version_99_preinstall + lifecycle_script (gate-FPR-test 2026-06-19: 0/3901 FP).',
|
|
2709
|
+
references: [
|
|
2710
|
+
'https://medium.com/@alex.birsan/dependency-confusion-4a5d60fec610',
|
|
2711
|
+
'https://attack.mitre.org/techniques/T1195.002/'
|
|
2712
|
+
],
|
|
2713
|
+
mitre: 'T1195.002'
|
|
2714
|
+
},
|
|
2702
2715
|
lifecycle_inline_exec: {
|
|
2703
2716
|
id: 'MUADDIB-COMPOUND-004',
|
|
2704
2717
|
name: 'Lifecycle Hook + Inline Node Execution',
|
package/src/scanner/package.js
CHANGED
|
@@ -165,17 +165,24 @@ async function scanPackageJson(targetPath) {
|
|
|
165
165
|
}
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
-
// v2.10.89: Dependency confusion indicator —
|
|
168
|
+
// v2.10.89: Dependency confusion indicator — repdigit "win-semver" major with install hooks.
|
|
169
169
|
// Catches: @corpweb-ui/wmkt-library, @toprank/partner, @adac-fahrzeugplattform/ui
|
|
170
|
+
// v2.11.118 (2026-06-19, gate-FPR-test on the GHSA-2026 miss corpus): tightened from a
|
|
171
|
+
// plain `major >= 99` to the repdigit set {99, 999, 9999}. `>= 99` also fired on calendar
|
|
172
|
+
// versions (2026.x — 51 in the FP corpus) and legit high-version packages (chromedriver@148,
|
|
173
|
+
// taskcluster@100, @jetbrains/junie@1966, salt@3008) — masked only because the lone signal
|
|
174
|
+
// stayed HIGH (<20). Restricting to repdigit majors keeps 27/27 corpus dep-conf MALWARE at
|
|
175
|
+
// ZERO benign hits, and unblocks the lifecycle_version99 compound below (which would
|
|
176
|
+
// otherwise inherit the calendar FPs once escalated to CRITICAL).
|
|
170
177
|
const versionStr = pkg.version || '';
|
|
171
178
|
const majorVersion = parseInt(versionStr.split('.')[0], 10);
|
|
172
|
-
if (
|
|
179
|
+
if ([99, 999, 9999].includes(majorVersion)) {
|
|
173
180
|
const hasInstallHook = ['preinstall', 'install', 'postinstall'].some(s => scripts[s]);
|
|
174
181
|
if (hasInstallHook) {
|
|
175
182
|
threats.push({
|
|
176
183
|
type: 'version_99_preinstall',
|
|
177
184
|
severity: 'HIGH',
|
|
178
|
-
message: `Version ${versionStr} (major
|
|
185
|
+
message: `Version ${versionStr} (repdigit win-semver major ${majorVersion}) with lifecycle hook — dependency confusion attack pattern.`,
|
|
179
186
|
file: 'package.json'
|
|
180
187
|
});
|
|
181
188
|
}
|
package/src/scoring.js
CHANGED
|
@@ -536,6 +536,23 @@ const SCORING_COMPOUNDS = [
|
|
|
536
536
|
message: 'Lifecycle hook on typosquat package — dependency confusion attack vector (scoring compound).',
|
|
537
537
|
fileFrom: 'typosquat_detected'
|
|
538
538
|
},
|
|
539
|
+
{
|
|
540
|
+
// 2026-06-19 detection-gap (GHSA-2026 misses): a repdigit "win-semver" version
|
|
541
|
+
// (version_99_preinstall: major 99/999/9999) + an install lifecycle hook is the full
|
|
542
|
+
// dependency-confusion RCE chain. version_99_preinstall alone is HIGH (10), below the
|
|
543
|
+
// 20 alert threshold, so these scored ~13 and were missed (e.g. @doaction/* @99.99.99).
|
|
544
|
+
// Gate-FPR-tested on the confirmed corpus: repdigit-major + lifecycle_script = 0/3901
|
|
545
|
+
// benign FP (the 3 repdigit-version FPs have no install hook), 22/42 GT MALWARE.
|
|
546
|
+
// Both signals are package.json-level (no sameFile / excludeIfBundled needed).
|
|
547
|
+
// requireOriginalSeverityHigh anchors on version_99_preinstall (HIGH) so a lone
|
|
548
|
+
// lifecycle_script (MEDIUM, fires on every install hook) can never trip this alone.
|
|
549
|
+
type: 'lifecycle_version99',
|
|
550
|
+
requires: ['version_99_preinstall', 'lifecycle_script'],
|
|
551
|
+
severity: 'CRITICAL',
|
|
552
|
+
message: 'Dependency-confusion version (repdigit major 99/999/9999) + install lifecycle hook — install-time RCE via dependency confusion (scoring compound).',
|
|
553
|
+
fileFrom: 'version_99_preinstall',
|
|
554
|
+
requireOriginalSeverityHigh: true
|
|
555
|
+
},
|
|
539
556
|
{
|
|
540
557
|
// RT-C1: Boundary-squat dep declared AND require()d in code → CRITICAL.
|
|
541
558
|
// Pattern Axios UNC1069 (March 2026): wrapper looks benign, payload is in the dep.
|