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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "muaddib-scanner",
3
- "version": "2.11.120",
3
+ "version": "2.11.121",
4
4
  "description": "Supply-chain threat detection & response for npm & PyPI/Python",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "target": "node_modules",
3
- "timestamp": "2026-06-18T19:56:37.339Z",
3
+ "timestamp": "2026-06-19T09:42:28.283Z",
4
4
  "threats": [
5
5
  {
6
6
  "type": "string_mutation_obfuscation",
@@ -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. ' +
@@ -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',
@@ -165,17 +165,24 @@ async function scanPackageJson(targetPath) {
165
165
  }
166
166
  }
167
167
 
168
- // v2.10.89: Dependency confusion indicator — version >= 99 with install hooks
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 (majorVersion >= 99) {
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 >= 99) with lifecycle hook — dependency confusion attack pattern.`,
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.