Skip to main content
rfxn

Changelog

Version history and release notes pulled directly from each project's CHANGELOG file on GitHub.

LMD

Linux Malware Detect

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 loc

... (truncated — view full changelog on GitHub)
APF

Advanced Policy Firewall

- 2.0.1 | Feb 20 2026:

  -- New Subsystems --

[New] Docker/container chain preservation mode (DOCKER_COMPAT); surgical
      flush via flush_apf_chains() removes only APF-owned chains, preserving
      Docker, containerd, Kubernetes, and Podman chains in FORWARD and nat.
      save_external_baseline()/restore_external_baseline() captures and
      replays non-APF INPUT/OUTPUT rules across flush cycles. Fast load
      and snapshot save auto-disabled in compat mode (conf.apf,
      functions.apf, apf, .ca.def)
[New] ipset block list support: kernel-level hash tables for O(1) IP
      matching. USE_IPSET config toggle, ipset.rules definition file,
      ipset_load()/ipset_update()/ipset_flush() lifecycle functions,
      --ipset-update CLI for cron hot-reload, cron.d.apf_ipset job,
      ip_set/xt_set module loading (conf.apf, internals.conf,
      functions.apf, bt.rules, apf, install.sh, ipset.rules)
[New] GRE tunnel support: encapsulated point-to-point links with dedicated
      GRE_IN/GRE_OUT chains, protocol 47 rules, per-tunnel interface accept
      rules. USE_GRE config toggle, gre.rules definition file, lifecycle
      functions (create_gretun/destroy_gretun/gre_init/gre_flush/
      gre_teardown/gre_status), --gre-up/--gre-down/--gre-status CLI,
      auto-MTU, keepalive, tunnel key, role routing (conf.apf, internals.conf,
      gretunnel.sh, gre.rules, firewall, functions.apf, apf, .ca.def)
[New] Centralized dependency checking via check_deps(); validates iptables,
      ip, modprobe, ip6tables (critical) and wget, iptables-save/restore,
      diff (warning) before firewall start with OS-aware install hints
      (functions.apf, apf)
[New] systemd service unit (apf.service); install.sh prefers systemd over
      SysV init when /run/systemd/system detected (install.sh)
[New] -v|--version CLI option outputs version number (apf, functions.apf)
[New] Adaptive conntrack scaling (SYSCTL_CONNTRACK_ADAPTIVE); auto-scales
      conntrack_max when usage exceeds 80%, capped at SYSCTL_CONNTRACK_HIGH.
      Hash table sizing via SYSCTL_CONNTRACK_BUCKETS (sysctl.rules, conf.apf)
[New] nf_conntrack_helper disabled by default to reduce ALG attack surface
      (CVE-2013-6390, CVE-2019-8956) (sysctl.rules)

  -- IPv6 Dual-Stack Support --

[New] Dual-stack iptables helpers: ipt() applies to both $IPT/$IP6T when
      USE_IPV6=1; ipt4()/ipt6() for protocol-specific rules; ipt_for_host()
      routes by address family; ipt_dst()/ipt_src() for VNET-aware port
      rules. Adopted across firewall, bt.rules, log.rules, cports.common,
      functions.apf
[New] valid_host() and valid_ip_cidr() input validation functions; validates
      IPv4 octets (0-255), CIDR masks (0-32 / 0-128), IPv6 colon groups,
      compressed forms (::1, ::/0), FQDN dot requirement (functions.apf)
[New] IPv6 port filtering with ipt_dst()/ipt_src() VNET-aware helpers;
      ICMPv6 filtering via IG_ICMPV6_TYPES/EG_ICMPV6_TYPES; NDP types
      133-136 always permitted (cports.common, conf.apf, functions.apf)
[New] IPv6 PKT_SANITY: IN_SANITY6/OUT_SANITY6 chains with TCP flag checks,
      INVALID state blocking, PZERO6 port-zero filtering, and FRAG_UDP6 for
      fragmented UDP; includes RAB integration matching IPv4 (bt.rules)
[New] IPv6 multicast blocking; MCAST6 chain blocks ff00::/8 when
      BLK_MCATNET=1 and USE_IPV6=1, with NDP ICMPv6 types 133-136
      exempted before DROP to preserve neighbor discovery (bt.rules)
[New] IPv6 trust system: cli_trust(), cli_trust_remove(), allow_hosts(),
      deny_hosts() detect IPv6 addresses and route to ip6tables with ::/0;
      bracket notation for advanced trust (e.g., d=22:s=[2001:db8::1])
      with trust_protect_ipv6()/trust_restore_ipv6() escaping; .localaddrs6
      prevents local IPv6 from being trust-listed (functions.apf)
[New] IPv6 fast load save/restore; ip6tables snapshot saved as .apf6.restore,
      restored when USE_IPV6=1; falls through to full load when
      ip6tables-restore missing or snapshot absent (apf)
[New] IPv6 sysctl hardening when USE_IPV6=1: disables accept_source_route,
      accept_redirects, accept_ra on /conf/all/ and /conf/$IFACE_UNTRUSTED/;
      disables forwarding when SYSCTL_ROUTE=1; route flush alongside IPv4;
      all writes guarded behind proc file existence (sysctl.rules)
[New] IPv6 DNS filtering; resolv.conf nameservers routed to ipt4/ipt6
      by address type (firewall)
[New] IPv6 PROHIBIT chain with icmp6-adm-prohibited reject target (firewall)
[New] IPv6 local address detection; .localaddrs6 generated when USE_IPV6=1
      (firewall)
[New] IPv6 kernel module loading (ip6_tables, ip6table_filter,
      nf_conntrack_ipv6) when USE_IPV6=1 (functions.apf)
[New] $IP6TS/$IP6TR variables for ip6tables-save/restore (internals.conf)
[New] nft backend detection; snapshot includes backend marker
      (.apf.restore.backend) for safe restore across nft/legacy (apf)
[Change] Chain creation, MSS clamping, connection state, default policies,
         helpers (FTP/SSH/Traceroute), logging, P2P/IDENT, cdports, RAB/
         RABPSCAN, blocklist chains (PHP/DSHIELD/SDROP), ECN shame, dnet()
         converted to ipt()/ipt4()/ipt6()/ipt_for_host() for dual-stack
         (firewall, bt.rules, log.rules, functions.apf, cports.common)
[Change] flush() refactored with ipt4/ipt6 table loops; list()/refresh()
         handle IPv6; cl_cports() clears ICMPv6 between VNET iterations
         (functions.apf)
[Change] VNET IPv4-only limitation documented in conf.apf

  -- Security Hardening --

[Fix] SYSCTL_ROUTE else branch removed; previously enabled ip_forward,
      bootp_relay, and forwarding when routing disabled, turning server
      into a router (sysctl.rules)
[Fix] GRE eval command injection: create_gretun() replaced eval with direct
      $ip tunnel add using if/else for optional key flag (gretunnel.sh)
[Fix] Advanced trust syntax rejects unrecognized flow, direction, or protocol
      fields; prevents malformed entries from injecting arbitrary iptables
      arguments (functions.apf)
[Fix] Trust system input validation: cli_trust() and cli_trust_remove()
      validate via valid_host(); allow_hosts()/deny_hosts() validate plain
      IP entries before passing to iptables (functions.apf)
[Fix] Blocklist integrity: valid_ip_cidr() applied in all dlist_* download
      functions including ecnshame; garbage from corrupted downloads rejected
      at parse time (functions.apf)
[Fix] sed delimiter hardened to % in cli_trust_remove() and expirebans();
      cli_trust_remove() pattern anchored with ^ and \b to prevent substring
      matching (functions.apf)
[Fix] EG_DROP_CMD LOG rule now includes --cmd-owner filter; previously logged
      ALL packets in DEG chain (cports.common)
[Fix] Predictable temp files replaced with mktemp: refresh(), list(), and all
      7 download functions now use mktemp/mktemp -d (functions.apf)
[Fix] for-in-$(cat) glob expansion: allow_hosts(), deny_hosts(), all
      dlist_*_hosts(), dnet(), expirebans(), refresh() converted to
      while IFS= read -r (functions.apf)
[Fix] wget exit code checked in all 7 download functions; partial downloads
      no longer processed (functions.apf)
[Fix] Unquoted variable expansion hardened in file operations (install.sh,
      functions.apf)
[Change] DLIST download URLs updated from HTTP to HTTPS for all upstream
         sources: cdn.rfxn.com, spamhaus.org, feeds.dshield.org (conf.apf,
         .ca.def)

  -- Bug Fixes --

[Fix] OUT_SANITY missing 4 TCP flag pairs vs IN_SANITY; added ALL FIN,URG,PSH,
      ALL SYN,RST,ACK,FIN,URG, ALL ALL, ALL FIN to both IPv4 OUT_SANITY and
      IPv6 OUT_SANITY6 (bt.rules)
[Fix] DNS INPUT rules now require ESTABLISHED,RELATED state; prevents spoofed
      packets from being accepted on source port 53 (firewall)
[Fix] RESET chain catch-all DROP added for non-TCP packets (firewall)
[Fix] SSH helper: removed dead rule (mutually exclusive --syn + --state
      ESTABLISHED,RELATED); removed spurious UDP rule (SSH is TCP-o

... (truncated — view full changelog on GitHub)
BFD

Brute Force Detection

1.5-2:
[Change] simplified dovecot rule regex matching
[Change] simplified exim rule regex matching
[Change] separated exim rule into exim_nxuser and exim_authfail rules
[Change] removed use of case insensitive (e)greps where not needed to improve performance

1.5-1:
[Change] modified handling of attack host variable to remove cidr scoping, if present,
         in case of forged syslog data.
[Note] thanks to rack911.com for input validation testing and feedback

1.5: 
[New] added mod_security rule
[New] added asterisk rules; thanks to shellvatore.us & seanmsiegel.com
[New] added vsftpd2 rule for systems with vsftpd.log files
[New] added a new postfix rule based on shellvatore.us's BFD rules
[Change] small code cleanups to improve BFD performance
[Change] modified pop3/imap rules and added dovecot only rule for better results
[Fix] ATTACK_COUNT value was causing integer expression error in certain situations
[Fix] added exim2 rule for specific attack cases missed by exim rule

1.4:
[Fix] properly sanitized vars passed to the command line
[Fix] ignore.hosts is now updated with system addresses on each bfd run
[Note] thanks to jpetersen@webhostsecurity.com for input validation testing and feedback
[Fix] escaped backticks in config import template
[Fix] corrected INSTALL_PATH variable in installer on migrating tmp/ data

1.3:
[Fix] expanded sed regexp on sshd rule to catch events for existing users
[Fix] reformated the pure-ftpd sed regexp rule for better performance

1.2:
[Change] changed interpreter definition from /bin/sh to /bin/bash
[Fix] issue with proftpd regexp corrected
[New] added courier rule for courier imap/pop3
[New] added cpanel rule for cpanel/whm/webmail
[New] added vpopmail rule for qmail pop3
[Fix] importconf was creating a broken symlink to old install path backups
[Change] the alert template has been rewritten for mobile friendly e-mail alerts
[Change] tlog now uses stat -c to grab file lengths instead of ls; both use
         st_size to grab file lengths but stat just does it faster
[Change] rewrite of all existing rules using sed + regexp
[New] all variables in conf.bfd have been renamed for better consistency
[New] all attacking hosts are tracked in bfd/tmp/track.attack and file is kept
      at no more than 2500 lines
[Change] removed the use of grep based pattern.* files for the more efficent
         use of sed based regexp checks
[Change] README file has been updated
[New] many changes and cleanups to the internals of bfd, far more than could
      be listed

0.9:
[Change] created apool_rgen function to update attack pool based on IPs
         currently banned and/or removed
[Fix] importconf template has escape errors on backticks
[Fix] modified sendmail rule; error in colum selection - 13 to 10
[Change] modified importconf to merge log tracking data upon updates
[Change] cleaned some repeated operations in bfd main check() function
[New] added importconf script to merge custom conf vars from previous install
[Change] moved exim rule back to standard path and increased trigger to 50
[Change] modified alert function to better handle and not send alerts for
         duplicate events
[Change] modified alert function to send less but more acurate logs with alerts
[New] added sendmail RCPT REJECT rule
[Change] added a test operation to all rules to determine if service exists
         on local system; if not rule is not processed at all
[Fix] altered the ban command execution style to be more compliant with options
      other than apf such as tcpwrappers
[Change] modified alert.bfd template
[Fix] corrected check() loop error that caused bfd to run untill killed on some
      systems
 
0.8:
[Fix] modified rh_imap/rh_pop3 rule to accomidate for events with no hostname
[Change] modified install.sh to setup 644 instead of 755 perms on cronjob
[Fix] modified tlog to better handle rotation events
[Change] small modifications to rules to more implicitly check for ip's
	 opposed to hostnames

0.7:
[Change] revised sshd rule again, reverted to parsing /var/log/secure, no
	 rhost logs are parsed anymore.
[Fix] used sed to remove traces of ipv6 from sshd logs (:::ffff::)
[Change] modified check() with more granular error checking on IP addresses
[Change] modified alert.bfd, added more conditional output

0.6:
[New] pure-ftpd rule added
[New] exim rule added
[Change] changed default permissions on installation files

0.5:
[Fix] modified sshd rule; handle rhost style logs
[Fix] modified imap rule; handle rhost style logs
[Fix] modified pop3 rule; handle rhost style logs
[Change] added various pattern entries to pattern.auth
[Change] modified alert() function, correct null entry log output
(rev:2)
[Change] added definition of module for triggered events in logs

0.4:
[Fix] used variables not being nulled properly between rule execution
[Fix] ip exclude/ignore routine imporperly excluding certian ip's
[Fix] sshd rule improperly handling 'illegal user' notices
[New] added example to check multiple log files [ensim]; apache rule
[Fix] 'stat' command not compatible with debian, replaced with use of 'ls'
(rev:2)
[Fix] LP variable not redefined during loop for vhost logs; apache rule
[Fix] missing '-d' from if operation; apache rule
(rev:3)
[Fix] minor revision made to sshd rule; was not properly parsing logs

0.3:
[New] rh_pop3 bfd-rule
[New] rh_imap bfd-rule
[New] added tlog script; log length  tracker
[New] added get_state(); - lockfile function
[Change] revised rule file formats
[New] added exclude.files; list of files containing hosts to ignore
[New] added local-ip precheck routine; ensure no local ip is banned
[Change] renamed $HOST var to $ATT_HOST
[Change] revised cronjob from 5 to 8 minute execution cycle
[New] added uninstall.sh / copies to $INSPATH
[Change] revised alert.bfd
[New] added apache rule; validates against HTTP AUTH failures in CLF
      apache error_log's

0.2:
[Change] removed deprecated conf.bfd options
[Change] replaced FWRST/FWRULES with BCMD/FWFILE
[Change] restructured logic of check() function
[Change] error checking routines revised
[New] added contents to README file
[Change] revised all comment headers
[Change] exported alert e-mail to alert.bfd file
[New] added host ignore file; ignore.hosts

0.1:
[New] Inital release