Repository navigation
Release v2.6.0
Added
- Optional Sentry crash reporting via a new
internal/obspackage wrappingsentry-go. Asentry:config block (enabled,dsn,environment,sample_rate,debug) toggles it; disabled or empty-DSN are no-ops. Long-lived daemon goroutines run throughobs.Go/obs.SafeGoso panics land in Sentry withcomponent/os/panel/webservertags. DSN is redacted fromcsm config show.
Changed
- YARA-X 1.14.0 -> 1.15.0 on the glibc-2.28 builder. Go binding API unchanged.
CSM_BUILDER_TAGstepped toglibc-2.28-r2. The 1.15.0 attempt on the previous Alpine+musl-static builder crashed inyrx_compiler_build; the move to glibc-dynamic clears that.
Added
- Emailav YARA-X adapter works under worker mode, closing ROADMAP item 2's last sub-item.
yaraipc.Matchandyara.MatchgainedMeta map[string]string(string-valued rule metadata);emailav.YaraXScannerreads severity fromMeta["severity"]viayara.Backendinstead of crossing the process boundary. Daemon and email-API UI switched fromyara.Global()toyara.Active()for consistent behaviour under either backend. - ROADMAP entries 4-9: Prometheus endpoint, audit log export, bbolt retention, SIGHUP hot-reload, baseline/state backup+restore, and challenge UX polish (CAPTCHA fallback, verified-session bypass, verified-crawler allow-pass).
- Internal
csm yara-workersubcommand andinternal/yaraipcwire protocol (length-prefixed JSON over Unix socket). Groundwork for moving YARA-X into a supervised child process so a cgo crash cannot take the daemon down (ROADMAP item 2); still in-process this release. yaraworker.Supervisorfork+execs the worker with exponential-backoff restart, readiness Ping, in-processReload, and an escalationRestartWorker. Gated bysignatures.yara_worker_enabled(default off); crashes emit a Criticalyara_worker_crashedfinding rate-limited to one per minute. Scan callers route throughyara.Active().internal/metricspackage: Counter, Gauge, Histogram, their labelled vector variants, and a Registry that renders Prometheus text exposition format. Zero external deps. Groundwork for ROADMAP item 4./metricsendpoint on the web UI (ROADMAP item 4 complete). Auth acceptscfg.WebUI.MetricsTokenas a dedicated Bearer and falls back to UI AuthToken / session cookie. Eleven metrics shipped (csm_build_info,csm_yara_worker_restarts_total,csm_findings_total,csm_store_size_bytes, threecsm_fanotify_*series,csm_check_duration_secondswith{name,tier}labels,csm_blocked_ips_total,csm_firewall_rules_total,csm_auto_response_actions_total). Documented indocs/src/metrics.md.- Metrics hardening: per-subsystem smoke tests so a dropped
observe*call site fails CI instead of surviving a manual scrape. Newdocs/src/examples/prometheus-scrape.ymlplus apromtool-checkCI job that validates it. docs/src/configuration.md"Editing csm.yaml by hand" section: documents thecsm rehashstep between a manual edit andsystemctl restart csm.integrity.Verifyrefuses any config whose sha256 disagrees withcfg.Integrity.ConfigHashand crash-loops the daemon on restart, so the section covers backup / edit / rehash / validate / restart / rollback.- SIGHUP config hot-reload (ROADMAP item 7, initial).
internal/configgainsActive()/SetActive()overatomic.Pointer[Config]and aDiff()that classifies top-level fields via a newhotreloadstruct tag. Fields taggedsafeswap in place; untagged orrestart-tagged fields abort the reload with a Warningconfig_reload_restart_requiredfinding naming the offending fields, and the live config stays untouched.Thresholdsis the first safe field. Parse/validation errors emit a Criticalconfig_reload_errorand keep the old config live. Reload re-signsintegrity.config_hashin place.ExecReload=/bin/kill -HUP $MAINPIDwired into the systemd unit. Known caveat: four long-lived tickers (deep_scan_interval_min,wp_core_check_interval_min,webshell_scan_interval_min,filesystem_scan_interval_min) keep firing at the old interval until restart; every other threshold takes effect next tick.
Fixed
- False-positive quarantine storm on WP auto-updates and WPML. Deep-scan for
/wp-content/languages/and/wp-content/upgrade/now runs content analysis first (matching the realtime path), the WPML translation queue is recognised as known-safe, and the auto-quarantine entropy floor is raised from 4.8 to 5.5 (WPML and Breakdance added to the library-path allowlist). A 2026-04-17 incident quarantined 109 benign files; the same content no longer trips any gate. - Realtime
php_in_sensitive_dir_realtimeWarning no longer fires on WPML translation-queue regenerations. The fanotify path now shareschecks.IsSafePHPInWPDirwith the polled deep-scan, so a language-pack refresh no longer produces 30-40 Warnings per second. - Realtime fanotify tests in
internal/daemonstopped feedingos.File.Fd()into analyzer functions (analyzeFile,checkCrontab,checkPHPContent,checkHtaccess,checkUserINI,checkHTMLPhishing,checkCGIBackdoor). That pattern attached the netpoller and a GC finalizer to fds the tests then handed off to syscalling code, producing an intermittent EBADF under-race+ coverage (CI job 93822). 11 test files converted to rawunix.Open/unix.Closefds, matching the production ownership model. - WebUI "YARA RULES" card and "Reload Rules" button work under worker mode. The rules API was reading
yara.Global()(nil when the worker is on, so the dashboard reported 0); it now usesyara.Active(), covering both backends. runPeriodicChecksno longer fires a spurious Criticalintegritytamper alert on every tier tick after a successful SIGHUP reload.integrity.Verifywas passed the startupd.cfgwhoseConfigHashwent stale as soon as reload re-signed the on-disk file; it now runs againstd.currentCfg(). Regression:TestReloadConfigIntegrityVerifyPassesAfterReload.- SIGHUP reload no longer misclassifies every reload as
restart_requiredfrom a false-positive firewall diff.startFirewallwas mergingcfg.InfraIPsintod.cfg.Firewall.InfraIPsat boot, so a fresh post-reload config (without that merge) diffed non-equal even on an unedited file. The merge now uses a shallow-copiedFirewallConfigand leavesd.cfg.Firewalluntouched. Caught on live production smoke (2026-04-19). Regression:TestDiffLoadLoadIsEmpty. - A SIGHUP reload rejected as
restart_requiredno longer leaves the on-disk file with a staleintegrity.config_hashthat would crash-loop the daemon on next restart. The handler now re-signs the file viaintegrity.SignAndSaveAtomicon that branch and updates the liveconfig.Active()ConfigHash in lock-step, so between edit and restartintegrity.Verify(currentCfg)does not see a disk/memory divergence. Also caught on live production smoke. Regression:TestReloadConfigRestartRequiredKeepsIntegrityConsistent. firewall: netlink receive: recvmsg: no buffer space availableon startup and every SIGHUP.Engine.loadStatewas issuing oneSetAddElementscall per persisted entry, overflowing the netlink socket'sSO_RCVBUFon hosts with a few hundred blocks. Entries are now collected per target set and shipped via a newaddElementsChunkedhelper that caps each message at 1000 elements (~28 KB, below the 208 KB rmem default); 1000 is even so interval sets never split a{start, IntervalEnd}pair.- Firewall
resolveSubnetSetandloadState's blocked_net loop skip cleanly whenlastIPInRangereturns nil (malformednet.IPNetwhose IP is neither 4 nor 16 bytes). Prior code fell through tonextIP(nil)and fed an empty Key to the kernel. Regression:TestResolveSubnetSetMalformedIPReturnsNil. plugincheckno longer double-logs one hung wp-cli call as bothCommand timed outandJSON parse failed: unexpected end of JSON input, and stderr chatter (PHP warnings, MySQL deprecation notices, broken-plugin backtraces) can no longer poison the JSON (theinvalid character 'W'/'P'/'N'class). wp-cli runs through a new stdout-onlyCmdRunner.RunContextStdoutthat surfacescontext.DeadlineExceeded, plus--skip-plugins --skip-themesandWP_CLI_PHP_ARGS='-d display_errors=0 -d error_reporting=0'so one broken plugin can't tip the whole enumeration into exit 255. Per-site failure lines replaced by a single refresh summary withtimeout=N exec_fail=N json_fail=Ncounters.
Changed
-
SIGHUP hot-reload safe-reload set grows from one field to six:
alerts,suppressions,auto_response,reputation, andemail_protectionare now taggedhotreload:"safe"alongsidethresholds. Auto-response paths,alert.Dispatch, and the heartbeat readd.currentCfg()per call; batch handlers (dispatchBatch, initial-scan) snapshot once at the top so a reload landing mid-batch never splits a finding set between policies. Regression:TestDiffAllSafeFieldsClassifiedSafe. -
csm run-deepno longer exits withreading response: i/o timeouton large servers. Tier-run RPCs get a 60-minute deadline (plugin-cache refresh fans out a wp-cli per site); other CLI commands keep the 5-minute default. The hourlycsm-deep.servicetimer now logs a realtier=deep findings=X new=Y elapsed_ms=Zline instead of failing every hour. -
db_post_injectionstopped firing on legacy author-embedded<script src="http://...">tags. Post-content URL classification uses a post-specific predicate that drops the plaintext-HTTP indicator but keeps structural markers (raw IP, abused TLD, known-bad exfil host, invalid host). wp_options classification is unchanged. -
suspicious_php_contentno longer fires purely on "shell function co-present with request input" against WordPress file-manager plugins (FileOrganizer, elFinder). The co-presence signal is corroboration only; same-line shell-function-with-request-input still fires alone.containsStandaloneFuncalso rejects method calls, static calls, and function declarations (e.g. an SQLite driver's$this->DB->...(...)line with a$_SERVERreference no longer trips the same-line rule). -
webshell_p0wnydropped the bare"p0wny"pattern. Combined with thep0wny.?shellregex it double-counted on a single occurrence of "p0wny-shell" (e.g. a docblock reference), clearingmin_match: 2on its own. The remaining patterns (featureShell,makeCommand,window.term) are structural markers unique to the shell's terminal UI. -
AbuseIPDB quota enforcement persists across 10-minute cycles: a 429/402 backs off until the next UTC midnight, a per-day counter (cap 900) acts as a circuit breaker, and transient-error cache entries expire at the intended ~1h (the pre-fix formula shifted
CheckedAtinto the future, effectively stretching error caches to ~11h).