-
Notifications
You must be signed in to change notification settings - Fork 246
Expand file tree
/
Copy pathCHANGELOG
More file actions
1029 lines (996 loc) · 74.1 KB
/
Copy pathCHANGELOG
File metadata and controls
1029 lines (996 loc) · 74.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
v2.0.1 | Mar 25 2026:
-- New Features --
[New] Monitor mode: supervisor model replaces double-fork; 12 pre-existing defects resolved (graceful shutdown, crash recovery, session rotation, event filter, PID guard, ClamAV cache); issue #454, #447, #459
[New] Config: digest_interval, digest_escalate_hits, monitor_paths_extra for monitor mode
[New] TSV canonical session format: 11-field hit records replace plaintext session files;
session_legacy_compat config (auto/0/1) for backward compatibility
[New] JSON report output: --json-report [SCANID|list|newest] renders TSV sessions as
JSON (v1.0 schema); --format text|json|html and --mailto ADDRESS
[New] Compound signature (csig) scanning: multi-pattern boolean logic (AND/OR/threshold),
case-insensitive matching (i:), wide UTF-16LE matching (w:), bounded gap wildcards
({N-M}); csig.dat and custom.csig.dat; scan_csig config var
[New] SHA-256 hash-based scanning: CPU hardware acceleration auto-detection (SHA-NI on
x86, SHA2 on ARM); scan_hashtype config (auto/sha256/md5/both); sha256v2.dat
signature file; ClamAV .hsb integration with version gate (>= 0.97);
custom.sha256.dat for user-defined sigs
[New] Native batch scan engine: 43x faster HEX+CSIG; parallel grep workers;
micro-chunked processing (scan_hex_chunk_size config); Perl dependency removed
[New] Batch hit processing: unified bulk operations replace per-hit fork loops across
all scan engines; batched chattr/chmod/chown for quarantine
[New] Native YARA scanning: scan_yara=1 enables YARA as independent scan stage with
yara or yr (YARA-X) binary; custom.yara and custom.yara.d/ drop-in directory;
compiled rules via yarac, --scan-list batch scanning; issue #392, #277, #239
[New] Email alerts reimagined: HTML+text dual-format with template engine ({{TOKEN}}
placeholders); SMTP relay support (smtp_relay, smtp_from, smtp_user, smtp_pass);
email_format config (text/html/both); Slack Block Kit, Telegram MarkdownV2,
Discord embed templates; on-demand HTML rendering from session data
[New] Discord alerting: discord_alert and discord_webhook_url config; scan reports
uploaded via Discord webhook multipart upload
[New] Shared library integrations: alert_lib, elog_lib (structured event logging with
audit trail), tlog_lib (incremental log tracking), pkg_lib (packaging primitives)
[New] ClamAV signature validation gate: clamscan -d validates sig files before
deployment; sigup() SIGUSR2 reload gated on validation success; issue #467
[New] sigup_interval: independent 6-hourly signature update cron job via
/etc/cron.d/maldet-sigup; --cron-sigup handler; configurable interval (0 to disable)
[New] cron.watchdog: weekly watchdog script for independent fallback signature updates
[New] cron.daily: explicit cPanel addon/subdomain document root detection via
/etc/userdatadomains; Bitrix panel detection; issue #268, #381
[New] -v/--version flag displays version information and exits 0
[New] scan_clamscan and scan_yara support 'auto' mode for runtime binary detection
[New] Hook scanning API: modsec/ftp/proftpd/exim/generic mode dispatch; --list/--stdin
batch; rate limit; sig masking
[New] Hook escalation: immediate alert on hit threshold; deduplicated with digest
[New] Hook digest and reporting: --digest on-demand alerts; --report hooks with
time/mode filters
[New] --test-alert {scan|digest} {email|slack|telegram|discord}: send test alert with
synthetic data through the real rendering pipeline; channel isolation; root-only gate
[New] Audit log: 7 event types (purge, update, alert_failed, hookscan source/rate metadata)
[New] importconf: config migration extracted from install.sh for shared use
[New] RPM and DEB packaging: FHS-compliant layout with backward-compatible symlink farm
[New] Package install tests: FHS layout, symlink farm, permissions verification
[New] Symlink farm enforcement: static manifest ships with RPM/DEB; pkg_fhs_verify_farm
auto-detects and repairs broken symlinks at startup
[New] FHS fallback sourcing: maldet boots from /usr/lib/maldet when legacy symlinks broken
[New] Portable source-tree execution: run maldet directly from git clone or tarball without
install.sh; auto-detects inspath from script location; LMD_BASEDIR env override
[New] Scan lifecycle management: --kill, --pause/--unpause, --stop/--continue for running
scans; -L/--list-active shows running/paused/stopped scans (text/json/tsv);
--maintenance rotates history, compresses sessions, archives by month; session index
for O(1) report listing; scan.meta tracks per-scan state; scan_meta_cleanup_age config
[New] SCANID format validation: ^[0-9]{6}-[0-9]{4}\.[0-9]+$ regex enforced at all 5 CLI
entry points (--kill, --pause, --unpause, --stop, --continue)
[New] -e list: redesigned columnar output with header row; --all flag shows full scan
history (default: recent 14 entries); QUAR column; stopped/checkpointed scans visible
between active and history sections (text and JSON); pager when --all on TTY;
JSON active array; FreeBSD sort support
[New] Logrotate config: /etc/logrotate.d/maldet rotates event_log, clamscan_log, and
audit.log weekly (12 rotations); inotify_log excluded (managed by --maintenance);
installed only when logrotate is available; RPM/DEB: %config(noreplace)
[New] post-scan hook: configurable script execution after scan completion;
supports args/file/json output tiers, sync/async execution, timeout
with SIGTERM/SIGKILL, elog audit trail, min_hits threshold, scan type filter;
scan_start epoch in JSON payload (LMD_SCAN_START env); issue #477
[New] ignore_inotify: two-file union model — LMD-managed defaults
($inspath/internals/ignore_inotify.defaults) refreshed for systemd-private
tmpdirs, modern MariaDB, PostgreSQL, Redis, ClamAV runtime; user-owned
ignore_inotify retained for site overrides; dead legacy regex defaults
replaced (broken since _monitor_escape_ere change); issue #480
[New] monitor_scan_owner_filters config variable: when 0 (default), monitor mode
admits all files regardless of owner so root-owned malware is not silently
dropped; when 1, scan_ignore_root/user/group ownership filters are applied
in monitor mode (opt-in); issue #485
[New] tests/uat/05-monitor-mode.bats: UAT scenario asserting monitor quarantines
a root-owned EICAR dropped into a webuser-owned docroot under reporter's
config (scan_ignore_root=1 + monitor_scan_owner_filters=0 default);
regression test closing the coverage hole that let rc1..rc3 ship with the
filter bug; issue #485
-- Changes --
[Change] slop: remove 15 unused LMD_<STEM>_VERSION sub-lib constants +
paired shellcheck disable=SC2034 suppressions; set at sub-lib
extraction, never consumed by any code, test, packaging, or
doc surface; _LMD_<STEM>_LOADED source guards (distinct symbols)
remain as the idempotent-sourcing mechanism; round 3 slop audit
[New] _monitor_to_ere_entry(): semantic dispatch helper for ignore_inotify
entry preparation (defaults-always-escape, user-raw-or-literal:)
[Change] tests/48-monitor-ignore-regex.bats: integration coverage for
ignore_inotify ERE + literal: prefix + ignore_paths monitor-mode
consistency + malformed-regex symmetry; issue #484
[Change] docs: ignore_inotify ERE-default + literal: prefix semantics
across ignore_inotify header, README §7, maldet.1 FILES; issue #484
[Change] tests: prune two tautological assertions — the
"uninstall.sh delegates service removal to pkg_service_uninstall"
grep-for-token check in 01-install-cli.bats (string presence, not
behavior) and the "ignore_inotify.defaults is installed at
internals path" existence check in 47-ignore-inotify-defaults.bats
(adjacent "has non-comment entries" test already fails if the
file is missing)
[Change] monitor: log filtered-cycle event count when all events dropped by
tier-2 scan filter (_event_count > 0 but _tot_files == 0); issue #485
[Change] tests/helpers/uat-lmd.bash: de-duplicate Dockerfile-level
scan_ignore_root="0" bake — remove redundant sed from
uat_lmd_install and add opt-in uat_lmd_disable_root_filter
helper so each UAT caller explicitly documents its
dependency on the override; all 19 existing UAT callers
migrated (effective value unchanged — still 0 via
Dockerfile bake + explicit helper call); unblocks issue-485
UAT which re-sets scan_ignore_root=1 to exercise the
production default; issue #485
[Change] docs: conf.maldet scan_ignore_root comment cross-references monitor carve-out;
README.md scan_ignore_root row notes monitor exception, new
monitor_scan_owner_filters row added to monitor config table;
maldet.1 MONITOR MODE gains carve-out paragraph (issue #485 rationale,
monitor_scan_owner_filters semantics) and Monitoring config group
listing updated; issue #485
[Change] Vendored libs synced to canonical: tlog_lib 2.0.6, alert_lib 1.0.7, elog_lib 1.0.6, pkg_lib 1.0.10 (zero functional change)
[Change] Alert templates: consolidate summary into headers; drop "TOTAL" prefix from
labels (HITS/CLEANED/QUARANTINED); add quarantine metrics; aligned column spacing
[Change] Hook scans write to rolling hook.hits.log instead of creating session files;
genalert suppressed for hook scans
[Change] HTML email rendered on-demand at send time from current templates; persistent
.html session files no longer stored; responsive layout with Outlook compatibility
[Change] CLI: modifier flags (-x, -i, -hscan, -qd, -co, --format, --mailto) are now
position-independent; -co uses in-memory parser; -qd with non-existent
directory exits 1
[Change] Rename sig_import_*_url config variables (from import_custsigs_*_url) for
sig_* namespace consistency; compat.conf migration maps old names
[Change] scan_workers default changed from "0" to "auto"; "0" silently accepted as
auto for backward compat
[Change] Update verification prefers SHA-256 over MD5; graceful MD5 fallback when
sha256sum absent
[Change] maldet.service: EnvironmentFile changed from conf.maldet to
/etc/sysconfig/maldet or /etc/default/maldet; init script uses -b daemonization
[Change] -E/--dump-report suppressed from help; case handler retained for backward compat
[Change] inotify_verbose config variable removed; per-file ClamAV logging was
superseded by batch engine log messages with no in-code consumer
[Change] telegram_file_caption config variable removed; was unreferenced — the
Telegram file upload passes an empty caption
[Change] Scan engine: HEX+CSIG merged into single worker pass; scan stage reorder
(strlen runs last); bulk awk HEX classifier
[Change] gensigs: awk compiler for faster signature compilation; dead helpers removed
[Change] _scan_progress(): plain newline-terminated output in non-TTY contexts;
ANSI escape sequences gated behind TTY check; logarithmic backoff reduces
progress I/O on non-native engines (ClamAV, YARA); watchdog semantics for
engine health monitoring
[Change] install.sh: delegate config/state migration to importconf
[Change] scan_hexdepth default reduced from 524288 (512 KB) to 262144 (256 KB); covers
98.9% of HEX patterns with YARA backstop for remaining 1.1%; importconf migration
for old default
[Change] FHS log path: /var/log/maldet/ is now the authoritative log directory for all
install methods; $inspath/logs is a backward-compatible symlink; install.sh
migrates existing logs on upgrade (cp -a, preserves timestamps/permissions)
[Change] --maintenance: session compression age raised from 1 hour to 30 days;
archive age raised from 30 days to 90 days; scan_meta_cleanup_age default
raised from 24 to 48 hours; new config variables maint_compress_age,
maint_archive_age (both disableable with 0)
[Change] cron.daily: run --maintenance after sigup/versionup for automated history
rotation and session cleanup; hardcoded log paths replaced with $maldet_log
[Change] Lifecycle JSON (-L --format json): "scan_id" is now the canonical field name;
"scanid" remains as a deprecated alias for one release cycle and will be
removed in v2.1.0. Consumers should switch to "scan_id"; issue #482
[Change] Lifecycle JSON (-L --format json): "workers" field type normalized to
unquoted number to match the field's underlying integer value; issue #482
[Change] _json_escape_string: promoted to lmd.lib.sh shared utilities so all JSON
emitters (scan list, active lifecycle, post-scan hook, ELK dispatch) share
one helper; sibling _json_escape_var out-parameter helper for hot loops
that must avoid a subshell fork per iteration; issue #482
[Change] --json-report list: active[]/stopped[] gain ppid + hashtype fields from
scan.meta; reports[] gains derived completed_epoch (started_epoch +
elapsed_seconds, null when inputs missing); field ordering normalized
across all three arrays (identity → process → location → time →
config → metrics)
[Change] --json-report list schema 1.1: top-level scanner block ({name, version,
sig_version}) and host block ({hostname, host_id}) mirror per-scan
JSON schema; field renames for parity with per-scan JSON — hashtype
→ hash_type, hits → total_hits, elapsed → elapsed_seconds; stopped[]
stopped_hr → stopped for symmetry with started/started_epoch pattern
(internal meta/checkpoint field names unchanged); active[]/stopped[]
add quarantine_enabled (boolean, from scan.meta) and null total_cleaned/
total_quarantined (post-scan actions not yet determined mid-scan);
stopped[] adds engine + sig_version parity with active[]; reports[]
adds sig_version + quarantine_enabled (null for pre-bump rows and
legacy plaintext sessions)
[Change] scan.meta: new quarantine_enabled field written by _lifecycle_write_meta
from $quarantine_hits; _lifecycle_read_meta parses into
_meta_quarantine_enabled
[Change] maldet.1, README.md: schema 1.2 docs — new JSON OUTPUT subsection
in maldet.1 documenting the uniform top-level shape; --json-report
description extended; session.index FILES entry describes 14-field
v2 schema with back-compat note for v1; README.md JSON references
updated v1.0 → v1.2
[Change] --json-report SCANID schema 1.2: per-scan JSON shape now mirrors
--json-report list — top-level keys are {schema_version, scanner,
host, reports[single]}; reports[0] carries scan_id (was scan.id),
started_epoch + completed_epoch (NEW), and the existing per-scan
fields (path, started, completed, elapsed_seconds, total_files,
total_hits, total_cleaned, total_quarantined, quarantine_enabled,
hits[], summary{}); scanner block at top level adds engine +
hash_type alongside name/version/sig_version; legacy plaintext
sessions emit the same shape with reports[0].source="legacy" and
scanner.{engine,hash_type,version,sig_version}=null
[Change] --json-report list schema_version 1.1→1.2: top-level "version" key
renamed to "schema_version" and bumped to "1.2"; reports[] entries
now carry "completed" (string from session.index field 12),
"engine" (field 13), "hash_type" (field 14) for parity with
per-scan JSON; pre-v1.2 index rows and pass-2 legacy plaintext
sessions emit literal JSON null (never "-", never empty)
[Change] session.index v1.2 readers: text path (view_report list) and JSON
list pass-1 extend their IFS=read named-vars lists with
_ix_completed_hr / _ix_engine / _ix_hashtype to consume the new
fields without spillage; pass-2 legacy reader unchanged (predates
v1.2 fields, will emit JSON null in Phase 4 emission step)
[Change] session.index schema 1.2: bumped 11→14 fields (completed_hr + engine
+ hash_type appended as fields 12-14); header sentinel #LMD_INDEX:v1
→ v2 for explicit consumer-side detection (readers tolerate both);
_session_index_append accepts 14 args (11-arg calls default fields
12-14 to "-"); _session_index_rebuild wires through previously-
discarded TSV throwaway vars _r_end_hr/_r_engine/_r_hashtype
[Change] session.index schema bumped 9→11 fields (sig_version + quarantine_enabled
appended as fields 10 + 11); _session_index_append accepts 11 args
(9-arg calls default fields 10-11 to "-" and "0"); _session_index_rebuild
emits 11 fields from TSV session headers; readers tolerate old 8/9-field
rows via existing backward-compat shim
[Change] lmd_lifecycle.sh: remove dead stage_started meta-schema parser case
and initializer (no code ever wrote stage_started to any meta file)
[Change] lmd_scan.sh, lmd_quarantine.sh: remove unused local variables (_total
in _wait_workers_with_progress, fname in restore, _filtered_sess/_ql
in _batch_quarantine)
[Change] conf.maldet / maldet.1: correct post_scan_hook_timeout documentation — prior
text claimed a 5-second grace period before SIGKILL, but timeout(1) is invoked
without --kill-after, so a hook that traps SIGTERM will run indefinitely; pr#478
-- Bug Fixes --
[Fix] monitor: restore v1.6.6 ERE semantics for ignore_inotify entries;
introduce literal: per-entry prefix for opt-in escape of paths
containing regex metachars; issue #484
[Fix] monitor: ignore_paths now uses grep -E -vf (ERE) to match scan-mode
semantics; fixes silent regression from awk index() substring
filter introduced by monitor-mode redesign; issue #484
[Fix] ignore_inotify.defaults: re-add "scantemp." (trailing-dot-safe) for
ClamAV scan-temp directory noise; trailing dot prevents matching
user files named scantemplate.*; issue #484, #104, #431
[Fix] monitor: ownership filters (scan_ignore_root/user/group) unconditionally
excluded root-owned files in monitor mode; root-owned malware drops silently
produced 0 quarantine hits despite detection; gated behind new
monitor_scan_owner_filters toggle (default 0 = filters off); issue #485
[Fix] monitor: union-load ignore_inotify + ignore_inotify.defaults; new _monitor_load_ignore_inotify_union helper skips blanks+comments, dedupes across both files; issue #480
[Fix] --json-report list: path field parity with text mode; unified JSON escaping
across reports[]/active[]/stopped[]; dedup+escape rewrite eliminates O(N^2)
hang at ~20K sessions (82s → 1.7s); active[] gains lifecycle schema
(eta/workers/sig_version/progress); stopped[] gains elapsed; issue #482
[Fix] --json-report list: reports[] now globally sorted by started_epoch
(newest first) across TSV index + legacy-session passes (pre-fix emitted
index entries in append-order then legacy, producing visible date
inversions); reports[]/active[]/stopped[] all gain started_epoch integer;
stopped[] gains stopped_epoch; pass-2 glob skips legacy session.*.html
artifacts (fixes 12s+ hangs on installs with pre-on-demand-HTML files);
issue #483
[Fix] clamav_linksigs: guard mktemp staging failure to prevent writing signature
files into the filesystem root. When mktemp -d fails, the empty _staging
variable caused "cp -f ... /" as root; pr#478
[Fix] _json_escape_string: replaced sed pipeline with bash parameter expansion;
fixes FreeBSD breakage (sed="$sed -E" execve) and multi-newline escaping
for post_scan_hook JSON payloads; pr#478
[Fix] DEB: override_dh_fixperms restores 640/750 modes (72 files incl.
conf.maldet.hookscan.default, /etc/default/maldet, and 15 sub-library shell
files) after debhelper normalizes executables to 755 and non-executables
to 644; RPM uses %attr() and is unaffected; pr#478
[Fix] --test-alert digest: seed $tmpdir/digest.hook.alert cursor to _orig_size
so first-run tlog_read dispatches synthetic hits on fresh installs; prevents
real-hit leakage into test email and re-send on next real digest; pr#478
[Fix] Hook validation: world-writable detection used broken glob extraction that always
returned empty string; replaced with bash substring to correctly extract last octal
digit; pr#478
[Fix] Scan lifecycle JSON: workers field emitted unquoted "auto" string producing invalid
JSON; now resolves to integer before writing scan.meta; pr#478
[Fix] Report list: --format tsv silently returned text output; now returns explicit error
directing users to --report active for TSV output; pr#478
[Fix] Background scans (-b): scan process recorded parent shell PID ($$) instead of
actual forked PID (BASHPID); --kill/--pause/--stop targeted wrong process; scan.meta
now stores ns_pid separately from pid for correct liveness/signal delivery
[Fix] Scan progress: clear TTY progress line before stage-transition output to
prevent overwritten/garbled text when scan moves between stages
[Fix] -L/--list-active: elapsed time showed 0h 00m for running scans; now
computed live from scan start epoch instead of reading the completed-only
meta field
[Fix] Checkpoint resume: eval replaced with printf -v and options gated through
-co allowlist; rejects PATH, IFS, LD_PRELOAD from tampered checkpoint files
[Fix] CLI error messages (--user, -s, -q, -n, unrecognized option) now write to
stderr; -co validation failure now exits instead of continuing silently
[Fix] checkout: returns error when file/directory not found (was silent return 0)
[Fix] smtp-relay: guard html_file before cat on text-format emails (was cat "")
[Fix] JSON report list hang: index-first hybrid eliminates O(N) per-file glob on servers
without session.index; legacy plaintext sessions preserved
[Fix] Package manifests: add lmd_lifecycle.sh to RPM spec, DEB rules, symlink-manifest
[Fix] Scan pause: suppress console progress and elapsed timer during --pause; elapsed
excludes paused duration
[Fix] CSIG compiler: reject invalid && separator and universal subsigs in OR groups
[Fix] install.sh: detect supervisor and legacy monitor; graceful stop+restart on upgrade;
man page compression on fresh install; backup robustness; no longer kills inotify
monitoring; Slackware init per rc.NAME convention; preserve hookscan config and
pub/ state; issue #414
[Fix] purge() dotfile glob: replace * glob with find -delete to catch dotfiles in
tmp/quarantine/sess
[Fix] Quarantine: correct scan ID in report warning; TOCTOU mv exit code check; inode
naming replaces $RANDOM; batch signature name; colon truncation; -q batch summary
now prints to stdout; issue #399
[Fix] Temp file leaks: cleanup .alert_html.* after email dispatch; add clean.$$ and
suspend.users.$$ to _scan_cleanup() rm list
[Fix] Restore orphan: remove .info metadata after successful quarantine restore
[Fix] Scan: extract hitname from session TSV for hook output
[Fix] ClamAV: sig deployment permissions 644, empty sig cleanup, linksigs ordering,
version-gated .hsb; artifacts cleaned from data dirs when ClamAV disabled;
MD5 merge format corrected for custom user signatures; _count_signatures()
counts from on-disk files instead of runtime variables
[Fix] --report: recognize "latest" as alias for "newest"
[Fix] -e list: strip timezone offset from TSV session timestamps for consistent alignment
[Fix] get_remote_file: track temp files (.tmpf_get.*) and clean up at end of remote
operations
[Fix] sigup: write downloaded version to maldet.sigs.ver to prevent CDN desync
repeated downloads
[Fix] Scan engine: isolate worker temp files using parent PID namespace to prevent
concurrent scan conflicts
[Fix] scan(): exit 1 when all provided scan paths do not exist
[Fix] Hash scanning: handle md5sum/sha256sum backslash-escaped filenames
[Fix] Alerting: Slack migrated from deprecated files.upload API; Telegram /bot prefix;
token security via curl -K; genalert() state isolation; issue #387, #458, #461, #426
[Fix] Security: _safe_source_conf() allowlist (79 vars); conf.maldet 0640; dirs 750;
remote config RCE prevention; semver validation prevents directory traversal;
hookscan.sh validates ModSecurity filenames; --user validates against path traversal;
JSON injection prevention; email header injection prevention
[Fix] view_report(): on-demand text rendering from TSV; "newest" and empty scan ID
resolve to most recent session; issue #336
[Fix] sigignore(): moved to runtime copies in gensigs(); signatures no longer
irrecoverably lost between signature updates
[Fix] CLI robustness: 19 bare exit statements given explicit codes; -c, -x, -i, -q,
-n, -s, --web-proxy reject missing/empty arguments; issue #366
[Fix] FreeBSD: detection via uname -s; id -u (POSIX); restore() touch -t for mtime;
portable command cp/mv/rm throughout; scan_strlen guard (wc -L is GNU-only)
[Fix] clamselector(): logs warning on clamd test failure instead of silently switching;
no longer overwrites user scan_max_filesize; issue #452, #410
[Fix] cron.daily: flock lock leak to backgrounded scans; lockfile prevents overlapping
runs; config errors propagate to cron; issue #373
[Fix] find/ignore: ignore_file_ext, --exclude-regex, --include-regex, ignore_paths
converted to bash arrays; scan_ignore_user/group handles non-existent entries;
issue #446, #438, #450, #72, #335, #440
[Fix] Alert rendering: hit type regex handles {MD5}/{CSIG}/{SHA256} prefixes; empty
quarpath field shift in text reports; empty SUMMARY_* tokens in single-hit messaging
[Fix] tlog trim cursor unit mismatch: purge() and monitor_cycle() subtracted byte
count from line-count cursor; issue #227; replace ed dependency; issue #308
[Fix] Miscellaneous portability: mktemp replaces $RANDOM/$$; command -v replaces
which; grep -E replaces egrep; POSIX ':' chown separator; hardcoded binary
paths replaced with command -v discovered variables
[Fix] restore() and restore_hitlist(): return exit 1 on all error paths
[Fix] YARA rules no longer counted as active when no engine available (YARA(no engine))
[Fix] Quarantine restore: quote $file_mode in chmod to prevent misinterpretation
when .info file is corrupt or has fewer than 9 fields
[Fix] Packaging: tar fallback excludes pkg/ directory (was pkg/build only)
[Fix] RPM/DEB: packages now run signature update on fresh install (was missing);
migrate core sig files from tarball installs; link ClamAV sigs and signal
clamd reload; shared pkg-postinst.sh for install.sh post-install parity
[Fix] RPM/DEB %pre: defensive detection for dir-vs-symlink cpio conflict; install
no longer fails with "rename failed - Is a directory" when prior install.sh
or partial install left real directories at symlink-target paths
v1.6.6.1 | Feb 25 2025:
[Fix] find_recentopts incorrectly escaping find options to the right of ( -mtime .. -ctime ); previously normalized by eval; issue #440, pr#442
[Fix] persist configuration value inotify_docroot between upgrades; issue #439
v1.6.6 | Feb 19 2025:
[Fix] replaced eval usage in dynamic execution to improve security; thank you for responsible disclosure from barrebas
[Fix] malware notification emails to ignore inactive siteworx users; pr #425
[New] add reporting support for telegram channel; pr #378
[New] add statistics collection and sending to ELK; pr #359
[Fix] prune ignore_paths with find -prune; pr #423, issue #433
[Fix] suppress excessive clamav temporary file inotify alerts by adding '/tmp/.*scantemp.*' to ignore_inotify; issue #431, #104
[Fix] consistent cron.daily file sourcing to allow configuration overrides; issue #401, #115
v1.6.5 | Mar 27 2023:
[Fix] monitor mode white space detection; issue #354
[Change] event_log/clamscan_log now record year in timestamp; issue #352
[Change] -p|--purge will now trim the inotify_log; issue #350
[New] -E|--dump-report to dump reports to stdout; pr #362
[Fix] monitor mode will now fail to start if 'ed' is not installed; issue #350
inotify_log requires in-place inode pruning to prevent exponential growth
[Fix] inotify kernel support on debian11 checking only System.map; pr #398
[Fix] human-readable path not displaying on -a|--scan-all default path scan (/home); #407
[Change] default scoped scan adjusted from /var/www/html to /var/www to make sure we scope all www content; #404
[Fix] compare md5 on ignore_sigs between monitor mode cycles and only regenerate signatures on file changes; #397
[New] add detect_control_panel function to files/internals/functions to determine installed control panel; pr #409
[New] add get_panel_contacts to files/internals/functions to discover contact emails; pr #409
[New] add configuration options for From, Subject, Reply-To headers on alert emails; pr #409
[New] add flag to enable these alerts (requires email_alert to be enabled as well); pr #409
[New] add internal configuration to set the user alert template location; pr #409
[New] add a base template that will be used to create emails to control panel contacts; pr #409
[Change] ambiguous restore error modified to include file name
[Fix] adjusted ftp.rfxn.com checkout credentials; #390
[Fix] systemd unit file not copying properly; #371, #413
[Fix] monitor mode dependency failures on 'ed' not properly logging to be captured by unit file; #395
[Fix] newer versions of cpulimit explicitly enforce the usage of '--' to define where cpulimit options end; #395
v1.6.4 | Mar 18 2019:
[New] add quarantine_on_error variable to control quarantine behavior when scanner engines such as ClamAV encounter an error
[New] add support for slack alerts; pr #240 mostafahussein
[New] add ability to disable cron via conf.maldet; issue #260 / pr #300 , #304 sporks5000
[New] add cleaner rule for php.malware.magentocore_ccskim and an alias of as php_malware_hexinject for associated yara rule
[Change] update cron.daily for ispmanager5; pr #305 yogsottot
[Change] normalize variable naming of pr #300 , #304
[Change] validate cron_daily_scan is set; otherwise default to 1
[Change] update importconf for cron_daily_scan block
[Change] don't need "find" if given a file list; pr# 303 sporks5000
[Change] rename ambiguous internal variables related to user signatures
[Change] removed clamscan_return code capture from piped logic of clam(d)scan execution; now always capture return code, even on good exits
[Change] scan results now explicitly exclude any occurrences of files related to 'no reply from clamd' errors
[Change] add backward compatibility for renamed internals.conf variables
[Change] removed legacy $verbose tagging at the end of eout() calls
[Change] modified cleaner rules to set their own PATH scoping
[Change] file_stat() has been renamed get_filestat to match associated quar_get_filestat function naming
[Change] get_file_stat() will now grab md5 hash of files to avoid superfluous md5sum calls
[Change] added inotify elapsed run time to scan report output
[Change] adjust '-e|--report' output for etime value and spacing
[Change] force email_ignore_clean=1 to stop the most common email requested issue
[Fix] hitname not logging to quarantine.hist on manual quarantine run against scanid; issue #319
[Fix] typo in PR #300; missing '; then' on elif
[Fix] set default_monitor_mode to resolve issue #311 systemd service passing $default_monitor_mode as a literal string to the service
[Fix] sad mail/sendmail validation logic, fix issue #316
[Fix] normalized scan start time output in scan reports when inotify monitoring is used
[Fix] scan report list summary to always display an etime value, even if null
[Fix] ad-hoc clean calls from clean_hitlist() was not executing sigignore and gensigs functions causing clean tasks to fail due to missing variables; issue #203
[Fix] adjust semantics of comma and spaced variables being passed to '-co|--config-option'; pr #298 sporks5000
[Fix] modified quarantine_hits to force disable if clamdscan explicitly encounters a 'no reply from clamd' fatal error
[Fix] modified install.sh 'ps' execution to be BSD compliant
[Fix] clean function was not properly stripping {CAV} and {YARA} prefixes from signature names when executing cleaner rules
[Fix] clean function was not properly handling signature names with both underscores and periods
[Fix] refactored clean_hitlist() & clean() functions to resolve pathing errors when cleaning previous session hits; issue #203
[Fix] ignore_inotify file exist/empty file negative match; issue #330
[Fix] operator issue cron.daily #331
[Fix] install.sh $ver required major numbering; renamed to ver_major so that session preservation semantics continue to work
v1.6.3 | Sep 01 2018:
[Fix] ensure clamscan_max_filesize is always set; pr #296
[Fix] remove escaping from inotifywait exclude regexp; pr #246 issue #205
[Fix] always set a value for monitor mode systemd unit; pr #257
[Fix] quar_get_filestat variable collisions during restore operations
[Fix] quarantine files could be prematurely deleted, during 'cron.daily/maldet', on distributions where the 'mv' command
preserves origin file mtime; call 'touch' on quarantined files to set current mtime post-move to quarantine path; issue #294
[Fix] update tlog inotify tracking file before trimming to prevent rescan loop; pr #292
[Fix] revert pruning empty lines from signature files to 1.6.1 behavior
[Fix] usage semantics of cd'ing to a wildcard path on newer versions of Bash were causing version updates to fail; we now explicitly
'cd' to maldetect-${upstreamver}
[Fix] spelling corrections; pr# 269
[Change] update importconf text to reflect monitor mode on systemd behavior
[Change] on restore actions, reset restored files to original mtime value
[Change] increase default remote_uri timeout from 10s to 30s
[Change] increase default remote_uri tries from 3 to 4
[Change] added base_domain variable to internals.conf
[Change] cleanup .tgz/.md5 files on version updates mid-flight to prevent potential 'cd: too many arguments' errors
[Change] trim inotify log from beginning instead of end of file; pr #292
[Change] user mode scanning no longer scans system temporary paths; issue #283
[Change] improve regexp of scan start time values for '-e|--list' output
[Change] added '--beta' flag to '-d|--update-ver' to support pulling down beta release of LMD
[Change] stage v1.6.3 release; update version and date stamps
[Kudos] Thank you to those that contributed pull requests and issues during this release cycle. PR contributions from:
sporks5000
jsoref
Joshua-Snapp
mkubenka
jkronza
AnnopAlias
v1.6.2 | Jul 13 2017:
[Fix] signature updates using get_remote_file() would incorrect write temporary update files into /; issue #242
[Fix] added 'which curl' and 'which wget' for variable scoping of binary locations into internals.conf; issue #237
[New] added support to send email through 'sendmail' binary as alternative to 'mail'; pr #241 & issue #238
v1.6.1 | May 28 2017:
[New] added conf.maldet option cron_prune_days to configure cron.daily pruning max age of quar/sess/tmp data; issue #197
[New] added curl support, as new default, into get_remote_file; wget support is preserved secondary to curl; issue #200
[New] added --force option on -u|--update-sigs
[New] added --force option on -d|--update-ver
[New] added empty lines cleaner for runtime signatures and sorting of hdb for better performance; pr #223
[Change] modified default prune interval of quarantine/sess/tmp data from older than 7d to 21d
[Change] set email alerts to disabled when -z $mail / issue verbose warning on CLI; issue #220
[Change] scan_export_filelist feature had no real need to be limited to just cron runs;
modified so when set, it will export find results for all '-r|--recent' scans
[Change] updated help and README to reflect '--force' option on '-u|--update-sigs' and '-d|--update-ver'
[Change] post-change to get_remote_file(); signature version file was truncating with tmp file for maldet-clean
[Change] replaced all calls of wget with get_remote_file()
[Change] refactored get_remote_file() to be more generic / not depend on wget
[Change] increased default values for wget --timeout from 5 to 10 seconds
[Change] replace egrep with posix 'grep -E'; direct invocation of egrep/fgrep is deprecated; pr #214
[Fix] modified sourcing of conf files and order of precedence in mald…et.sh init script to properly
treat default_monitor_mode being defined in conf.maldet; issue #224
[Fix] escape quotes within eval md5sum command as fix for issues #230 and #216
[Fix] test condition for systemd was generating unary errors on older versions of bash; pr #36
[Fix] systemd based systems were skipping addition of sysconfig entry; pr #36
[Fix] install.sh find operation to prune old install backups was generating error when no previous installs existed
[Fix] wgetopt was single quoted making the variables inside of it strings, set double quotes
[Fix] potential out of memory issue while scanning a large set of files on native LMD scanner; pr #223
[Fix] -f option issue with relative path message; pr #223
[Fix] issue with checkout of relative file path for non root user; pr #223
v1.6 | Mar 17 2017:
[New] added curated set of YARA webshell & malware signatures for use with ClamAV >= 0.99b
[New] added cleaner rule 'VisitorTracker.Mob'
[New] added cleaner rule 'js.inject.fakejquery02'
[New] added support for 'froxlor' to cron.daily execution
[New] added support for 'vestacp' to cron.daily execution
[New] added support for 'ispconfig3' to cron.daily execution
[New] added support for 'DTC' to cron.daily execution
[New] added '$confpath', '$varlibpath' and '$libpath' for FHS separation
[New] moved compatibility (legacy) variables out of internals.conf into compat.conf
[New] added support to pull configuration variables for cron executions from 'sysconfig/maldet'
[New] added Debian derivatives sysconfig and initd compatibility for function sourcing and subsys locking
[New] added LSB tags to init script
[New] added capability of moving public scan path with $userbasedir variable
[New] manpage added and setup default with install.sh execution
[New] added support for clamd running as an unprivileged user through clamdscan w/ --fdpass options
[New] added --wget-proxy CLI option for http(s) proxy support
[New] added clam(d)scan_extraopts variables to internals.conf for appending extra CLI options on clam(d)scan;
these values can also be defined in sysconfig or cron/exec based config files and on CLI
[New] sysconfig support through '/etc/sysconfig/maldet' or '/etc/default/maldet', system dependant, to
allow easier configuration overrides; all conf.maldet and internals.conf variables supported
[Change] file stat calls replaced with function file_stat
[Change] stat calls are now (Free|Net)BSD compatible through file_stat function
[Change] report listing, '-e|--report list', now displays scan run time
[Change] scan reports and cli outputs once again display simplified path definitions instead of expanded paths
[Change] unified all clamav selection logic for data paths, running clamd processes, clam(d)scan CLI options etc...
into a single function, clamselector(); this will make clam behavior more predictable across all functions
[Change] added subdomains path for ISPConfig to cron.daily
[Change] corrected variable naming semantics for import_*_(md5|hex)_url parameters
[Change] monitor mode now identifies inotifywait processes based on a string pattern unique to maldet
to avoid conflicts with any other inotifywait processes
[Change] added wget_proxy variable for us in sysconfig and conf.maldet options
[Change] YARA-LMD curated signature set will now be included with signature updates
[Change] differentiate signature hits for YARA with '{YARA}' signame prefix
[Change] inotify_docroot now accepts comma or white spaced list of paths under user root to monitor
[Change] removed absolute path usage from 'pidof'
[Change] drop unneeded usage of shebang from sourced configuration files
[Change] modified shebang usage with 'env' prefix for portability
[Change] temporary path usage now consistently using $tmpdir value
[Change] scan paths must now be absolute paths
[Change] modified init script stop function for Debian derivatives
[Change] improved history tracking with proper date stamps, more verbose quarantine history logging and storing
into more explicitly named files '$sessdir/hits.hist' and '$sessdir/quarantine.hist'
[Change] added scan_days value to cron.daily allowing customization of the date range scanned by daily cron
[Change] replaced remaining absolute calls to sigdirs with '$sigdir'
[Change] added Debian derivatives support for MONITOR_MODE checks
[Change] updated cron.daily to provide for a custom execution file and modified custom config file into
'cron/conf.maldet.cron' and 'cron/custom.cron'
[Change] install.sh cased variable on find execution
[Change] symlink hookscan.sh to modsec.sh for pre-v1.5 compat
[Change] added '^/tmp/clamav-.*' to ignored paths where ownership matches clamd process
[Change] preserve custom cron configuration files on upgrade
[Change] hookscan.sh was calling LMD using legacy, deprecated, '--config-option' options
[Change] normalize installation path variable between LMD proper and installation scripts
[Change] reduced redundant path definitions
[Change] added test for main.cvd and main.cld in determining clamav signature paths
[Change] README changes to reflect new cron customization setup
[Change] added attempting passive ftp when active fails for malware checkout uploads
[Change] .ca.def configuration template renamed importconf and now copied over during installation to
'internals/importconf'
[Change] new versions of 'chown' don't support use of . (dot) to separate user and group
[Change] find option regextype is now dropped on FreeBSD for compatibility
[Change] scan.tpl reporting template handles column spacing on filenames with spaces better
[Change] CLI usage semantics of --include-regex and --exclude-regex now consistently passing to 'find' command
[Change] moved all internal field separator line break modifications to lbreakifs()
[Change] quarantine .info file is now field separated with colon symbol (:)
[Change] quarantine .info file value ordering has been modified
# owner:group:mode:size(b):md5:atime(epoch):mtime(epoch):ctime(epoch):file(path)
[Change] record_hits() now writes file mode and file times (a|m|c) into hits history file
[Change] 'eval' is now used as a prefix on the 'find' command to better handle the complex set of options passed to 'find'
and avoid globbing, splitting and other bash'esque semantic issues
[Change] modified mkpubpaths cronjob to execute every 5 minutes instead of 10
[Change] public mode scanning errors are now more verbose
[Change] updated README to reflect required modsec >=2.9 variable 'SecTmpSaveUploadedFiles'
for upload scanning
[Change] hookscan.sh (modsec.sh) now checks for variable override file at conf.maldet.hookscan
[Change] added use of sed flag -E for FreeBSD compatibility with GNU sed usage
[Change] clamscan will now respect scan_max_filesize value instead of hardcoded 5M
[Change] default scan_max_filesize increased from 768k to 2048k
[Change] clamscan max-scansize for archive depth set as scan_max_filesize*2
[Fix] improved special character argument escaping for -a|-r options that could have caused arbitrary command
executions in environments where LMD was allowed to be called by non-root users and/or set-uid/gid wrappers
[Fix] FreeBSD calls to 'md5 -q' were being incorrectly escaped causing file names to never pass and return valid
md5 hash string; corrected by preprending 'eval' to the md5 command callouts.
[Fix] corrected typo with import_* variables causing configuration imports to fail
[Fix] suppress eout() output for certain import_*() and get_remote_file() calls; this was causing
false-positive hits for modsec integration
[Fix] install.sh may not have preserved certain variables on upgrade
[Fix] clamdscan was running as a non-root user, would generate lstat errors for all file find results
leading to potential false positive hit/quarantine
[Fix] the permissions of the $tmpdir path can cause clamd when running as a non-root user to fail on
startup due as a result of lstat errors on the custom user signature files stored under $tmpdir
[Fix] clamd.conf configurations containing Follow(File|Directory)Symlinks set to false results in
the rfxn.*/lmd.user.* links causing clamd startup failures
[Fix] suppress error output to cli for customer user signature files when they do not exist
[Fix] uninstall.sh now cleans up signature files from clamav data paths
[Fix] corrected invalid matching against clamdscan binary when clamd was running as non-root user
[Fix] inotifywait on Ubuntu12 doesn't support the '-o' and '-d' option; modified to send stdout to logfile
for better compatibility
[Fix] conditionally test for vz container and disable use of ionice which is not support in vz containers
[Fix] '-k|--kill-monitor' would under certain circumstances leave zombie processes
[Fix] monitor_cycle() could lead to memory depletion due to infinite loop cycle calls
[Fix] uninstall.sh was not shutting off monitor mode on uninstall
[Fix] legacy variable suppress_cleanhit references updated to email_ignore_clean
[Fix] email alerting broke during an iterative update due to order of precedence change of how configuration
files were loaded and compatibility (legacy) variables being set before main conf.maldet was loaded;
caused by FHS refactoring
[Fix] installation upgrade configuration importer was not properly executing after FHS refactoring during an
iterative update
[Fix] issue #167 certain variables not being preserved on importconf execution, updated 'compat.conf'
[Fix] custom signature runtime files could grow exponentially in monitor mode
[Fix] make '--mkpubpaths' option cross-platform compatible (debian, rh, bsd)
[Fix] replaced usage of 'awk' on file name sensitive variables with 'cut' and/or better scoped field separator for awk
[Fix] double quote wrapped file name variables properly on restore*() functions
[Fix] quarantine .info files were not properly recording source file atime,mtime,ctime values manual quarantine calls
[Fix] user supplied paths to CLI are now better handled if they contain special characters
[Fix] multiple user supplied paths to CLI would generate an error if the first path contained a space and
subsequent paths did not
[Fix] commit c8a1279 introduced bug where clamav could be fed zero sized signature files resulting in fatal exit
[Fix] public mode scanning will now properly error if mkpubpaths paths do not exist
[Fix] hookscan.sh (modsec.sh) will now default to not using clamav if clamd is not running
[Fix] though functional, public mode scanning would result in permission errors on console due to pathing issues with
history tracking files
[Fix] clam(d)scan was not respecting values in 'ignore_sigs' file, this has been corrected for both CLI and monitor mode
[Fix] addition of prefixing eval to find command required certain values to be escaped differently for proper function
of '-r|--recent'
[Fix] util-linux 2.23 supports 'column' command with '-o' but earlier versions do not, resulting in scan reports
generating empty hit lists
[Fix] importconf was setting invalid vars for custom signature imports; correct variables are import_custsigs_md5_url
and import_custsigs_hex_url
[Fix] multiplying maldet monitor processes due to 'ps' command expansion under parent bash process on CentOS6
[Fix] added default installation path to ignore_inotify to prevent monitor looping when '/' is scoped into
monitoring mode; results in notify log filling disk space
[Fix] importconf was not importing the value for import_config_url
v1.5 | Sep 19 2015:
[New] added -f|--file-list CLI option to allow user supplied run-time file list for scanning
[New] added -i|--include-regex CLI option for run-time path/file inclusion based on posix-egrep regular expressions
[New] added -x|--exclude-regex CLI option for run-time path/file exclusion based on posix-egrep regular expressions
[New] added support for custom md5/hex signatures with preservation across signature and version updates, files located at:
sigs/custom.md5.dat
sigs/custom.hex.dat
[New] custom signatures perform run-time conversion into clamscan compatible format on systems that use clamscan engine
[New] new md5 signature format (md5v2) now includes file size that an md5 hash was derived from in format of:
hash:filesize:signame
[New] added support for custom cleaner rules to be executed on clean events, file name format of
"clean/custom.signame"; rules are preserved across signature and version updates
[New] added support for clam(d) engine when running in inotify monitoring mode
[New] added URL import feature for global configuration overrides using import_config_url variable in conf.maldet
[New] added URL import feature for user custom signatures using import_custsigs_md5_url & import_custsigs_hex_url variables in conf.maldet
[New] added set of defined exit codes for errored exits(1), successful runs with hits(2), successful runs with no hits(0)
[New] added uninstall.sh script to maldetect installation path
[New] added md5 hash verification of signature and version update downloads
[New] added scan_cpunice option to control CPU priority value of all scan operations such as find, clamscan etc.. (default 19)
[New] added scan_ionice option to control IO priority value of all scan operations such as find, clamscan etc.. (default 6)
[New] added autoupdate_signatures/autoupdate_version options to control daily cron based signature/version updates
[New] added autoupdate_version_hashed option to control validating hash of maldet executable against upstream version
[New] added support for virtualmin to cron.daily scans
[New] added support for ispmanager to cron.daily scans
[New] added support/detection of clamdscan to leverage memory preloaded signatures and multi-threaded scanning
[New] added scan_find_timeout option which controls the maximum execution time, in seconds, for the find command to generate a file list
[New] added scan_ignore_root option to exclude root owned files from scans
[New] added scan_ignore_user and scan_ignore_group options which allow for the exclusion of specified user and group names from scans
[New] added scan_export_filelist option allowing for daily scan of recent added/modified files to be exported to a static path
[New] added sourcing of of conf.maldet.cron into the cron.daily task which allows for cron specific configurations
[New] added inotify_reloadtime which controls the time at which inotify watcher will reload LMD configuration data
[New] added support for comma space (,) path list on CLI
[New] added reload option for monitor mode to invoke forced configuration reload (-m|--monitor reload)
[New] added maldet init script for monitor mode with $default_monitor_mode conf.maldet variable
[New] added usage of /etc/sysconfig/maldet for configuration of monitor mode init/systemd options, overrides conf.maldet
[New] added support for 'cpulimit' usage, when installed, through scan_cpulimit and inotify_cpulimit configuration variables
[Change] increased randomness of quarantine temporary file names
[Change] added atime,mtime,ctime since epoch values into quarantine info files
[Change] monitor mode now supports all existing ignore options as well as enforcing minimum/maximum file sizes
[Change] monitor mode now supports hot configuration reloads by touching reload_monitor under installation path (e.g: touch /usr/local/maldetect/monitor_reload)
[Change] modsec.sh has been renamed to hookscan.sh and more generic hook based scanning conventions set
[Change] hookscan.sh will now autodetect if clamdscan is running and perform scans through clamd when appropriate
[Change] hookscan.sh will now provide more verbose output on malware hit events
[Change] hookscan.sh now explicitly disables scanning of temporary paths, ensuring only requested file/paths are scanned
[Change] install.sh now gracefully handles upgrades when monitoring mode is enabled by restarting monitor mode
[Change] improved handling of single file scans which should now behave as expected
[Change] explicitly removed the inclusion of tmpdir paths during single file scans
[Change] automagically remove empty lines from ignore files
[Change] reordered configuration file, expanded on variable descriptions, overall attempt to simplify/streamline conf.maldet
[Change] installer symlinks LMD signatures into known/existing ClamAV paths to ensure signatures are loaded into memory by clamd
[Change] installer issues SIGUSR2 to any running clamd processes to force reload of signature databases
[Change] cron.daily signature updates issue SIGUSR2 to any running clamd processes to force reload of signature databases
[Change] cron.daily signature/version updates sleep random interval 1-999 secs before contacting upstream rfxn.com servers to reduce cdn load
[Change] modified clamscan database path checks to support cPanel >=11.40 RPM clamAV connector RPM's
[Change] modified location of statistical data files from tmpdir to sessdir making tmpdir a stateless path that can be purged at anytime
[Change] when clamscan engine is enabled scan_max_filesize value is now set dynamically based on the largest known file in the md5v2 signature set
[Change] modified e-mail based alerts to source from an e-mail template file at .email.template
[Change] clamscan execution command logged to logs/clamscan_log to make debugging clamscan errors easier
[Change] clamscan stderr/stdout output now pipes to logs/clamscan_log and if clamscan returns an error code (2), flag with an appropriate
error message to check the clamscan_log file for more details
[Change] ambiguous variables renamed for better consistency and more logical naming conventions, documented in CHANGELOG.VARIABLES
[Change] modified sessionid values to derive from YYMMDD instead of MMDDYY and adjusted human readable report START/END date to include year value
[Change] modified view_report output to sort output on unix time of scan start times
[Change] signature updates now download as a single file tgz to reduce bandwidth usage and request load on upstream cdn
[Change] modified signature update function for additional error checking and better handling of zero sized signature downloads
[Change] modified version update function for additional error checking and better handling of zero sized file downloads
[Change] modified '-e|--report list' output include total files scanned, hits and cleaned results, reversed output order and
consistent column spacing (column -t)
[Change] moved tlog executable out of inotify/ path, changed inotify_log path to logs/, removed inotify directory
[Change] created logs/ path, moved event_log path to logs/
[Change] modified previous wget timeout values of 3s timeout & 3 retries to 5s timeout & 3 retries
[Change] wget timeout and retry attempts are now configurable through internals.conf wget_timeout & wget_retries variables
[Change] removed file type check on native LMD stage2 hex scanner which was part of legacy code and no longer needed
[Change] removed verbose progressive scan output for native LMD scanner as performance penalty was unreasonable
[Change] replaced usage of tmpwatch with find in cron.daily for temporary path pruning
[Change] removed internals.conf from version check hashing for installation version updates (-d|--update-ver)
[Change] cron.daily now tests for directadmin and scans appropriate user domain paths
[Change] directory checkout uploads limited to maximum of 50 files
[Change] added tmpdir_paths option to explicitly scan known temporary (world-write) paths on all scan types
[Change] updated example ModSecurity rule in README file for compatibility with ModSec 2.7 which now requires
every rule, even hooks, to have a rule ID
[Change] -r|--recent scan now uses mtime and ctime, instead of just mtime, to find recently changed/modified files
[Change] LMD v1.4.2+ will now use the new md5 v2 signature format and make direct requests on signature
updates to the appropriate upstream file (md5v2.dat); old format, md5 v1, preserved in signature
releases for compatibility of pre-1.4.2 releases
[Change] modified hexfifo.pl & hexstring.pl to accept user supplied value for path to hex signature file
[Change] install.sh now deletes LMD backup installation copies older than 30days
[Change] references to www.rfxn.com for remote signature and version updates now query cdn.rfxn.com
[Change] cleaner rules are now executable scripts in which infected files are passed as an argument ($1)
allowing for a diverse set of cleaner rule options apart from the previous sed only setup
[Change] converted current cleaner rules to new executable scripts format
[Change] checkout uploads now store malware in the filename format of (hostid is an anonymous md5 identifier):
$hostid.$RANDOM.$filename.[ascii|bin]
[Change] inotifywait from inotify-tools is no longer packaged with LMD, it should be downloaded in binary or
source form from:
https://github.com/rvoicilas/inotify-tools/wiki/
binary versions are also available from dag repo at:
http://pkgs.repoforge.org/inotify-tools/
[Change] internals.conf will now attempt to detect the path to inotifywait from $PATH
[Change] inotify max_user_watches was static set to 128, now configurable with inotify_user_watches
[Change] inotify values for max_user_instances|watches will first be checked and only modified if the existing
values are lower than what maldet requires
[Change] modified error output for missing inotifywait to display URL to inotify-tools github page
[Change] modified default scan_hexdepth value to 65k as a result of improved scan efficiency in native scanner engine
[Change] added backwards compatibility for all pre-v1.5 configuration options however they should be considered deprecated and will be removed in the future
[Change] expanded on EICAR test signature support for native LMD scanner engine to better facilitate testing of functional installed signature set
[Change] added scan/find elapsed execution time values to scan report and cli output
[Change] relocated internal files into $inspath/internals/
[Change] created generic clean_exit() function to handle file cleanups on all fatal exist and replaced many random rm -f calls with it
[Change] moved all pre/post actions into a prerun() and postrun() functions
[Change] moved statistical logging to record_hits() function
[Change] quarantine() function borrows stat file data from record_hits to reduce calls to stat
[Change] more extensible cleaner rules with additional input arguments:
$1 file path, $2 signame, $3 owner.group, $4 file_chmod, $5 file_size, $6 file_md5
[Change] added additional fields file_size and file_md5 to quarantine info file
[Change] added caching support for import_config_url with import_config_expire to control expiry interval
[Change] stricter handling of variable definitions which contain dynamic variable values
[Change] modified daily cron recent range from 2 to 1 as mtime/ctime values are n*24h, as such value of 1 is equal to two days
[Change] modified daily cron to use comma spaced path lists instead of multiple maldet executions
[Change] changed quarantine malware cleaning default value to 0
[Change] use of clamav engine output statement now more verbose
[Change] previously LMD only linked clamav signatures into clamav data paths on install, this is now done after each signature update
[Change] maldet.sh init script exites code 1 on status check when maldet monitor mode is not found running
[Change] monitor mode now invokes every 15 seconds, legacy installations will preserve 30 second cycle timing
[Change] modified shebang to use env bash for portability
[Fix] when clamdscan was running as a non-root user, would generate lstat errors for all file find results leading
to potential false positive hits/quarantines
[Fix] the permissions of the $tmpdir path can cause clamd when running as a non-root user to fail on startup due
as a result of lstat errors on the custom user signature files stored under $tmpdir
[Fix] clamd.conf configurations containing FollowDirectorySymlinks/FollowFileSymlinks set to false results in the
rfxn.* and lmd.user.* links causing clamd startup failures; corrected by updating clamav_linksigs() to copy
signatures into clamav data paths instead of linking them
[Fix] inotify monitor execution now properly passes ionice configuration value
[Fix] monitor_paths was not being preserved on version updates
[Fix] record_hit() was not being invoked outside of clamscan based events
[Fix] monitor.pid file would potentially have an incorrect pid written to it on each execution of monitor_check()
[Fix] quote syntax error in scan.etpl
[Fix] help output for -k|--kill-monitor incorrectly referred to --kill instead of --kill-monitor
[Fix] inotify_user_instances was defined in internals.conf incorrectly as inotify_user_watches
[Fix] tlog executable was not being set +x during installation
[Fix] install.sh was attempt to create default event_log while the parent directory did not yet exist
[Fix] invalid find expression was causing find to return directory paths on recent scans
[Fix] OSTYPE env checking was not properly matching on all FreeBSD versions
[Fix] renamed alert() to genalert() to avoid builtin function conflict on Ubuntu
[Fix] corrected -r|--recent scan mode trap on SIGINT (CTRL+C) not calling trap_exit() for cleanup actions
[Fix] modified native LMD scanner to better leverage bash internal field separator for handling of paths with spaces
[Fix] modified all calls to system executables to use paths derived from $PATH
[Fix] suppressed ignore signature count being displayed when calling with --modsec
[Fix] set modsec.sh to use /bin/bash as interpreter instead of /bin/sh for compatibility
[Fix] removed MAILTO & SHELL variables from crons which were causing crond 'bad minute' errors on some systems
[Fix] quoted extension values from ignore_file_ext input to provide consistent behavior
[Fix] added trailing slash '/' to all cron.daily scan (find) paths to properly handle symlinked paths
[Fix] install.sh now links LMD clamav signatures into all clamav data paths it finds instead of just the first
[Fix] clean() function was improperly exiting after first file hit clean attempt and ignoring all other hits
[Fix] set interpreter in uninstall.sh to /bin/bash instead of /bin/sh for better compatibility
[Fix] modified psa scan paths to pull in top level and sub domain content
[Fix] corrected invalid matching against clamdscan binary when clamd was not available
v1.4.2 | Feb 25th 2013:
[New] detection and alerting of libkeyutils root compromised libraries
[Change] cron.daily now tests for directadmin and scans appropriate user domain paths
[Change] removed temporary paths /var/tmp, /tmp, and /dev/shm from cron.daily which are
now added explicitly to all scanning paths / modes
v1.4.1 | Nov 20th 2011:
[Change] rfxn.com ftp server moved and anonymous FTP checkout uploads changed
[Change] modsec.sh force sets clamav_scan=0 as native LMD scanner engine is faster on
single / small file sets
[Fix] correct plesk if statement added to to daily scan cronjob
[New] added -U|--user to force execution under defined user, ideal for restoring user
quarantined data or viewing user reports
e.g: maldet --user nobody --report
e.g: maldet --user nobody --restore 050910-1534.21135
[New] added public_scan variable to conf.maldet to control enabling of public mode
scanning, disabled by default
[New] added cron.d/maldet_pub cronjob to populate public user paths when public mode
scanning is enabled; does nothing when disabled
[Change] README file updated, had fallen behind on CLI usage help details
[New] added -co|--config-option for defining conf.maldet options on the CLI
[Fix] README, COPYING.GPL and CHANGELOG are now properly copied into the installation path
[Fix] version header in config import template was incorrect
[Fix] value of email_ignore_clean is now properly preserved on version upgrades
[New] added modsec.sh to allow for easy calls from mod_security2 inspectFile hook
[Change] autodetect executing uid and define public mode scanning variables
[New] added public mode scanning which redefines tmpdir, sessdir, quardir to pub/username/
directory tree for user initiated (non-root) scans
[Change] installation permissions changed to 644/755 for public mode support
[Change] revised (gz)base64 rules to be more specific thus reducing false positives
[Fix] tlog was set to use /bin/sh which breaks usage on systems with default shells other
than bash
v1.4.0 | Apr 17th 2011:
[Change] default editor now inherited from $EDITOR
[New] clamav signatures update through sigup(), -u|--update
[New] cleaner rules update through sigup(), -u|--update
[Change] added error checking for missing or corrupted signature files
[Fix] monitor_cycle() now properly trims inotify_log
[Fix] version dates in CHANGELOG for 1.3.8 -> current had 2010 instead of 2012
[New] added -b|--background flag to execute scans in background
[Change] cron.daily now uses the -b flag for background scanning
[Change] wget calls now use the --referer option to broadcast local LMD version
[Fix] replaced stray references of absolute install path with the install path variable
[New] stage2 (HEX) scanner now supports use of named pipe (FIFO) for passing file hex contents,
enabled by default, provides better performance with larger depth analysis of files
[New] added hex_fifo_scan & hex_fifo_depth variables to conf.maldet for fifo hex scanning
[Change] -c|--checkout now supports directory paths
[Change] -r|--scan-recent and -a|--scan-all now supports single file scans
[Fix] replaced absolute path to nice on inotifywait exec to which located variable value
[Change] added error checking for all internally required binaries e.g: wget, find, od etc...
[New] detection of ClamAV clamscan binary and usage as default scanner engine; when detected,
clamscan is executed on scan file lists using rfxn.com LMD clamav-compat sigs
[Change] added OSTYPE check for differentiating md5 sum binaries on linux and FreeBSD
[Change] added OSTYPE check on monitor mode to disable on FreeBSD, pending kqueue alternative
to inotifywait
[Fix] revised od flags for FreeBSD support
[Fix] ignore_inotify now properly interprets extended posix regexp as ignore parameters
[Change] added sample ignore values into ignore_inotify along with sane defaults to
ignore common noisy files
[New] added statistical analysis for string length to identify threats based on the longest
uninterrupted string within files, common of obfuscated code (e.g: base64, gzip etc...)
[New] added string_length_scan & string_length variables to conf.maldet for strlength scanning
[Fix] ignore_file_ext has been readded and now correctly ignores files based on extension
[Fix] replaced absolute path to mail with which located variable value
[Fix] lmdup() now properly errors out when rfxn.com web server is offline
[New] added clamav_scan variable to conf.maldet to toggle clamscan detection
[New] Full compatibility under the following distros has been verified :)
- FreeBSD 9.0-CURRENT
- RHEL/CentOS 5.6
- RHEL 6
- Fedora Core 14
- OpenSuse 11.4
- Suse Linux Enterprise Server 11 SP1
- Ubuntu Desktop/Server 10.10
- Debian 6.0.1a
[Change] updated README file for new features & vars, sample ignore usage, revised features
and updated cymru hash statistics
[Fix] relaxed grep for inotify sysfunctions to just inotify_ on System.map file
[New] can now pass list to -e|--report to view all available scan reports
e.g: maldet --report list
[New] can now pass an e-mail address to -e|--report to email a specific report
e.g: maldet --report SCANID user@domain.com
[New] added email_ignore_clean variable to suppress alerts where all hits are cleaned
v1.3.9 | Mar 16th 2011:
[Fix] ignore files are now properly imported on version updates
[Change] cron.daily now checks for version updates
[Fix] hexdepth greater than 65Kb caused an 'argument list too long' error with hexstring.pl
which would fail-clean any malware on hex checks
[Change] default hex depth increased to 61440 as there was an increasing margin of error on
missing threats due to them falling outside the default hexdepth; will add offset
option to signatures in the near future
[Change] updated cymru hash statistics in README file
v1.3.8 | Jan 30th 2011:
[Fix] revised inotify tracking log file to properly rotate instead of growing indefinitely
v1.3.7 | Nov 27th 2010:
[Fix] package ownership at some point got set to uid 501 instead of root
[Fix] daily cronjob now checks ps output for inotifywait proc instead of pidof
[Fix] monitor mode users would exit prematurely if a user home path did not exist
[Fix] a file hijacking race condition existed with quarantine mode restore function
[Fix] inotify max_user_instances value was being set to a value that would cause inotifywait
to fail
v1.3.6 | May 21st 2010:
[Fix] restore option will now handle session based restores for quarantines that
were manually invoked with -q|--quar SCANID
[Fix] session data gets recreated if it disappears during scan
v1.3.5 | May 18th 2010:
[Fix] tlog now handles data that logged between 0bytes and first wake cycle
[Fix] monitor_check now properly handles CREATE,ISDIR events
[Change] --alert-daily|weekly alerts have been changed similar to manual alerts
[Fix] cleaner was not properly running on monitor_check calls to scan files
[Fix] quar_suspend was not properly running on monitor_check calls to quar()
[Change] monitor tracker files now pass through trim_log to avoid oversizing
[Fix] monitor_check now properly handles path names with spaces
[Fix] monitor_check was throwing nx file/directory error for monitor.pid
[Fix] older bash versions were having trouble with the [[ =~ ]] regexp search
[Change] set all script files from shebang/bin/sh to shebang/bin/bash
[Change] --alert-daily|weekly will now only send alerts if hits were found
[New] -d|--update-ver now compares file hashes to determine update status
[Fix] suspend events were not properly being added to monitor alerts
[Change] all alerts have had spacing changes to make them more readable
[Fix] signature names now properly list for daily|weekly alerts hit list
[Fix] monitor_check will now recursive monitor newly created directories
[New] monitor daily|weekly alerts now save as a pseudo scan report with SCANID
[Fix] monitor reports now generate properly when quar_hits=0
v1.3.4 | May 16th 2010:
[Fix] cleaner function was not properly executing under certain conditions
[Change] additional error checking/output added to the cleaner function
[Change] default status output of scans changed for better performance
[New] added ignore_inotify for ignoring paths from the monitor service
[Change] updated ignore section of README
[Fix] backreference errors kicking from scan_stage1 function
[New] -d|--update-ver option added to update installed version from rfxn.com
[Change] updated short and long usage output for update-ver usage
[Fix] -k|--kill-monitor now properly kills only the inotifywait/monitor pid's
[Fix] monitor_cycle function now correctly stores its pid in the pidfile
[Fix] files with multiple events in the same waking cycle are only scanned once
[Change] install.sh now symlinks maldet executable to /usr/local/sbin/lmd
v1.3.3 | May 15th 2010:
[Fix] quarantined files were not properly dropping owner
[New] signature based, rule driven, cleaner component added
[New] base64.inject cleaner rule
[New] gzbase64.inject cleaner rule
[New] -n|--clean SCANID option added to batch clean scan all files from a scan
[Fix] made default install file/path permissions more strict (750/640)
[New] install.sh now preserves conf.maldet settings
[New] install.sh now links backups of old installation to INSTALL_PATH.last
[Fix] install.sh now properly imports session data from previous install
[New] -s|--restore can now take a SCANID to batch restore all files from a scan
[Change] improved the layout of conf.maldet; more scan options and commenting
[New] added quar_susp_minuid option for suspend user minimum user id
[Fix] inotify monitor now properly acts on MODIFY,MOVE_TO,MOVE_FROM states
[Change] inotify monitor now can take a list of paths or file for path input
[Change] inotify monitor now has no default use, must specify USER|FILE|PATHS
[Change] revised short and long usage output for new options/usage changes
[Change] inotify monitor now spawns only one process for all monitored paths
[Change] inotify monitor sets max_user_instances to processors*2
[Change] inotify monitor sets max_user_watches to inotify_base_watches*users
[Change] migrated all inotify options from internals.conf to conf.maldet
[New] added inotify_base_watches to conf.maldet for max file watches multiplier
[New] added inotify_nice to conf.maldet for run-time prio of inotifywait
[New] added inotify_webdir to conf.maldet for html/web root only monitoring
[Change] extensive format change to README
[Change] rewrote inotify section of README to reflect the many changes
[New] added cleaner section to README
[Change] -q|--quarantine now calls cleaner if quar_clean=1
[Change] -n|--clean can now do in place cleaning without quarantine
[Fix] cleaner function was not properly executing under certain conditions
v1.3.2 | May 13th 2010:
[New] added ignore files: ignore_paths , ignore_sigs
[Change] ignore_sigs is processed as a pre-scan component before all scans
[Change] revised README file to include details on new ignore options
[Change] signature counts now displayed pre-scan and post-update
[Change] install.sh now runs --update after installation
[Fix] -p|--purge now properly clears session state data
[New] added [ SIGNATURE UPDATES ] section to README file
[Fix] some functions were referencing full paths instead of the variable equivs
v1.3.1 | May 12th 2010:
[Fix] typo in report command eout()
[Fix] cron.daily tmpwatch on invalid path
[Change] redirect stdout to /dev/null on tmpwatch calls in cron.daily