muaddib-scanner 2.11.36 → 2.11.37
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/bin/muaddib.js +20 -0
- package/package.json +1 -1
- package/{self-scan-v2.11.36.json → self-scan-v2.11.37.json} +51 -1
- package/src/output/formatter.js +32 -3
- package/src/output/report.js +40 -0
- package/src/output/sarif.js +9 -4
- package/src/pipeline/processor.js +5 -1
- package/src/rules/index.js +312 -1
package/bin/muaddib.js
CHANGED
|
@@ -56,6 +56,7 @@ let temporalPublishMode = false;
|
|
|
56
56
|
let temporalMaintainerMode = false;
|
|
57
57
|
let temporalFullMode = false;
|
|
58
58
|
let breakdownMode = false;
|
|
59
|
+
let domainFilter = null; // P0a: --domain malware,author → filter output by risk domain
|
|
59
60
|
let noDeobfuscate = false;
|
|
60
61
|
let noModuleGraph = false;
|
|
61
62
|
let noReachability = false;
|
|
@@ -146,6 +147,24 @@ for (let i = 0; i < options.length; i++) {
|
|
|
146
147
|
temporalMaintainerMode = true;
|
|
147
148
|
} else if (options[i] === '--breakdown') {
|
|
148
149
|
breakdownMode = true;
|
|
150
|
+
} else if (options[i] === '--domain') {
|
|
151
|
+
// P0a: comma-separated list of risk domains to DISPLAY (filter only, not
|
|
152
|
+
// a score modifier). Valid values: malware, author, engineering,
|
|
153
|
+
// vulnerability, license, unknown. Example: --domain malware,author
|
|
154
|
+
const val = options[i + 1];
|
|
155
|
+
if (!val || val.startsWith('-')) {
|
|
156
|
+
console.error('[ERROR] --domain requires a comma-separated list (e.g. malware,author)');
|
|
157
|
+
process.exit(1);
|
|
158
|
+
}
|
|
159
|
+
const VALID = new Set(['malware', 'author', 'engineering', 'vulnerability', 'license', 'unknown']);
|
|
160
|
+
const parts = val.split(',').map(s => s.trim().toLowerCase()).filter(Boolean);
|
|
161
|
+
const invalid = parts.filter(p => !VALID.has(p));
|
|
162
|
+
if (invalid.length > 0) {
|
|
163
|
+
console.error('[ERROR] --domain invalid value(s): ' + invalid.join(',') + ' (valid: ' + Array.from(VALID).join('|') + ')');
|
|
164
|
+
process.exit(1);
|
|
165
|
+
}
|
|
166
|
+
domainFilter = parts;
|
|
167
|
+
i++;
|
|
149
168
|
} else if (options[i] === '--no-deobfuscate') {
|
|
150
169
|
noDeobfuscate = true;
|
|
151
170
|
} else if (options[i] === '--no-module-graph') {
|
|
@@ -265,6 +284,7 @@ if (command === 'version' || command === '--version' || command === '-v') {
|
|
|
265
284
|
exclude: excludeDirs,
|
|
266
285
|
entropyThreshold: entropyThreshold,
|
|
267
286
|
breakdown: breakdownMode,
|
|
287
|
+
domainFilter: domainFilter,
|
|
268
288
|
noDeobfuscate: noDeobfuscate,
|
|
269
289
|
noModuleGraph: noModuleGraph,
|
|
270
290
|
noReachability: noReachability,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"target": "node_modules",
|
|
3
|
-
"timestamp": "2026-05-24T21:
|
|
3
|
+
"timestamp": "2026-05-24T21:28:43.647Z",
|
|
4
4
|
"threats": [
|
|
5
5
|
{
|
|
6
6
|
"type": "string_mutation_obfuscation",
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"rule_id": "MUADDIB-AST-074",
|
|
15
15
|
"rule_name": "String Mutation Obfuscation",
|
|
16
16
|
"confidence": "high",
|
|
17
|
+
"domain": "malware",
|
|
17
18
|
"references": [
|
|
18
19
|
"https://attack.mitre.org/techniques/T1027/",
|
|
19
20
|
"https://attack.mitre.org/techniques/T1140/"
|
|
@@ -34,6 +35,7 @@
|
|
|
34
35
|
"rule_id": "MUADDIB-AST-074",
|
|
35
36
|
"rule_name": "String Mutation Obfuscation",
|
|
36
37
|
"confidence": "high",
|
|
38
|
+
"domain": "malware",
|
|
37
39
|
"references": [
|
|
38
40
|
"https://attack.mitre.org/techniques/T1027/",
|
|
39
41
|
"https://attack.mitre.org/techniques/T1140/"
|
|
@@ -54,6 +56,7 @@
|
|
|
54
56
|
"rule_id": "MUADDIB-AST-074",
|
|
55
57
|
"rule_name": "String Mutation Obfuscation",
|
|
56
58
|
"confidence": "high",
|
|
59
|
+
"domain": "malware",
|
|
57
60
|
"references": [
|
|
58
61
|
"https://attack.mitre.org/techniques/T1027/",
|
|
59
62
|
"https://attack.mitre.org/techniques/T1140/"
|
|
@@ -74,6 +77,7 @@
|
|
|
74
77
|
"rule_id": "MUADDIB-AST-074",
|
|
75
78
|
"rule_name": "String Mutation Obfuscation",
|
|
76
79
|
"confidence": "high",
|
|
80
|
+
"domain": "malware",
|
|
77
81
|
"references": [
|
|
78
82
|
"https://attack.mitre.org/techniques/T1027/",
|
|
79
83
|
"https://attack.mitre.org/techniques/T1140/"
|
|
@@ -94,6 +98,7 @@
|
|
|
94
98
|
"rule_id": "MUADDIB-AST-074",
|
|
95
99
|
"rule_name": "String Mutation Obfuscation",
|
|
96
100
|
"confidence": "high",
|
|
101
|
+
"domain": "malware",
|
|
97
102
|
"references": [
|
|
98
103
|
"https://attack.mitre.org/techniques/T1027/",
|
|
99
104
|
"https://attack.mitre.org/techniques/T1140/"
|
|
@@ -114,6 +119,7 @@
|
|
|
114
119
|
"rule_id": "MUADDIB-AST-074",
|
|
115
120
|
"rule_name": "String Mutation Obfuscation",
|
|
116
121
|
"confidence": "high",
|
|
122
|
+
"domain": "malware",
|
|
117
123
|
"references": [
|
|
118
124
|
"https://attack.mitre.org/techniques/T1027/",
|
|
119
125
|
"https://attack.mitre.org/techniques/T1140/"
|
|
@@ -134,6 +140,7 @@
|
|
|
134
140
|
"rule_id": "MUADDIB-AST-074",
|
|
135
141
|
"rule_name": "String Mutation Obfuscation",
|
|
136
142
|
"confidence": "high",
|
|
143
|
+
"domain": "malware",
|
|
137
144
|
"references": [
|
|
138
145
|
"https://attack.mitre.org/techniques/T1027/",
|
|
139
146
|
"https://attack.mitre.org/techniques/T1140/"
|
|
@@ -154,6 +161,7 @@
|
|
|
154
161
|
"rule_id": "MUADDIB-AST-075",
|
|
155
162
|
"rule_name": "Module Internals Hijack",
|
|
156
163
|
"confidence": "high",
|
|
164
|
+
"domain": "malware",
|
|
157
165
|
"references": [
|
|
158
166
|
"https://nodejs.org/api/modules.html",
|
|
159
167
|
"https://attack.mitre.org/techniques/T1574.006/"
|
|
@@ -174,6 +182,7 @@
|
|
|
174
182
|
"rule_id": "MUADDIB-AST-006",
|
|
175
183
|
"rule_name": "Dynamic Require with Concatenation",
|
|
176
184
|
"confidence": "high",
|
|
185
|
+
"domain": "malware",
|
|
177
186
|
"references": [
|
|
178
187
|
"https://attack.mitre.org/techniques/T1027/"
|
|
179
188
|
],
|
|
@@ -193,6 +202,7 @@
|
|
|
193
202
|
"rule_id": "MUADDIB-AST-002",
|
|
194
203
|
"rule_name": "Sensitive Environment Variable Access",
|
|
195
204
|
"confidence": "high",
|
|
205
|
+
"domain": "malware",
|
|
196
206
|
"references": [
|
|
197
207
|
"https://blog.phylum.io/shai-hulud-npm-worm",
|
|
198
208
|
"https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions"
|
|
@@ -213,6 +223,7 @@
|
|
|
213
223
|
"rule_id": "MUADDIB-AST-006",
|
|
214
224
|
"rule_name": "Dynamic Require with Concatenation",
|
|
215
225
|
"confidence": "high",
|
|
226
|
+
"domain": "malware",
|
|
216
227
|
"references": [
|
|
217
228
|
"https://attack.mitre.org/techniques/T1027/"
|
|
218
229
|
],
|
|
@@ -232,6 +243,7 @@
|
|
|
232
243
|
"rule_id": "MUADDIB-AST-006",
|
|
233
244
|
"rule_name": "Dynamic Require with Concatenation",
|
|
234
245
|
"confidence": "high",
|
|
246
|
+
"domain": "malware",
|
|
235
247
|
"references": [
|
|
236
248
|
"https://attack.mitre.org/techniques/T1027/"
|
|
237
249
|
],
|
|
@@ -251,6 +263,7 @@
|
|
|
251
263
|
"rule_id": "MUADDIB-AST-019",
|
|
252
264
|
"rule_name": "Require Cache Poisoning",
|
|
253
265
|
"confidence": "high",
|
|
266
|
+
"domain": "malware",
|
|
254
267
|
"references": [
|
|
255
268
|
"https://attack.mitre.org/techniques/T1574/006/"
|
|
256
269
|
],
|
|
@@ -270,6 +283,7 @@
|
|
|
270
283
|
"rule_id": "MUADDIB-AST-006",
|
|
271
284
|
"rule_name": "Dynamic Require with Concatenation",
|
|
272
285
|
"confidence": "high",
|
|
286
|
+
"domain": "malware",
|
|
273
287
|
"references": [
|
|
274
288
|
"https://attack.mitre.org/techniques/T1027/"
|
|
275
289
|
],
|
|
@@ -289,6 +303,7 @@
|
|
|
289
303
|
"rule_id": "MUADDIB-AST-008",
|
|
290
304
|
"rule_name": "Dynamic import() of Dangerous Module",
|
|
291
305
|
"confidence": "high",
|
|
306
|
+
"domain": "malware",
|
|
292
307
|
"references": [
|
|
293
308
|
"https://attack.mitre.org/techniques/T1027/"
|
|
294
309
|
],
|
|
@@ -308,6 +323,7 @@
|
|
|
308
323
|
"rule_id": "MUADDIB-AST-005",
|
|
309
324
|
"rule_name": "new Function() Constructor",
|
|
310
325
|
"confidence": "high",
|
|
326
|
+
"domain": "vulnerability",
|
|
311
327
|
"references": [
|
|
312
328
|
"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/Function"
|
|
313
329
|
],
|
|
@@ -327,6 +343,7 @@
|
|
|
327
343
|
"rule_id": "MUADDIB-AST-074",
|
|
328
344
|
"rule_name": "String Mutation Obfuscation",
|
|
329
345
|
"confidence": "high",
|
|
346
|
+
"domain": "malware",
|
|
330
347
|
"references": [
|
|
331
348
|
"https://attack.mitre.org/techniques/T1027/",
|
|
332
349
|
"https://attack.mitre.org/techniques/T1140/"
|
|
@@ -347,6 +364,7 @@
|
|
|
347
364
|
"rule_id": "MUADDIB-AST-074",
|
|
348
365
|
"rule_name": "String Mutation Obfuscation",
|
|
349
366
|
"confidence": "high",
|
|
367
|
+
"domain": "malware",
|
|
350
368
|
"references": [
|
|
351
369
|
"https://attack.mitre.org/techniques/T1027/",
|
|
352
370
|
"https://attack.mitre.org/techniques/T1140/"
|
|
@@ -367,6 +385,7 @@
|
|
|
367
385
|
"rule_id": "MUADDIB-AST-008",
|
|
368
386
|
"rule_name": "Dynamic import() of Dangerous Module",
|
|
369
387
|
"confidence": "high",
|
|
388
|
+
"domain": "malware",
|
|
370
389
|
"references": [
|
|
371
390
|
"https://attack.mitre.org/techniques/T1027/"
|
|
372
391
|
],
|
|
@@ -386,6 +405,7 @@
|
|
|
386
405
|
"rule_id": "MUADDIB-AST-019",
|
|
387
406
|
"rule_name": "Require Cache Poisoning",
|
|
388
407
|
"confidence": "high",
|
|
408
|
+
"domain": "malware",
|
|
389
409
|
"references": [
|
|
390
410
|
"https://attack.mitre.org/techniques/T1574/006/"
|
|
391
411
|
],
|
|
@@ -405,6 +425,7 @@
|
|
|
405
425
|
"rule_id": "MUADDIB-AST-008",
|
|
406
426
|
"rule_name": "Dynamic import() of Dangerous Module",
|
|
407
427
|
"confidence": "high",
|
|
428
|
+
"domain": "malware",
|
|
408
429
|
"references": [
|
|
409
430
|
"https://attack.mitre.org/techniques/T1027/"
|
|
410
431
|
],
|
|
@@ -424,6 +445,7 @@
|
|
|
424
445
|
"rule_id": "MUADDIB-AST-008",
|
|
425
446
|
"rule_name": "Dynamic import() of Dangerous Module",
|
|
426
447
|
"confidence": "high",
|
|
448
|
+
"domain": "malware",
|
|
427
449
|
"references": [
|
|
428
450
|
"https://attack.mitre.org/techniques/T1027/"
|
|
429
451
|
],
|
|
@@ -443,6 +465,7 @@
|
|
|
443
465
|
"rule_id": "MUADDIB-AST-070",
|
|
444
466
|
"rule_name": "Shared Memory IPC",
|
|
445
467
|
"confidence": "medium",
|
|
468
|
+
"domain": "malware",
|
|
446
469
|
"references": [
|
|
447
470
|
"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer",
|
|
448
471
|
"https://attack.mitre.org/techniques/T1559/"
|
|
@@ -465,6 +488,7 @@
|
|
|
465
488
|
"rule_id": "MUADDIB-AST-007",
|
|
466
489
|
"rule_name": "Dangerous Shell Command Execution",
|
|
467
490
|
"confidence": "high",
|
|
491
|
+
"domain": "malware",
|
|
468
492
|
"references": [
|
|
469
493
|
"https://owasp.org/www-community/attacks/Command_Injection"
|
|
470
494
|
],
|
|
@@ -486,6 +510,7 @@
|
|
|
486
510
|
"rule_id": "MUADDIB-AST-007",
|
|
487
511
|
"rule_name": "Dangerous Shell Command Execution",
|
|
488
512
|
"confidence": "high",
|
|
513
|
+
"domain": "malware",
|
|
489
514
|
"references": [
|
|
490
515
|
"https://owasp.org/www-community/attacks/Command_Injection"
|
|
491
516
|
],
|
|
@@ -507,6 +532,7 @@
|
|
|
507
532
|
"rule_id": "MUADDIB-AST-007",
|
|
508
533
|
"rule_name": "Dangerous Shell Command Execution",
|
|
509
534
|
"confidence": "high",
|
|
535
|
+
"domain": "malware",
|
|
510
536
|
"references": [
|
|
511
537
|
"https://owasp.org/www-community/attacks/Command_Injection"
|
|
512
538
|
],
|
|
@@ -528,6 +554,7 @@
|
|
|
528
554
|
"rule_id": "MUADDIB-AST-007",
|
|
529
555
|
"rule_name": "Dangerous Shell Command Execution",
|
|
530
556
|
"confidence": "high",
|
|
557
|
+
"domain": "malware",
|
|
531
558
|
"references": [
|
|
532
559
|
"https://owasp.org/www-community/attacks/Command_Injection"
|
|
533
560
|
],
|
|
@@ -549,6 +576,7 @@
|
|
|
549
576
|
"rule_id": "MUADDIB-AST-007",
|
|
550
577
|
"rule_name": "Dangerous Shell Command Execution",
|
|
551
578
|
"confidence": "high",
|
|
579
|
+
"domain": "malware",
|
|
552
580
|
"references": [
|
|
553
581
|
"https://owasp.org/www-community/attacks/Command_Injection"
|
|
554
582
|
],
|
|
@@ -570,6 +598,7 @@
|
|
|
570
598
|
"rule_id": "MUADDIB-AST-007",
|
|
571
599
|
"rule_name": "Dangerous Shell Command Execution",
|
|
572
600
|
"confidence": "high",
|
|
601
|
+
"domain": "malware",
|
|
573
602
|
"references": [
|
|
574
603
|
"https://owasp.org/www-community/attacks/Command_Injection"
|
|
575
604
|
],
|
|
@@ -591,6 +620,7 @@
|
|
|
591
620
|
"rule_id": "MUADDIB-AST-007",
|
|
592
621
|
"rule_name": "Dangerous Shell Command Execution",
|
|
593
622
|
"confidence": "high",
|
|
623
|
+
"domain": "malware",
|
|
594
624
|
"references": [
|
|
595
625
|
"https://owasp.org/www-community/attacks/Command_Injection"
|
|
596
626
|
],
|
|
@@ -612,6 +642,7 @@
|
|
|
612
642
|
"rule_id": "MUADDIB-AST-007",
|
|
613
643
|
"rule_name": "Dangerous Shell Command Execution",
|
|
614
644
|
"confidence": "high",
|
|
645
|
+
"domain": "malware",
|
|
615
646
|
"references": [
|
|
616
647
|
"https://owasp.org/www-community/attacks/Command_Injection"
|
|
617
648
|
],
|
|
@@ -633,6 +664,7 @@
|
|
|
633
664
|
"rule_id": "MUADDIB-AST-007",
|
|
634
665
|
"rule_name": "Dangerous Shell Command Execution",
|
|
635
666
|
"confidence": "high",
|
|
667
|
+
"domain": "malware",
|
|
636
668
|
"references": [
|
|
637
669
|
"https://owasp.org/www-community/attacks/Command_Injection"
|
|
638
670
|
],
|
|
@@ -654,6 +686,7 @@
|
|
|
654
686
|
"rule_id": "MUADDIB-AST-007",
|
|
655
687
|
"rule_name": "Dangerous Shell Command Execution",
|
|
656
688
|
"confidence": "high",
|
|
689
|
+
"domain": "malware",
|
|
657
690
|
"references": [
|
|
658
691
|
"https://owasp.org/www-community/attacks/Command_Injection"
|
|
659
692
|
],
|
|
@@ -675,6 +708,7 @@
|
|
|
675
708
|
"rule_id": "MUADDIB-AST-007",
|
|
676
709
|
"rule_name": "Dangerous Shell Command Execution",
|
|
677
710
|
"confidence": "high",
|
|
711
|
+
"domain": "malware",
|
|
678
712
|
"references": [
|
|
679
713
|
"https://owasp.org/www-community/attacks/Command_Injection"
|
|
680
714
|
],
|
|
@@ -696,6 +730,7 @@
|
|
|
696
730
|
"rule_id": "MUADDIB-AST-007",
|
|
697
731
|
"rule_name": "Dangerous Shell Command Execution",
|
|
698
732
|
"confidence": "high",
|
|
733
|
+
"domain": "malware",
|
|
699
734
|
"references": [
|
|
700
735
|
"https://owasp.org/www-community/attacks/Command_Injection"
|
|
701
736
|
],
|
|
@@ -717,6 +752,7 @@
|
|
|
717
752
|
"rule_id": "MUADDIB-AST-007",
|
|
718
753
|
"rule_name": "Dangerous Shell Command Execution",
|
|
719
754
|
"confidence": "high",
|
|
755
|
+
"domain": "malware",
|
|
720
756
|
"references": [
|
|
721
757
|
"https://owasp.org/www-community/attacks/Command_Injection"
|
|
722
758
|
],
|
|
@@ -738,6 +774,7 @@
|
|
|
738
774
|
"rule_id": "MUADDIB-AST-007",
|
|
739
775
|
"rule_name": "Dangerous Shell Command Execution",
|
|
740
776
|
"confidence": "high",
|
|
777
|
+
"domain": "malware",
|
|
741
778
|
"references": [
|
|
742
779
|
"https://owasp.org/www-community/attacks/Command_Injection"
|
|
743
780
|
],
|
|
@@ -759,6 +796,7 @@
|
|
|
759
796
|
"rule_id": "MUADDIB-AST-007",
|
|
760
797
|
"rule_name": "Dangerous Shell Command Execution",
|
|
761
798
|
"confidence": "high",
|
|
799
|
+
"domain": "malware",
|
|
762
800
|
"references": [
|
|
763
801
|
"https://owasp.org/www-community/attacks/Command_Injection"
|
|
764
802
|
],
|
|
@@ -780,6 +818,7 @@
|
|
|
780
818
|
"rule_id": "MUADDIB-AST-007",
|
|
781
819
|
"rule_name": "Dangerous Shell Command Execution",
|
|
782
820
|
"confidence": "high",
|
|
821
|
+
"domain": "malware",
|
|
783
822
|
"references": [
|
|
784
823
|
"https://owasp.org/www-community/attacks/Command_Injection"
|
|
785
824
|
],
|
|
@@ -801,6 +840,7 @@
|
|
|
801
840
|
"rule_id": "MUADDIB-AST-007",
|
|
802
841
|
"rule_name": "Dangerous Shell Command Execution",
|
|
803
842
|
"confidence": "high",
|
|
843
|
+
"domain": "malware",
|
|
804
844
|
"references": [
|
|
805
845
|
"https://owasp.org/www-community/attacks/Command_Injection"
|
|
806
846
|
],
|
|
@@ -822,6 +862,7 @@
|
|
|
822
862
|
"rule_id": "MUADDIB-AST-007",
|
|
823
863
|
"rule_name": "Dangerous Shell Command Execution",
|
|
824
864
|
"confidence": "high",
|
|
865
|
+
"domain": "malware",
|
|
825
866
|
"references": [
|
|
826
867
|
"https://owasp.org/www-community/attacks/Command_Injection"
|
|
827
868
|
],
|
|
@@ -847,6 +888,7 @@
|
|
|
847
888
|
"rule_id": "MUADDIB-ENTROPY-001",
|
|
848
889
|
"rule_name": "High Entropy String",
|
|
849
890
|
"confidence": "medium",
|
|
891
|
+
"domain": "malware",
|
|
850
892
|
"references": [
|
|
851
893
|
"https://attack.mitre.org/techniques/T1027/"
|
|
852
894
|
],
|
|
@@ -872,6 +914,7 @@
|
|
|
872
914
|
"rule_id": "MUADDIB-ENTROPY-001",
|
|
873
915
|
"rule_name": "High Entropy String",
|
|
874
916
|
"confidence": "medium",
|
|
917
|
+
"domain": "malware",
|
|
875
918
|
"references": [
|
|
876
919
|
"https://attack.mitre.org/techniques/T1027/"
|
|
877
920
|
],
|
|
@@ -897,6 +940,7 @@
|
|
|
897
940
|
"rule_id": "MUADDIB-ENTROPY-001",
|
|
898
941
|
"rule_name": "High Entropy String",
|
|
899
942
|
"confidence": "medium",
|
|
943
|
+
"domain": "malware",
|
|
900
944
|
"references": [
|
|
901
945
|
"https://attack.mitre.org/techniques/T1027/"
|
|
902
946
|
],
|
|
@@ -922,6 +966,7 @@
|
|
|
922
966
|
"rule_id": "MUADDIB-ENTROPY-001",
|
|
923
967
|
"rule_name": "High Entropy String",
|
|
924
968
|
"confidence": "medium",
|
|
969
|
+
"domain": "malware",
|
|
925
970
|
"references": [
|
|
926
971
|
"https://attack.mitre.org/techniques/T1027/"
|
|
927
972
|
],
|
|
@@ -947,6 +992,7 @@
|
|
|
947
992
|
"rule_id": "MUADDIB-ENTROPY-001",
|
|
948
993
|
"rule_name": "High Entropy String",
|
|
949
994
|
"confidence": "medium",
|
|
995
|
+
"domain": "malware",
|
|
950
996
|
"references": [
|
|
951
997
|
"https://attack.mitre.org/techniques/T1027/"
|
|
952
998
|
],
|
|
@@ -972,6 +1018,7 @@
|
|
|
972
1018
|
"rule_id": "MUADDIB-ENTROPY-001",
|
|
973
1019
|
"rule_name": "High Entropy String",
|
|
974
1020
|
"confidence": "medium",
|
|
1021
|
+
"domain": "malware",
|
|
975
1022
|
"references": [
|
|
976
1023
|
"https://attack.mitre.org/techniques/T1027/"
|
|
977
1024
|
],
|
|
@@ -997,6 +1044,7 @@
|
|
|
997
1044
|
"rule_id": "MUADDIB-ENTROPY-001",
|
|
998
1045
|
"rule_name": "High Entropy String",
|
|
999
1046
|
"confidence": "medium",
|
|
1047
|
+
"domain": "malware",
|
|
1000
1048
|
"references": [
|
|
1001
1049
|
"https://attack.mitre.org/techniques/T1027/"
|
|
1002
1050
|
],
|
|
@@ -1022,6 +1070,7 @@
|
|
|
1022
1070
|
"rule_id": "MUADDIB-ENTROPY-001",
|
|
1023
1071
|
"rule_name": "High Entropy String",
|
|
1024
1072
|
"confidence": "medium",
|
|
1073
|
+
"domain": "malware",
|
|
1025
1074
|
"references": [
|
|
1026
1075
|
"https://attack.mitre.org/techniques/T1027/"
|
|
1027
1076
|
],
|
|
@@ -1047,6 +1096,7 @@
|
|
|
1047
1096
|
"rule_id": "MUADDIB-ENTROPY-001",
|
|
1048
1097
|
"rule_name": "High Entropy String",
|
|
1049
1098
|
"confidence": "medium",
|
|
1099
|
+
"domain": "malware",
|
|
1050
1100
|
"references": [
|
|
1051
1101
|
"https://attack.mitre.org/techniques/T1027/"
|
|
1052
1102
|
],
|
package/src/output/formatter.js
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
const { saveReport } = require('../report.js');
|
|
2
2
|
const { saveSARIF } = require('../sarif.js');
|
|
3
3
|
const { getPlaybook } = require('../response/playbooks.js');
|
|
4
|
+
const { DOMAIN_CODES, getRuleDomain } = require('../rules/index.js');
|
|
5
|
+
|
|
6
|
+
// P0a — domain tag formatter for CLI text output.
|
|
7
|
+
// Returns a bracketed 3-letter code like "[MAL]" / "[AUT]" / "[ENG]" / "[VUL]"
|
|
8
|
+
// to display next to the severity prefix. Resolves the domain from the threat
|
|
9
|
+
// type if not already set on the threat object (defense in depth).
|
|
10
|
+
function domainTag(threat) {
|
|
11
|
+
const d = (threat && threat.domain) || (threat && threat.type ? getRuleDomain(threat.type) : 'malware');
|
|
12
|
+
const code = DOMAIN_CODES[d] || 'UNK';
|
|
13
|
+
return '[' + code + ']';
|
|
14
|
+
}
|
|
4
15
|
|
|
5
16
|
/**
|
|
6
17
|
* Format and print scan output in the requested format.
|
|
@@ -85,8 +96,9 @@ function formatOutput(result, options, ctx) {
|
|
|
85
96
|
enrichedThreats.forEach((t, i) => {
|
|
86
97
|
console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`);
|
|
87
98
|
const countStr = t.count > 1 ? ` (x${t.count})` : '';
|
|
88
|
-
console.log(` ${i + 1}. [${t.severity}] ${t.rule_name}${countStr}`);
|
|
99
|
+
console.log(` ${i + 1}. [${t.severity}] ${domainTag(t)} ${t.rule_name}${countStr}`);
|
|
89
100
|
console.log(` Rule ID: ${t.rule_id}`);
|
|
101
|
+
console.log(` Domain: ${t.domain || getRuleDomain(t.type)}`);
|
|
90
102
|
console.log(` File: ${t.file}`);
|
|
91
103
|
if (t.line) console.log(` Line: ${t.line}`);
|
|
92
104
|
console.log(` Confidence: ${t.confidence}`);
|
|
@@ -162,14 +174,28 @@ function formatOutput(result, options, ctx) {
|
|
|
162
174
|
// clutter the output on monorepos. Show with --verbose. Scoring, JSON,
|
|
163
175
|
// SARIF, and HTML output are unaffected — this is display-only.
|
|
164
176
|
const hiddenCount = options.verbose ? 0 : deduped.filter(t => t.degraded && t.severity === 'LOW').length;
|
|
165
|
-
|
|
177
|
+
let displayThreats = options.verbose ? deduped : deduped.filter(t => !(t.degraded && t.severity === 'LOW'));
|
|
178
|
+
// P0a — --domain filter is DISPLAY ONLY. Score/exit code are computed
|
|
179
|
+
// from the full set; this only narrows the printed threats. Allows
|
|
180
|
+
// workflows like "show me only author-risk threats" without changing
|
|
181
|
+
// the underlying alert level.
|
|
182
|
+
let domainFilteredOut = 0;
|
|
183
|
+
if (Array.isArray(options.domainFilter) && options.domainFilter.length > 0) {
|
|
184
|
+
const allowed = new Set(options.domainFilter);
|
|
185
|
+
const before = displayThreats.length;
|
|
186
|
+
displayThreats = displayThreats.filter(t => {
|
|
187
|
+
const d = t.domain || getRuleDomain(t.type);
|
|
188
|
+
return allowed.has(d);
|
|
189
|
+
});
|
|
190
|
+
domainFilteredOut = before - displayThreats.length;
|
|
191
|
+
}
|
|
166
192
|
if (displayThreats.length === 0 && hiddenCount > 0) {
|
|
167
193
|
console.log(`[OK] No high-confidence threats detected (${hiddenCount} low-confidence signal(s) hidden, use --verbose to show).\n`);
|
|
168
194
|
} else {
|
|
169
195
|
console.log(`[ALERT] ${displayThreats.length} threat(s) detected:\n`);
|
|
170
196
|
displayThreats.forEach((t, i) => {
|
|
171
197
|
const countStr = t.count > 1 ? ` (x${t.count})` : '';
|
|
172
|
-
console.log(` ${i + 1}. [${t.severity}] ${t.type}${countStr}`);
|
|
198
|
+
console.log(` ${i + 1}. [${t.severity}] ${domainTag(t)} ${t.type}${countStr}`);
|
|
173
199
|
console.log(` ${t.message}`);
|
|
174
200
|
console.log(` File: ${t.file}`);
|
|
175
201
|
const playbook = getPlaybook(t.type);
|
|
@@ -181,6 +207,9 @@ function formatOutput(result, options, ctx) {
|
|
|
181
207
|
if (hiddenCount > 0) {
|
|
182
208
|
console.log(` + ${hiddenCount} low-confidence signal(s) hidden (use --verbose to show)\n`);
|
|
183
209
|
}
|
|
210
|
+
if (domainFilteredOut > 0) {
|
|
211
|
+
console.log(` + ${domainFilteredOut} threat(s) hidden by --domain filter (score unchanged)\n`);
|
|
212
|
+
}
|
|
184
213
|
}
|
|
185
214
|
}
|
|
186
215
|
|
package/src/output/report.js
CHANGED
|
@@ -1,12 +1,39 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const { escapeHtml } = require('../utils.js');
|
|
3
|
+
const { DOMAIN_CODES, getRuleDomain } = require('../rules/index.js');
|
|
4
|
+
|
|
5
|
+
// P0a — color palette for risk domain badges in the HTML report.
|
|
6
|
+
const DOMAIN_COLORS = {
|
|
7
|
+
malware: '#e94560', // red — top threat
|
|
8
|
+
author: '#ff6b35', // orange — identity/maintainer issues
|
|
9
|
+
engineering: '#f9c74f', // yellow — quality/hygiene
|
|
10
|
+
vulnerability: '#9b59b6', // purple — CWE-class defects
|
|
11
|
+
license: '#4ecdc4', // cyan — reserved
|
|
12
|
+
unknown: '#888888' // gray — fallback
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
function domainBadge(threat) {
|
|
16
|
+
const d = (threat && threat.domain) || (threat && threat.type ? getRuleDomain(threat.type) : 'malware');
|
|
17
|
+
const code = DOMAIN_CODES[d] || 'UNK';
|
|
18
|
+
const color = DOMAIN_COLORS[d] || DOMAIN_COLORS.unknown;
|
|
19
|
+
return `<span class="domain-badge" style="background:${color};color:#fff;padding:2px 8px;border-radius:3px;font-size:11px;font-weight:bold;">${escapeHtml(code)}</span>`;
|
|
20
|
+
}
|
|
3
21
|
|
|
4
22
|
function generateHTML(results) {
|
|
5
23
|
const { target, timestamp, threats, summary } = results;
|
|
6
24
|
|
|
25
|
+
// P0a — Risk by Domain breakdown
|
|
26
|
+
const domainCounts = { malware: 0, author: 0, engineering: 0, vulnerability: 0, license: 0, unknown: 0 };
|
|
27
|
+
for (const t of threats) {
|
|
28
|
+
const d = t.domain || getRuleDomain(t.type);
|
|
29
|
+
if (domainCounts[d] !== undefined) domainCounts[d]++;
|
|
30
|
+
else domainCounts.unknown++;
|
|
31
|
+
}
|
|
32
|
+
|
|
7
33
|
const threatRows = threats.map(t => `
|
|
8
34
|
<tr class="${escapeHtml(t.severity).toLowerCase()}">
|
|
9
35
|
<td>${escapeHtml(t.severity)}</td>
|
|
36
|
+
<td>${domainBadge(t)}</td>
|
|
10
37
|
<td>${escapeHtml(t.type)}</td>
|
|
11
38
|
<td>${escapeHtml(t.message)}</td>
|
|
12
39
|
<td>${escapeHtml(t.file)}</td>
|
|
@@ -142,10 +169,23 @@ function generateHTML(results) {
|
|
|
142
169
|
</div>
|
|
143
170
|
|
|
144
171
|
${threats.length > 0 ? `
|
|
172
|
+
<div class="domain-breakdown" style="background:#16213e;padding:20px;border-radius:8px;margin:20px 0;">
|
|
173
|
+
<h3 style="color:#e94560;margin-top:0;">Risk by Domain</h3>
|
|
174
|
+
<div style="display:flex;gap:12px;flex-wrap:wrap;">
|
|
175
|
+
${Object.entries(domainCounts).filter(([, n]) => n > 0).map(([d, n]) => `
|
|
176
|
+
<div style="background:${DOMAIN_COLORS[d]};color:#fff;padding:8px 14px;border-radius:6px;min-width:90px;">
|
|
177
|
+
<div style="font-size:11px;opacity:0.8;">${escapeHtml(DOMAIN_CODES[d])}</div>
|
|
178
|
+
<div style="font-size:22px;font-weight:bold;">${n}</div>
|
|
179
|
+
<div style="font-size:11px;opacity:0.8;text-transform:capitalize;">${escapeHtml(d)}</div>
|
|
180
|
+
</div>
|
|
181
|
+
`).join('')}
|
|
182
|
+
</div>
|
|
183
|
+
</div>
|
|
145
184
|
<table>
|
|
146
185
|
<thead>
|
|
147
186
|
<tr>
|
|
148
187
|
<th>Severity</th>
|
|
188
|
+
<th>Domain</th>
|
|
149
189
|
<th>Type</th>
|
|
150
190
|
<th>Message</th>
|
|
151
191
|
<th>File</th>
|
package/src/output/sarif.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
-
const { RULES } = require('../rules/index.js');
|
|
3
|
+
const { RULES, getRuleDomain } = require('../rules/index.js');
|
|
4
4
|
|
|
5
5
|
const pkgVersion = (() => {
|
|
6
6
|
try {
|
|
@@ -26,7 +26,7 @@ function generateSARIF(results) {
|
|
|
26
26
|
name: 'MUADDIB',
|
|
27
27
|
version: pkgVersion,
|
|
28
28
|
informationUri: 'https://github.com/DNSZLSK/muad-dib',
|
|
29
|
-
rules: Object.
|
|
29
|
+
rules: Object.entries(RULES).map(([type, rule]) => ({
|
|
30
30
|
id: rule.id,
|
|
31
31
|
name: rule.name,
|
|
32
32
|
shortDescription: { text: rule.description },
|
|
@@ -35,7 +35,10 @@ function generateSARIF(results) {
|
|
|
35
35
|
properties: {
|
|
36
36
|
severity: rule.severity,
|
|
37
37
|
confidence: rule.confidence,
|
|
38
|
-
mitre: rule.mitre
|
|
38
|
+
mitre: rule.mitre,
|
|
39
|
+
// P0a — Risk Domains taxonomy. Either set explicitly on the rule
|
|
40
|
+
// or resolved via getRuleDomain default (currently 'malware').
|
|
41
|
+
risk_domain: getRuleDomain(type)
|
|
39
42
|
}
|
|
40
43
|
}))
|
|
41
44
|
}
|
|
@@ -66,7 +69,9 @@ function generateSARIF(results) {
|
|
|
66
69
|
],
|
|
67
70
|
properties: {
|
|
68
71
|
confidence: threat.confidence,
|
|
69
|
-
mitre: threat.mitre
|
|
72
|
+
mitre: threat.mitre,
|
|
73
|
+
// P0a — per-result risk domain (resolved from threat.type).
|
|
74
|
+
risk_domain: getRuleDomain(threat.type)
|
|
70
75
|
}
|
|
71
76
|
}))
|
|
72
77
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
-
const { getRule } = require('../rules/index.js');
|
|
3
|
+
const { getRule, getRuleDomain } = require('../rules/index.js');
|
|
4
4
|
const { getPlaybook } = require('../response/playbooks.js');
|
|
5
5
|
const { computeReachableFiles, computeReachableFunctions } = require('../scanner/reachability.js');
|
|
6
6
|
const { applyFPReductions, applyCompoundBoosts, calculateRiskScore, getSeverityWeights, applyContextualFPCaps, applySingleFireCriticalFloor, applyReputationFactor, applyMatureStableCap, applySandboxVerdict, applyDeltaMultiplier } = require('../scoring.js');
|
|
@@ -399,6 +399,10 @@ async function process(threats, targetPath, options, pythonDeps, warnings, scann
|
|
|
399
399
|
rule_name: rule.name || t.type,
|
|
400
400
|
confidence: rule.confidence || 'medium',
|
|
401
401
|
confidenceTier: t.confidenceTier || 'medium',
|
|
402
|
+
// P0a — Risk Domains taxonomy (inspired by Phylum's 5-domain model).
|
|
403
|
+
// Lets downstream tooling filter by risk category (malware/author/
|
|
404
|
+
// engineering/vulnerability/license) without re-mapping threat types.
|
|
405
|
+
domain: getRuleDomain(t.type),
|
|
402
406
|
references: rule.references || [],
|
|
403
407
|
mitre: t.mitre || rule.mitre,
|
|
404
408
|
playbook: getPlaybook(t.type),
|