Changelog
The canonical source is enodia’s own
CHANGELOG.md
— this page mirrors it, kept in sync alongside the rest of this site on
every release, with links into the rest of these docs where a change
affects how you’d actually configure something. Tags follow
MAJOR.MINOR.PATCH+BUILD, no v prefix; +BUILD is semver build
metadata, used only for a rebuild with no functional change, not to
sidestep a real version bump.
2.2.1+0 — 2026-10-27
Section titled “2.2.1+0 — 2026-10-27”A maintenance release: probes stop tripping over their own version
checks (MySQL/MariaDB host blocks, PostgreSQL login-only roles), ${VAR}
values are taken verbatim, and two cve update edge cases are fixed. No
new probes, inventories are unchanged. One behaviour change: the
postgresql probe now connects to the postgres database instead of
one named after the login user — set
options.database
for a server that has no postgres database.
postgresqltargets takeoptions.database. The probe now asks for thepostgresdatabase by default instead of one named after the login user, so a role with nothing butLOGINreveals the version without a database of its own.
mysqlandmariadbno longer risk getting enodia’s own host blocked (ERR 1129). They read the version from the greeting and hung up, which the server counts as an aborted connection before authentication; enough of those tripmax_connect_errors. The probes now answer the greeting with a throwaway login, so the connection counts as a failed authentication, which doesn’t block the host. The version still comes from the greeting; no credential is used.${VAR}in a config orcredentials_fileis expanded after the YAML is parsed, so a variable’s value is taken verbatim: a password with a backslash,#,:or a leading*/&/[no longer breaks the file orconfig validate.enodia cve updatewithcve.oval.pathorcve.alpine.pathset but no release or branch to fetch (none on disk, in--fromor the flags) succeeded quietly, leaving a directorycheckthen refused; it now says so and exits1.kafkastartedkafka-topics --version(a JVM start, a few seconds) on every run when it was onPATH, even with the broker’s jar found; it now runs only when no jar is.
2.2.0+0 — 2026-10-09
Section titled “2.2.0+0 — 2026-10-09”enodia cve update downloads the CVE databases itself, vendors’ own
security data (MariaDB, Atlassian, PostgreSQL, nginx) joins БДУ and NVD,
CVE matching reaches iLO 4, iDRAC and Synology DSM, and 27 new probes
land — 123 in total. Every new cve: key is optional, and 2.1 configs
and inventories work unchanged — except a credential of a kind its
product never reads, which is now an error (see Fixed).
enodia cve updatedownloads the CVE databases every configuredcve.*.pathnames — БДУ, NVD (this year, last year and missing years;--all-yearsfor all), Debian, OVAL and Alpine (the releases already on disk, those--frominventories need,--oval/--alpine), MariaDB, Atlassian, PostgreSQL (--postgresqlfor per-major pages) and nginx. If-Modified-Since; a download replaces a file only after it loads. TLS is verified against the system roots pluscve.update.ca_fileandcve.update.ca_dir, or not at all withcve.update.tls_skip_verify. Every other command still never downloads anything.- 27 new probes:
splunk— splunkd’s management API on 8089, Basic or a Splunk token.code-server—codeServerVersionfrom the login page.phpipam— the login page’s footer and asset version.domainmod— the CHANGELOG in its web root.netdata— the agent’s anonymous/api/v1/info.libretranslate— the public OpenAPI document/spec.torrserver—/echo.kafka— the broker’s version over SSH from its own jar, optionally in a container; Confluent Platform builds are reported asconfluentwith the Apache Kafka line they carry.home-assistant—/api/configwith a long-lived access token,kind: bearer.openhab— the anonymous REST root/rest/.doxygen— which Doxygen generated a docs site, from its generator mark.qbittorrent— the Web UI API after a form login,kind: password.netbox— the anonymous login page’sdata-netbox-version.greenbone— (aliasesopenvas,gsad) gsad’s version from its/gmpreply, unauthenticated.posthog— self-hosted PostHog’s git commit from its anonymous login page.uptime-kuma— logs in over Uptime Kuma’s socket.io API (kind: password) and reads the version it sends after login.wapt— the WAPT server’s anonymous/ping.minio—minio --versionover SSH, optionally in a container; MinIO’sRELEASE.<timestamp>names now compare as versions.sentry— self-hosted Sentry’s version from its anonymous login page.zookeeper— thesrvrfour-letter word.ghost— the anonymous/ghost/api/admin/site/, which gives major.minor.onlyoffice— andeuro-office: ONLYOFFICE Docs and its Euro-Office fork, read anonymously from the document server’s/index.html; a server of the other brand is refused with the product to use.weblate— the anonymous “Powered by Weblate” footer.memcached— the text protocol’sversioncommand, no credentials.rabbitmq— the management plugin’s/api/overview,kind: basic.cassandra—release_versionover the CQL native protocol v4,kind: passwordwhen the cluster has PasswordAuthenticator.
- CVEs for
mariadbtargets. БДУ and NVD now cover MariaDB, and a newcve.mariadb.pathreads MariaDB’s own table of fixed CVEs (community-server.md), which knows the fixing release per series. Where MariaDB’s table knows a CVE, its verdict replaces БДУ’s and NVD’s open-ended ranges, so the latest release of a maintained series is no longer flagged for CVEs fixed only in newer series — see Vendors’ own data. cve.atlassian.path: Atlassian’s own per-release CVE data forjira,confluence,bitbucketandbamboo, third-party dependency CVEs included. Judged within each branch; for a release Atlassian lists, its verdict wins — see Atlassian.cve.postgresql.pathandcve.nginx.path: the projects’ own security pages, with the fix release per branch. Current PostgreSQL 17/16/15/14 releases and nginx 1.30.5 no longer show БДУ’s branchless ranges — see PostgreSQL and nginx.- CVEs for 24 more products: cassandra, code-server, domainmod, doxygen, ghost, greenbone, home-assistant, kafka, memcached, minio, netbox, netdata, onlyoffice, openhab, pfsense, phpipam, qbittorrent, rabbitmq, sentry, splunk, uptime-kuma, wapt, weblate, zookeeper. MinIO’s timestamp versions compare; pfSense CE and Splunk Enterprise skip ranges for other editions; Confluent Kafka builds get no lookup.
- CVEs for
hp-ilo4,dell-idracandsynology-dsm. iDRAC is matched per generation, read from the Redfish model; DSM compares version, build and Update (7.2.1-69057-6), and the probe now records the Update inextra.update— see Dell iDRAC and Synology DSM. In total, 91 of the 123 products are now matched — see which products are matched. - A Privacy page: what enodia connects to (your
targets, endoflife.date, the GitHub API — product and repository names
only — and, only for
enodia cve update, the CVE database publishers) and what it stores (only your own files and a local cache). No telemetry.
Changed
Section titled “Changed”- The
githubresolver skips releases whose tag names a pre-release (5.3.0.M2,2026.10.0b7,-rc1,-beta.1) even when GitHub doesn’t flag them; reads underscore-spelled (Release_1_18_0) andrelease--prefixed (release-5.2.4) tags as versions; and drops a leading<repo>-/<repo>_from tags, soweblate-2026.10reads as2026.10— see Supported products. teamcityworks without credentials: with none configured it reads the anonymous/app/rest/server/version, open on every TeamCity checked from 2017.2 to 2026.1 even with guest login off. A token still selects/app/rest/serveras before.
jenkinsCVEs: a fixed LTS release is no longer flagged by the weekly range of the same fix (LTS 2.568.3 by “before 2.580”). Weekly and LTS ranges now apply only to their own release line.- The
githubresolver no longer fails on repositories whose releases list is over 1 MiB (minio/minio’s is 3.4 MB): it now reads up to 8 MiB. - A credential of a kind its product never sends is now a config
error instead of being dropped silently.
kind: passwordon an HTTP product (RouterOS, Harbor, …) used to send the request with noAuthorizationheader at all;config validatenow names the kinds the product accepts — for a web login that iskind: basic. Check your config before upgrading: a run with such a credential now refuses to start. See Configuration → Credentials.
2.1.1+0 — 2026-10-08
Section titled “2.1.1+0 — 2026-10-08”- MariaDB 11.0+ no longer masks its version behind
5.5.5-(11.4.9-MariaDB-…), somysqlrecorded such servers as MySQL andmariadbrefused them. Both probes now recognise MariaDB by either shape. Aproduct: mysqltarget pointing at MariaDB 11.0+ now fails — switch it toproduct: mariadb.
2.1.0+0 — 2026-10-01
Section titled “2.1.0+0 — 2026-10-01”CVE correlation goes down to installed packages on ten Linux
distributions, and six new probes land. Nothing breaks: the new cve:
keys are optional, and inventories only gain optional fields, so 2.0
configs and inventories work unchanged.
- Package-level CVEs for Linux distributions.
The OS probes now also read the installed packages and the running
kernel in their one SSH round trip, and each distribution’s own
security data is matched per package. Each source is a file you
download, like БДУ and NVD:
cve.debian.path— the Debian Security Tracker’s JSON, fordebian.cve.oval.path— vendor OVAL files, one per release, forubuntu,linuxmint(via its Ubuntu base),rhel,rocky-linux(against Red Hat’s file — Rocky’s own is refused as unusable),almalinux,oracle-linux,astra-linux(SE 1.7/1.8) andredos(7.3/8.0). Parsed OVAL is cached like БДУ and NVD.cve.alpine.path— Alpine’s secdb, foralpine-linux.
- Only CVEs that already have a fix newer than what’s installed are reported — what an upgrade (and, for the kernel, a reboot) would close. One finding per package, linked to the advisory carrying the fix (USN, RHSA, ALSA, ELSA, Astra bulletin, ROS, Debian/Alpine tracker page), with every CVE folded under it in the HTML report.
- Matching follows each package manager’s own rules: dpkg, rpm and apk
version ordering, AppStream module streams, Oracle’s arch, FIPS and
Ksplice variants, and the running kernel rather than whatever kernel
packages are installed. Every source was cross-checked against the
reference tool (
oscap oval eval,dnf updateinfo, python3-apt,apk version -t) on real containers, with identical results. - New probes:
mariadb,pfsense(Community Edition, over SSH),supermicro-bmc,dell-idracandhp-ilo4(over Redfish), andfreeradius(over SSH, withoptions.containerfor a FreeRADIUS in Docker or Podman). 96 probes in total. github-tag-branchesresolver: one lifecycle cycle per major.minor from GitHub tags, for projects maintaining several branches at once (FreeRADIUS 3.0.x and 3.2.x).- FreeRADIUS is matched in both NVD and БДУ.
- VMware’s “8.0 U3k” shorthand in the lifecycle calendar now compares
equal to “8.0.3”: a patched vCenter
or ESXi 8.0 host no longer shows as
ahead. - LATEST/CYCLE columns show cleaned versions for GitHub-resolved
products, not the raw tag (
2026.9.1, notv2026.9.1). config validatereports a missingcve.*.pathfile instead of passing and failing later incheck.
- A Proxmox VE host gets package
findings as a second, SSH
debiantarget next to its APIproxmoxone; Debian’slinuxis only matched against a running Debian kernel, so Proxmox’s own kernel isn’t mistaken for one. - With every source configured at once (БДУ, NVD, Debian, eight OVAL
files, Alpine)
checktook ~22 s cold and ~3.4 s warm, peaking at ~0.5–0.6 GB — less ifcve.oval.pathholds only the releases you run. - The repository’s history was rewritten and re-signed to drop internal hostnames; every tag was re-created on the rewritten history. Release binaries up to 2.0.0+0 report commit hashes from before the rewrite.
- MariaDB, pfSense and the BMC probes have no CVE mapping yet.
2.0.0+0 — 2026-09-23
Section titled “2.0.0+0 — 2026-09-23”A major version for a major feature, not for a break: CVE correlation is
the first evaluation axis that isn’t about lifecycle. Existing
enodia.yaml, settings.yaml and inventory files work unchanged — the
new cve: block is optional, and a config without it behaves exactly as
1.2 did.
- CVE correlation against two local databases, БДУ ФСТЭК
and NIST NVD. enodia never downloads them: you fetch БДУ’s
vulxml.zipand NVD’s yearlynvdcve-2.0-<year>.json.gzfiles and pointcve.bdu.path/cve.nvd.pathinenodia.yamlat them (a file, or for NVD a directory of files). Either source works alone. Both are stream-parsed and cached: the first run after a database changes takes about a minute for all of NVD plus БДУ, every later run under a second. See how to download them, including the extra CA certificate bdu.fstec.ru needs. - 52 probes matched (53 product names upstream —
sshcounts as both OpenSSH and Dropbear), every probe with usable data in either source. Deliberately not matched, each for a stated reason: general-purpose Linux distributions (their CVEs are package-level), the BSDs and Solaris, ESXi/vCenter and Synology DSM (patch levels and build suffixes the matcher doesn’t read yet) — see which products are matched, and each product’s own page. - Edition-aware matching for GitLab,
Vault,
Nextcloud and
MongoDB: a community instance no
longer sees enterprise-only findings (on real data, GitLab 19.2.2 CE
sees 4 of NVD’s 9, Nextcloud 27.1.3 CE 11 of 23). The four probes now
record their server’s edition in
extra.enterprise; an unknown edition keeps every finding. sshtargets are matched as OpenSSH or Dropbear by their banner; any other SSH stack gets no CVE lookup rather than OpenSSH’s.- A
CVEScolumn incheck’s compact and drift views, counting distinct CVEs. - A per-CVE list in
export --format html, pure CSS with no JavaScript, so the inline report stays a zero-<script>offline file: one line per CVE with links to NVD, cve.org and bdu.fstec.ru, БДУ’s Russian text when БДУ has the CVE, a coloredCRITICAL · CVSS 3.1 9.8rating, most severe first. export --format jsoncarries every per-source finding under each assessment’scves, including a structured CVSS rating parsed from both sources.fortiosprobe for Fortinet FortiGate, via its REST API with a REST API Admin token.- CDN-mode HTML reports remember a dismissed “needs internet access” warning per viewer.
- The
cve:block is read from whichever config the run actually uses —--config,$ENODIA_CONFIG, or the default search paths. - Windows paths work unquoted, in single quotes, with forward slashes or
as UNC paths. In YAML double quotes
\tand\nbecome a tab and a newline, so such a path is rejected at load with a hint. cisco-ios-xeis off the roadmap for good.
1.2.1+0 — 2026-09-10
Section titled “1.2.1+0 — 2026-09-10”p4d/p4pdidn’t applytimeoutto thep4CLI subprocess they shell out to — every other probe in this tree clamps its own transport totimeoutbefore touching the network, and this one didn’t. Ap4process stuck dialing an unreachable direct server (no response, no reset — the exact network behavior that’s the whole reason these two probes shell out top4in the first place) hung indefinitely, stalling an entire collection run. Reported directly from a real hang in production.
1.2.0+0 — 2026-09-10
Section titled “1.2.0+0 — 2026-09-10”p4dandp4pprobes, for Perforce Helix Core Server and Perforce Proxy. Perforce’s own RPC wire protocol was fully reverse-engineered and a hand-built client reproduced its handshake correctly against a real proxy, but that exact, byte-verified-correct handshake is silently dropped by real directp4dservers for reasons not visible from the client side. Both probes shell out to the operator’s ownp4CLI instead — the first probes in enodia to run an external process rather than speak a wire protocol directly. The binary path is configurable per target viaoptions.binary(falling back top4on$PATH); this works identically on Windows, pointed atp4.exe. A proxy’s reply is told apart from a direct server’s by the presence of its ownproxyVersionfield — each probe rejects the other’s shape.
- The
p4 -Ztagoutput parser didn’t strip Windows line endings: a realp4.exewrites\r\n, leaving a trailing\rinside field values likeServerID. probe.Observation.Resolver(added in 1.1.0+0 for SonarQube) was a plain struct, not a pointer —encoding/json’somitemptyhas no concept of “empty” for a struct value, so every single observation was serialising a spurious"resolver":{}in JSON exports, not just SonarQube’s. Fixed to a pointer, the same reasontlsVerifiedis already nullable rather than a barefalse.
1.1.1+0 — 2026-09-10
Section titled “1.1.1+0 — 2026-09-10”debianwas reporting a bare major version (13) instead of the actual point release (13.6) — Debian’s/etc/os-releaseVERSION_IDnever carries one, even on a fully patched install; the point release lives only in/etc/debian_version.debianmoved off the sharedosReleaseFamilyProbemechanism into its own dedicated probe, which reads both files and only trustsdebian_versionafter confirmingID=debianand that its content is a plain dotted number — a real Ubuntu image was confirmed to ship the identical file with meaningless inherited content.ubuntuhad the same gap:VERSION_IDnever changes after a release ships, so a fully patched22.04host reported bare22.04, not22.04.5.ubuntualso moved off the shared mechanism into its own probe, preferring the point release fromos-release’s ownVERSIONfield when it’s strictly more precise thanVERSION_ID. Every other product in the shared SSH-based OS identification family was audited the same way; none of the rest have this gap.
No config changes for either — same product: value, same credentials,
same endpoint. Only the reported version got more precise.
1.1.0+0 — 2026-09-10
Section titled “1.1.0+0 — 2026-09-10”- A
github-tagslifecycle resolver, for a product that publishes no GitHub Releases at all, only tags in a non-dotted shape — gave pgAdmin its first working resolver (pgadmin-org/pgadmin4’s tags areREL-9_17, converted to9.17, picking the highest-parsing tag rather than the first one). - The
GITHUB_TOKENenvironment variable — authenticates every GitHub-backed lifecycle lookup, raising the unauthenticated cap from 60 requests/hour to 5000/hour. See Supported products. - A probe can now override its product’s lifecycle resolver per observation, for the rare case where the right calendar is only knowable after seeing the vendor’s own version reply. First used to split SonarQube between SonarQube Server and SonarQube Community Build — two separate products since SonarSource’s late-2024 split, tracked as two different endoflife.date pages with different cycle data.
- Resolver failures used to show only
resolver_errorin the report, with no way to tell a GitHub rate limit from a DNS failure from a reshaped API.enodia check/exportnow print the real underlying error to stderr when this happens. - SonarQube was always compared against the Community Build lifecycle calendar, even for a SonarQube Server instance — collecting its version worked, but the report showed an unmatched cycle regardless. Now resolved per instance from the version string itself.
Changed
Section titled “Changed”- Container image publishing (
ghcr.io/epicmorg/enodia, also mirrored to Docker Hub and Quay) moved out of this repository’s own release pipeline entirely, into theEpicMorg/dockermonorepo, on that repo’s own build schedule. The published image address and tags (latest,1, the exact version) are unchanged, but the image itself is nowlinux/amd64only and runs as root — see Getting started.
1.0.0+0 — 2026-09-09
Section titled “1.0.0+0 — 2026-09-09”Initial release. collect → inventory.jsonl → evaluate → assessment → render, end to end, verified against real production infrastructure:
- 87 probes, one file each, compiled in and explicitly registered — most speaking HTTP, some (Redis, PostgreSQL, MySQL, MongoDB) their own wire protocol directly, and a growing set (every mainstream Linux distribution, the BSDs, macOS, OPNsense, Proxmox VE, TrueNAS, Synology DSM, network appliances) reached over SSH or a vendor HTTP API instead of assuming a version endpoint exists at all.
product: generic— a config-only probe for anything in-house, with a deliberately frozen vocabulary (no conditionals, loops, or templating).- Lifecycle resolution against endoflife.date and GitHub Releases, cached on disk, evaluated on three independent axes (patch drift, lifecycle phase, newer branch) rather than one collapsed verdict — see Concepts.
- Four report views across table, HTML, JSON, and Prometheus output.
enodia serve— a snapshot-only HTTP server; a background ticker collects, handlers only ever read the last snapshot.- Config schema with
${VAR}/${VAR:-default}interpolation, a dedicated credential store, and TLS pinning/ insecure-opt-in per target. - Packaging:
.deb,.rpm,.apk, and Arch’s.pkg.tar.zst, a dedicated unprivilegedenodiasystem user, man pages for every command, raw archives for Linux/Windows/macOS/Android (Termux), and a container image — see Getting started. Checksums signed with cosign keyless (OIDC, no key to manage or leak).