Upgrading¶
What to do when upgrading NSClient++, newest release first. Most upgrades are in place โ defaults are preserved and the default install is usually unaffected โ but the items below change observable behaviour or want a configuration touch. Read the entries between the version you are on and the version you are moving to.
Each entry carries an icon for the area it touches. ๐ is the one that matters: those entries are security-relevant, and the Security notices page tracks them in one place. Full per-release detail lives in each GitHub release.
0.18.1¶
- ๐ Icinga API submissions now honour the configured
timeout, and credentials no longer reach the trace log. TheIcingaClientmodule’s HTTP calls previously waited forever โ the target’stimeoutsetting (default 30 s) was read but never applied โ so a stalled Icinga endpoint could silently wedge passive-result submission; settimeout = 0on the target if you depend on the old unbounded wait. The same pass maskedpassword/tokenvalues in the trace-level target dump (this also covers the other client modules sharing that machinery) and added a log message when anhttpssubmission runs with certificate verification disabled (verify modeempty ornone). See Security notices. - ๐ Filter expressions are now bounded in length and nesting depth. A
filter/warning/criticalexpression โ and a%(...)expression placeholder inside a syntax template โ longer than 1024 characters or nested more than 64 parentheses deep is now rejected at parse time instead of being evaluated, failing with a clear “exceeds the maximum length/depth” error. The where-parser and the expression evaluator both recurse with the shape of the input, so an unbounded or deeply nested expression could exhaust the stack and crash the agent. Real filters are a small fraction of these limits, so the default install and every normal configuration are unaffected โ only a pathologically large or deeply nested expression is refused. See the security notice. - ๐ CheckExternalScripts hardening. A hardening pass over the external
scripts module tightened several rough edges: the
ext-scr installargument lockdown now writes to the setting the module actually reads (previously it was a no-op, so a lockdown could silently not apply), the command timeout is enforced on every execution path with output capped, theshow/deletesandbox resolves symlinks, and%/^are blocked on the shell-fallback path. The default install is unaffected (arguments are off by default). If you rely onext-scr installto disable arguments, re-run it after upgrading so the effective setting is written. See the security notice. - ๐ NSCA-NG cert mode now actually verifies the server (and presents the
client certificate). In 0.18.0 the
NSCANgClientcert mode (use psk = false) applied its TLS configuration to the OpenSSL context after the connection object had been created from it, and OpenSSL copies the verify mode, client certificate, cipher list and TLS-version bounds out of the context at creation time โ soverify mode = peer-certwas silently ignored, any certificate the server presented was accepted, and the configured client certificate was never sent. The configuration is applied before the connection is created now. Two operator-visible consequences: a cert-mode target that “worked” against a server whose certificate does not chain to the configuredca(or does not match the host name) will now fail to connect โ that is the verification working; fix the server certificate, or opt out explicitly withinsecure = trueif you accept the MITM risk. And servers that require a client certificate will start seeing it. The default PSK mode (use psk = true) is unaffected. See Security notices. - ๐ NSCA: an unrecognized
encryptionvalue is now a hard error instead of silently running without encryption. A typo’d algorithm name (aes-256), or one not compiled into the build, used to fall back to no encryption on the end carrying it. Since the ciphers must match, a one-sided typo showed up as the peer rejecting every submission with a CRC error rather than as accepted plaintext โ but that failure gave no hint of its cause, and a value broken the same way on both ends did run plaintext while looking encrypted. Now theNSCAServermodule refuses to load and anNSCAClientsubmission fails, each naming the problem and listing the available algorithms. Default installs (aes256) are unaffected. Breaking only for setups relying on the fallback: fix the algorithm name, or setencryption = noneexplicitly if plaintext was intended โ this includes builds compiled without crypto++, where any cipher name previously degraded to plaintext and the server now refuses to start. See the security notice. - ๐ NSCA hardening: empty-password warning,
performance data = falsehonoured, wire-field validation. Enabling NSCA encryption with an emptypasswordnow logs an error on both ends (the password is the key, so an empty one is a well-known key) โ set the same password on both ends to clear it.NSCAServer’sperformance data = falsenow actually strips perfdata from forwarded submissions (it was silently ignored). Inbound host/service names are stripped of control characters and out-of-range status codes are clamped to UNKNOWN. No action needed on a default install. See the security notice. - ๐ NRDP submissions now honour
timeoutandretry. Both settings were parsed but never applied: a submission to a server that accepted the connection and then stalled hung the submission thread forever, and failed submissions were never retried. Every step of the exchange (connect, TLS handshake, proxy tunnel, request, response) now runs under the configuredtimeout(default 30 seconds for configured targets, 10 for one-shotnscp clientsubmissions), and transport failures are retried up toretrytimes. Nothing to do unless your NRDP endpoint legitimately takes longer than the timeout to answer โ raisetimeouton that target. The response body is also capped at 5 MB, far above any real NRDP reply. See the security notice. - ๐ A
tls versionwith a trailing+now means “that version or later”.1.2+(the common default) previously negotiated TLS 1.2 only; it now also permits TLS 1.3, andanyis accepted as the documentation always claimed. This applies everywhere the setting exists: NRDP and the other HTTP-based clients, the NRPE/NSCA clients and servers, andcheck_tcp. No action needed; pin an exact version (tls version = 1.2) if a peer misbehaves when TLS 1.3 is offered. See the security notice. - ๐ The Elastic module now verifies HTTPS server certificates and can
authenticate.
ElasticClientpreviously hardcoded TLS verification off; anhttps://address now defaults toverify mode = peeragainst the platform CA bundle, with newtls version,verify modeandcasettings to tune it. Newuser/passwordandapi keysettings authenticate against secured clusters (Elasticsearch 8+ defaults), and a newtimeout(default 30s) bounds each submission. If you rely on a self-signed certificate, pointcaat it or setverify mode = noneexplicitly. See Security notices. - ๐ค The Elastic module no longer sends the legacy
_typeparameter by default. Mapping types were removed in Elasticsearch 8, which rejects bulk requests carrying them, so theevent type,metrics typeandnsclient log typedefaults are now empty. Only Elasticsearch 6.x or older needs them: set the old values (eventlog,metrics,nsclient log) explicitly to keep the previous behaviour. Batched documents also now get distinct ids โ previously all documents in one bulk request shared an id and overwrote each other, so multi-entry events show up completely now. - ๐ check_mk client targets: configured TLS settings are honoured again.
check_mk_target_object::read()added the SSL keys (use ssl,certificate,verify mode,ca, โฆ) to its settings registry but never calledregister_all()/notify(), so values set on a[/settings/check_mk/client/targets/โฆ]section were silently ignored and the client connected in plaintext regardless of configuration. The keys are read (and documented) again. If you configureduse ssl = trueon a check_mk target, the connection becomes TLS on upgrade โ make sure the server side actually speaks TLS, or the check starts failing. Details in the security notice. - ๐จ Syslog client targets: configured severities and templates are honoured
again. The same defect existed in the syslog client’s target object: the
severity,facility,tag_syntax,message_syntaxand per-status severity keys on a[/settings/syslog/client/targets/โฆ]section were never read, so the built-in defaults (error/kernel/โฆ) always won. Values you configured โ perhaps years ago, without effect โ now apply; if your syslog routing depends on the previously effective defaults, review the target sections for stale keys. -
๐จ ๐ Syslog messages now carry the RFC 3164 HOSTNAME field, and several syslog options work for the first time (see the security notice). What changes on the wire and in behaviour:
- Datagrams now read
<PRI>TIMESTAMP HOSTNAME TAG MESSAGE. Thehostnamesetting under[/settings/syslog/client]โ until now read but never used โ fills the HOSTNAME field (defaultauto, the machine name). Receivers that promoted the tag (defaultNSCA) to origin host will now file records under the real host name; adjust any log-parsing rule that keyed on the old, hostname-less format. - The
tag_syntaxandmessage_syntaxtarget settings now reach the wire. They were stored under keys the sender never read, so a settings-defined target sent an empty tag and dropped the message text. - The per-state severity options (
ok-severity,warning-severity,critical-severity,unknown-severity) passed as command arguments now take effect; they too were stored under keys that were never read. - An unknown
severityorfacilityname now degrades to priority<13>(user.notice) instead of<0>โ which is kernel.emergency, a priority many receivers page or broadcast on. A missing per-state severity now falls back to the baseseverityinstead of tripping that fallback. - All C0 control bytes and DEL in the outgoing line are replaced with spaces (previously only CR, LF and NUL), so check output cannot smuggle ANSI escape sequences into the receiver’s log.
- Datagrams now read
-
โฑ๏ธ The Graphite
timeoutis now enforced โ as a budget for the whole submission. It was doubly dead before: the value the operator configured never reached the connection (the lookup read a map the well-knowntimeoutkey is not stored in, so the default 30 always won), and the connection did not use even that โ resolution, connect, the TLS handshake and every write ran with no deadline, so a stalled carbon endpoint could hold the submitting thread for the OS-level TCP timeout, or indefinitely on a stuck write. The configuredtimeout(default 30s) is read now and bounds the whole submission as one budget, like the SMTP client’s. A target whose submissions previously completed by quietly taking longer will now fail at the configured value; raisetimeouton targets talking to a slow relay. See Security notices. - ๐งน The Graphite
retrysetting is not honoured and is no longer read. The module always made exactly one attempt per submission; reading the value made it look otherwise, and a retry loop would multiply the worst-case time a stalled endpoint can hold the submitting thread by the retry count.retry/retriesare registered for every client module centrally, so they still appear in the GraphiteClient reference, butGraphiteClientdoes not act on them. Mirrors the SMTPretrychange in 0.18.0.
0.18.0¶
-
๐ฅ
check_nscpis now a filter check, and it can see crash reports again. Crash reporting itself has always worked โ the agent has archived crash dumps since 0.4.x โ butcheck_nscp’s count of them has not, for two independent reasons that accumulated over the years:- The count matched files whose extension equalled
txt, while the helper it used returns the extension with its leading dot (.txt). That comparison has been false since the check was written in 0.4.2, so the crash count read 0 whatever was in the folder. - 0.6.10 dropped Google Breakpad, whose vendored submodule and build
machinery had become a dependency burden, along with the separate
crash-report sender tool that shipped with it. The handler that replaced
it writes one plain-text
<timestamp>.crashfile per crash โ the exception, the faulting address and the module it landed in โ where breakpad left a<guid>.dmpminidump plus a<guid>.dmp.txtdescription. From 0.6.10 on, even a corrected.txtmatch would have found nothing.
- The count matched files whose extension equalled
Separately, 0.4.3 stopped the module reading the archive folder from
[/settings/crash] archive folder and hardcoded the compile-time default
instead, so on any installation that had moved the archive folder the check
was looking in the wrong place as well.
All of that is fixed. Crash reports are recognised by .crash, and still by
.dmp and .txt so pre-0.6.10 archives keep counting; the configured
archive folder is read again; and check_nscp now exposes crashes,
last_crash, crash_age, errors, last_error, uptime, version and
date as filter keywords, accepts the usual filter / warning /
critical and top-syntax / detail-syntax options, and emits perfdata for
whichever keywords the thresholds name.
The default verdict is unchanged โ any crash report or any logged error is
CRITICAL โ but two things change for existing users. The message is now
N crash(es), M error(s), uptime <duration> without the appended
last crash: / last error: fragments. To put them back, pass a
detail-syntax:
```
check_nscp "detail-syntax=${crashes} crash(es) (${last_crash}), ${errors} error(s) (${last_error}), uptime ${uptime}"
```
And because the crash count now works, an agent with an old report still
sitting in the crash archive folder will start reporting CRITICAL where it
previously read 0 โ threshold on crash_age (for example
"crit=crash_age < 7d") if you only care about recent crashes, or clean the
folder out. Crash reports remain a Windows-only concept; on Linux there is no
crash handler, so crashes is always 0.
-
๐ค
check_and_forwardnow actually submits the result. The command ran the wrapped check, answeredMessage submittedand delivered nothing: the submission was built in a form the channels could not read, so NSCA, NRDP, Graphite and every other client module received a message with no results in it. It now submits like a scheduled check does. If you had given up on the command, it works โ and if you built a workaround around its silence (for instance a schedule that exists only to be triggered), that workaround is no longer needed. The command also gainedchannel(targetstill works as a synonym),alias,destinationandsourceoptions, and names the result after the command when no alias is given.Breaking: the command no longer accepts positional arguments for the wrapped command.
check_and_forward command=check_cpu warn=load>80used to (try to) hand the bare trailing tokens to the wrapped command; it now fails to parse. Pass each wrapped-command argument througharguments=instead, one per argument:check_and_forward command=check_cpu "arguments=warn=load>80" "arguments=crit=load>90"The positional form had to go because its parser also swallowed the CLI’s own
--argument key=valuetokens, which is what fed the wrapped command garbage and made it fail. If a submission is rejected by the channel the command now reports that failure instead ofMessage submittedโ including when only one channel of a comma list (channel=NSCA,GRAPHITE) fails, which previously was silently reported as success. -
โ๏ธ A reload now loads modules enabled in an included file since the last one. An
[/includes]file is read once when the configuration is loaded and served from memory after that, so a module switched on in one โ most importantlyfleet.ini, which the fleet sync rewrites whenever a bundle changes โ was not actually loaded until the service next restarted. Nothing said so: the file on disk was right and a fleet host reported itself in sync, while the module quietly did nothing. The visible case was a fleet bundle turning onNRDPClientandSchedulerto start passive submissions, which then never arrived. A reload now re-reads the included files first, so settings changed in them take effect and newly enabled modules are loaded; modules already running are left alone. Two things are unchanged: a module disabled since the last load keeps running until the service restarts, and[/modules]in the mainnsclient.iniis still only read at startup. - ๐
New: run scheduled checks on demand with
run_schedules. After editingnsclient.iniyou no longer have to wait out the interval to see the new result on the monitoring server โnscp client --boot --query run_schedules(optionally--argument schedule=<alias>) runs the configured schedules now and submits their results on their normal channel. It is a regular check command, so it also works over NRPE, REST and innscp test. Nothing changes for existing configurations; the timers are untouched. See Passive monitoring โ Step 6. - ๐ซ A denied check is no longer submitted as a passive result. The permission
layer answers a denied query as a successful query carrying an UNKNOWN
“Permission denied” payload, and both
run_schedulesandcheck_and_forwardforwarded that to the monitoring server โ overwriting the last real result for that service while telling the caller it had succeeded. Both now refuse withPermission denied: not allowed to run <command>, nothing was submittedand touch no channel. If you restrict what a REST or NRPE identity may run, expect the denial as an error where you previously saw a stale UNKNOWN appear on the server. See Permissions. - ๐ง
settings --update --add-defaults --use-samplesnow writes the sample objects. The flag was parsed and never read, so it behaved exactly like the plain invocation. It now writes the registered/samplesections, and--remove-defaultsstrips them again โ the two are now exact inverses. An edited sample is still never overwritten or removed, and without the flag the output is byte-for-byte what it was. If you have scripted--add-defaults --use-samplesexpecting today’s (sample-free) output, drop the flag. - ๐ฌ
nscp client --query <cmd>no longer appends “No module was specifiedโฆ”. The line was appended to every result when no--modulewas named. Scripts that stripped or matched it can stop; naming a module is unchanged. - ๐ง Settings writes work again when
[/includes]names a directory. Saving handed the directory path to the INI writer, and the resulting “Is a directory” error aborted the whole save โ sonscp settings --setand the web UI failed and the main file was never written. Directory includes are read-only by nature and are now skipped when saving. If you worked around this by removing a directory include, you can put it back. - ๐ NRDP HTTPS submissions now verify the server certificate by default on
the
nscp client/REST path. Previously anhttps://submission made that way with noverify modeset trusted any certificate silently (configured targets already defaulted topeer). If you submit to a self-signed NRDP endpoint that way and want to keep skipping verification, pass--verify none(or point--caat the certificate) explicitly. Plainhttp://is unaffected. Two further NRDP hardening fixes ship in the same release โ a malformed server response can no longer crash the agent, and the NRDP token and any proxy-URL credentials are redacted from the trace log. See Security notices. - ๐ก
--source-host/--sender-hostnow name the sending host, on every client module. They were registered against the destination container, where the well-knownhostkey is routed into the typed address field โ so naming a source host silently redirected the connection to it, and the sender the handler reads was never set.SMTPClientandNRDPClienthad each worked around this by registering their own copies, which made the option name ambiguous and so unusable on those two modules (option '--source-host' is ambiguous). The options are registered once now, against the sender. If you had scripted around the old behaviour by passing--source-hostto redirect a connection, use--hostor--addressfor that instead. - ๐ SMTP submissions now verify the server certificate against the agent’s
CA bundle.
SMTPClientrelied on OpenSSL’s built-in default verify paths, which on Windows do not include the Windows certificate store โ so the defaultsecurity=starttlsfailed verification against Gmail, Microsoft 365 and every other public provider there, andinsecure-skip-verifywas the only way through. A newcatarget setting (and--caargument) defaults to${ca-path}, the same trusted bundle the other TLS clients use: the distribution’s CA store on unix, the exported Windows ROOT store on Windows. If a Windows SMTP target was only working because you setinsecure-skip-verify = true, remove it and retry โ verification should now succeed. For an internal relay with a private CA, pointcaat that bundle instead of waiving verification. Setca = noneto restore the old behaviour. A bundle that cannot be loaded now fails the submission with a message naming the file, rather than failing the handshake later with an unrelated-looking issuer error. A target that names nocaat all โ a one-shot command line, or a default target โ falls back to the same bundle, resolved once at module load, so no submission path is left on OpenSSL’s built-in verify paths by accident. - ๐ SMTP client security hardening. The same pass closed a set of
trust gaps in
SMTPClient: data pipelined into the STARTTLS greeting is refused rather than trusted as post-handshake input, the EHLO name is validated for command injection before it reaches the wire, and ESMTP capabilities are matched per reply line instead of by substring search. No configuration change is needed. See Security notices. - โฑ๏ธ The SMTP
timeoutis now a budget for the whole submission rather than a fresh deadline per operation (and per resolved address). A target that previously completed by using several times its configuredtimeoutacross a slow session will now give up at the configured value; raisetimeouton targets talking to a slow relay. - โ๏ธ SMTP messages now carry a
Message-IDheader. Nothing to do โ it improves deliverability and gives mail administrators a handle to trace a notification by. - ๐งน The SMTP
retrysetting is not honoured and is no longer read. The module always made exactly one attempt per submission; reading the value made it look otherwise.retry/retriesare registered for every client module centrally, so they still appear in the SMTPClient reference, butSMTPClientdoes not act on them.
- ๐ NRPE hardening: a new
expose versionsetting, and the metachar guard now also checks decoded input. Nothing to do on a default install. Two things are worth knowing.NRPEServergainedexpose version(defaulttrue, which keeps the legacy bannercheck_nrpeexpects); set it tofalseto answer the unauthenticated_NRPE_CHECKping with a generic message instead of the exact build. Andallow nasty characters = falsenow re-checks the decoded command and arguments, not just the raw wire bytes โ with a non-UTF-8encodingset, a multi-byte sequence could previously decode into a metacharacter that was never literally on the wire, so a request the guard was always meant to block may now be rejected. Separately,nscp nrpe installreads the storedverify modeagain instead of silently resetting it on a re-run. See the security notice. - ๐ WEB server security hardening. A review of the
WEBServermodule produced several defense-in-depth fixes (session tokens now come from the OpenSSL CSPRNG, cookie-name matching requires a name boundary, the installer refuses an HTTPSโHTTP redirect, and thelegacygrant’s startup warning now names/settings/query.pb). The default install needs no action. Two changes touch observable behaviour: a script or module name that begins with-is now rejected (rename it; interior dashes are fine), and the legacyPOST /auth/logoutroute now enforcesallowed hostslike the rest of the API (a caller outside the perimeter gets 403). A third only bites on a broken system: if the OpenSSL CSPRNG fails, the server now refuses to issue a session token (HTTP 500, logged asSECURITY:) rather than falling back to a weaker generator. See the security notice. - ๐ The bundled OpenSSL is updated from 3.5.4 to 3.5.8 in the Windows
builds, picking up the fixes from four upstream security releases on the
3.5 LTS line. The most relevant fix for NSClient++ is
CVE-2025-11187, a stack
buffer overflow parsing a crafted PKCS#12 file โ reachable through
check_certificatewhen it scans certificate files that less-trusted principals can write to โ alongside further PKCS#12/ASN.1 and TLS-stack fixes. No configuration change is needed. The Linux packages link the distribution’s OpenSSL and are unaffected. See Security notices.
0.17.0¶
-
๐ท๏ธ Check-specific filter keywords that clashed with the generic summary keywords are renamed. A handful of checks registered their own keyword named
status,countortotalโ the same names as the built-in summary keywords (%(status),%(count), โฆ). The check-specific value won infilter/warning/criticalanddetail-syntax, whiletop-syntaxand the reference documentation showed the generic one, which was confusing. Each such keyword now has a distinct, documented name:Check Old New check_cpu,check_cpu_utilizationtotalusagecheck_batterystatusbattery_statuscheck_networkstatus,totallink_status,throughputcheck_os_updatescountupdatescheck_patch_agecountpatchescheck_pending_rebootcountsignalscheck_printjobsstatusjob_statuscheck_printqueuestatusprinter_statuscheck_installed_software(Linux)statuspackage_statuscheck_activationstatusactivation_statuscheck_dockerstatuscontainer_statuscheck_connectionscount,totalconnections,total_connectionscheck_dnscountrecordscheck_httpstatusstatus_messagecheck_shadowcopycountcopiescheck_disk_healthtotalsize
Existing configurations keep working: the old names remain as
undocumented deprecated aliases with unchanged behaviour, so filters like
check_cpu "warn=total > 80" still work. Migrate to the new names at your
convenience; only they appear in the reference documentation. A few
behaviour changes ride along:
- `check_os_updates`' default output now reports the actual number of
updates (rendered from the detail line via `${list}`) instead of the
matched-row count the old default showed.
- Three default perfdata keys change because the default `perf-config`
lists the renamed keyword: `check_cpu_utilization` (Linux)
`cpu_total` โ `cpu_usage`, `check_patch_age` `patch_count` โ
`patch_patches`, `check_pending_reboot` `reboot_count` โ
`reboot_signals`. Pass your own `perf-config=extra(...)` with the old
(alias) keyword to keep the old key. All other perfdata keys are
unchanged (the renames keep their original perf suffixes, and
`check_connections`' default perf-config intentionally still uses the
alias for series continuity).
- ๐
${host}and friends now resolve in attachment paths and in[/includes]. Host name placeholders were only expanded in settings urls and in the url an attachment is fetched from, not in the path it is written to nor in an included file name. An unknown${...}token in a path is not an error - it resolves to the installation directory - so a configuration such as[/attachments] ${shared-path}/${host}.ini = ...did not fail, it quietly wrote one file with the installation directory in its name. Those paths now name the host, which changes where such a file lands: check any${host},${hostname}or${domain}you already have under[/attachments]or[/includes], and remove the workaround if you scripted around this. Configurations without a host name placeholder are unaffected. When the substitution lands in a local path, the value is sanitized to the characters a legal host name can contain (see the security notice). Likenscp settings --switch,nscp settings --migrate-to(and the REST migrate) now keeps a placeholder you pass it as-is inboot.iniwhile migrating into the expanded per-host file, so the template survives on a fleet-managed machine. - ๐ข Check messages can now be told how to render their numbers. Every filter
check gained four options -
decimals,byte-unit,decimal-separatorandthousands-separator- socheck_drivesizecan report141.06GB/1006.85GB(or141,06GB/1.006,85GB) instead of140.293GB/0.983TB. The defaults are unchanged, so an installation that does not set them renders exactly what it rendered before. The options only touch the message: performance data keeps its full precision and its.radix, and so do the numbers you write in a filter or a threshold. Real-time filters take the same settings asdecimals,byte unit,decimal separatorandthousands separatorkeys, inheritable from the default template.decimalsis capped at 15 (adoublecarries no more than that): the query option and theformat_bytes()/format_number()argument reject a larger value, and the settings key clamps it, so a typo likedecimals=1000000can no longer make a check try to render a multi-megabyte number. Note that setting any of the four options also moves plain float keywords in the message onto the number format: withdecimalsunset they then render with up to three decimals (trailing zeros stripped) instead of the legacy 6-significant-digit form โ2.71094becomes2.711, and large values stop rendering scientific (1.23457e+07). A pipeline that matches float text in the message may need its pattern relaxed when you first set one of these options; leave all four unset and the message is byte-for-byte unchanged. - ๐ข An unknown unit in
format_bytes()is now reported instead of rendering nonsense.format_bytes(used, 'gb')used to render1.27055e-10because the unit comparison was case sensitive, and any misspelled unit renderedvalue/1024^7. Lowercase units now work, and a unit that names nothing (say'ZB') makes the check reportFilter processing failed: format_bytes failed: Unknown byte unit: ZB. A syntax string with such a typo returns UNKNOWN rather than a quietly wrong number - fix the unit, or the check will stay UNKNOWN. - ๐ A
unit:inperf-configthat names no unit no longer divides the metric by 1024โท. An unrecognised unit now leaves the value alone. If a graph of yours has been flat at a near-zero value, check theunit:spelling in itsperf-config: the metric will jump to its real magnitude on upgrade. - ๐
perf-config’sunit:now converts plain byte series instead of relabelling them. On series that are byte counts but do not auto-scale (most byte keywords outsidecheck_drivesize),unit:KBused to change the label only, shipping=1536KBfor a value of 1536 bytes - a metric off by the unit ratio to any consumer that trusts the label. The value and the warn/crit bounds now convert into the requested unit, matching what the auto-scaling series always did. A dashboard that compensated for the mislabelling will see the metric drop by that ratio on upgrade. Series not measured in bytes (ms,%,s, …) and explicitminimum:/maximum:overrides are unaffected, and aunit:that names no byte unit still only changes the label. - ๐งฉ Errors raised while a template renders are now reported. A function that
failed inside
detail-syntaxortop-syntaxused to leave the placeholder empty and say nothing; the check now returns UNKNOWN withFilter processing failed: โฆ. This surfaces template mistakes that have been silently producing incomplete messages. - ๐ช
check_pending_reboot’s default message now names the pending-since time. When the reboot was queued by Component Based Servicing or Windows Update, the message gains a suffix:Reboot required: Windows UpdatebecameReboot required: Windows Update (pending since 2026-08-16 09:41:12). Notification pipelines that match the exact message text (an anchored regex, a string equality) need their pattern relaxed; thresholds, states and existing keywords are unchanged. - ๐ข Filter comparisons between a text keyword and a bare number are now
numeric. A string-typed keyword compared against an unquoted number used
to order lexically โ
filter=value > 90onfilter_perfmatchedvalue=100as false (“100” sorts before “90”) โ or, with the operands reversed (90 > value), failed to evaluate at all. Both now compare as numbers, whichever side the keyword is on: the row’s text is parsed per record, and a value that is not a number simply never matches (the check logs one warning naming the value; the result stays a certain non-match, not UNKNOWN). This applies to keywords such asvalue/warn/crit/min/max(filter_perf,render_perf),speed(check_network),string_value(check_registry_value) and thecolumn()function (check_logfile). Quoted literals keep the lexical comparison โversion < '8'still orders as text โ as dolike,regexpandin, keyword-specific converters (state = 'running',age > 30m), and the= 'unknown'/= 'never'sentinels for optional values. Review any filter that deliberately relied on text ordering against a bare number: quote the number to keep the old behaviour. - ๐ข Fractional numbers in thresholds are no longer truncated or rounded.
count > 2.5used to evaluate ascount > 3(the literal was rounded into the counter’s integer domain); unit literals lost their fraction entirely, soworking_set > 1.5gmeant 1g anduptime < 2.5hmeant 2h. Fractions now mean what they say. Whole-number thresholds are unchanged; only expressions that already used a decimal point can behave differently. - ๐
filter_perf/render_perf/xform_perf: themaxandminfilter keywords were swapped.maxread the perf-data minimum bound andminthe maximum. They now read the bounds they name โ a filter that compensated for the swap needs the two names exchanged back. - ๐จ Syslog submission works again, so a configured syslog server will start
receiving traffic.
SyslogClientread its connection settings from the wrong place, so the target’s address, port, facility, severity and templates were all ignored: the agent loggedUndefined facility:and sent nothing. Broken since 0.4.3 (2015). If you have a syslog target configured, check it still points where you want before upgrading - it has not been delivering, and it will now.CheckMKClienthad the same defect on its query path. - โ๏ธ SMTP notifications now announce this host in EHLO instead of
localhost. The sender’s host name was read from the wrong place, so it was always empty and the EHLO fell back tolocalhost. If your mail server applies HELO/EHLO policy (SPF checks, or a rule that rejectslocalhost), the agent will now identify itself properly - setehlo-hostnameon the target if you need a specific name. - ๐ง
nscp settings --shownow says so when--keyis missing.--show --path /some/pathwithout a--keyused to print nothing and exit 0; it now reportsInvalid command line please use --path and --key with showand exits non-zero. A bare--showstill describes the active settings store, and--show --path โฆ --key โฆis unchanged. Scripts that relied on the silent success need the missing--keyadded. - ๐ฌ Client commands shorter than eight characters work again. A command
such as
cpuorrunansweredException processing command line: basic_string::substr โฆinstead of running, in every module built on the shared client machinery (NRPE, NSCA, NRDP, Graphite, โฆ). Remove any workaround that renamed such commands to a longer alias; no configuration change is needed. - ๐ง The settings diff no longer reports changes that were already saved.
get_changes()โ behind the REST settingsdiffendpoint and any operator-facing “what am I about to save?” view โ kept listing an edit for the lifetime of the process after it had been written, reporting it as amodifiedentry whose old value equalled its new one. Tooling that treated a non-empty diff as “unsaved work pending” no longer needs to special-case that; no configuration change is needed.
0.16.4¶
- ๐ The bundled Mongoose web server is upgraded to 7.23, fixing two
critical (CVSS 9.1) HTTP request-smuggling vulnerabilities in its HTTP
parser (CVE-2026-73256,
CVE-2026-73257). This
affects the Windows builds of the
WEBServermodule (REST API / web UI) and is exploitable when NSClient++ sits behind a reverse proxy or WAF โ upgrade promptly in that topology. The Linux packages use the Boost.Beast backend and are unaffected. No configuration change is needed. See Security notices.
0.16.3¶
- ๐
check_nt(NSClientServer) answers the real nagios-plugins client again. Requests without a trailing newline used to hang until the client timed out (No data was received from host!) โ broken since 0.12.2. Remove any client-side timeout/retry workarounds; no configuration change is needed. If you expose this legacy endpoint, see the new guidance on securing it (password,allowed hostsand theallowcommand list).
0.16.2¶
- ๐ Sensitive settings values are redacted on read. The REST settings
read endpoints (
GET /api/v2/settings/...,/descriptions) andnscp settings --list/--shownow return***for keys registered sensitive, matching thediffendpoint. No action required; tooling that read such a value back now receives***. See Security notices. - ๐ The built-in
legacyWEB role is no longer seeded on fresh installs, and any role granting thelegacypermission now triggers aSECURITYwarning at startup (and fromnscp web add-role/add-user). Existing installs are unaffected โ the role stays in their config. Thelegacygrant unlocks the deprecated/query.pband/query/{name}query-dispatch endpoints, so a token with it can run any registered check/command; only grant it to trusted legacy systems. See Security notices.
0.16.1¶
- ๐ง RHEL/SUSE: workaround
ca=arguments can be dropped โ${ca-path}now resolves on its own (the explicit form still works). Packagers cross-building for another distribution should set-DCONFIG_CA_PATH=. - ๐
check_logfileis unchanged unless you opt in tobookmark/max-lines. Adoptingbookmarkis a trade-off: a line is consumed when the check runs (not when its result is submitted) and positions are saved on clean shutdown, so a crash re-reports the backlog. Prefer an explicit bookmark name for a check whose filter changes often. - ๐ง Settings URLs with a query string now send it. A server that relied on receiving the bare path will now see the parameters. The offline-boot cache file is migrated to the query-aware name once on first start.
- ๐ท๏ธ
${hostname}in an existing config changes meaning โ it is now expanded everywhereexpand_hostnameis used (including submit clients’hostname), where it used to be left as literal text. - โฑ๏ธ
run on startupis off by default so the default install is unaffected; if you enable it for thedefaultschedule usestartup windowto avoid a thundering herd. - ๐ Building the HTML docs on non-Windows now needs
-DNSCP_BUILD_DOCS_HTML=ON.
0.14.1¶
- โ๏ธ Licence change: now distributed as Apache-2.0 OR GPL-2.0-only โ a clarification/relicensing with no code or runtime behaviour change. Review it if your organisation tracks bundled-software licences.
- ๐ CheckNet perfdata is on by default. If you added perfdata manually, make sure you are not now emitting it twice.
- โ๏ธ Boolean check arguments (
option=true/option=false) now work from the CLI as well as REST; bare-flag usage is unchanged. - ๐
CheckSecurityis not loaded by default. Enable it before using its checks (nscp settings --active-module CheckSecurity). Windows-only checks return UNKNOWN elsewhere.
0.12.6¶
- ๐ New permission policy layer, disabled by default. Existing installs
behave exactly as before until an operator sets
/settings/permissions/enabled = true. If you opt in: per-command rules apply to queries only (exec is gated by the separateallow execboolean, which defaultstrue); roll out withlog allows = truefirst to inventory real traffic. See Permissions. - ๐ NRPEServer
client identity sourcedefaults tonone(previous behaviour). Set tocnonly after configuringverify_mode = peer-certand aca pathpinned to your private monitoring CA โ the system trust store would accept any public cert’s CN. - ๐
[/paths]overrides from an older install moved to[paths]inboot.ini(same section name, different file). No automatic migration โ copy each entry across and delete the old section. - ๐ WEB
disable admin user = trueis a new opt-in for status-only WEB exposure; existing installs keep their admin unchanged. - ๐ NRPEServer now survives a failed listener (logs an ERROR, leaves the module loaded) instead of failing the whole module. Add “NRPE listener failed” as a signal if you alerted on module-load failure.
- ๐
insecure = trueon NRPEServer now logs at ERROR (louder, behaviour unchanged) โ whitelist the message on agents intentionally run insecure.
0.12.5¶
- ๐
[/paths]users: copy entries into[paths]inboot.ini; the settings-side section is no longer consulted. Default installs are unaffected. - ๐งฉ Custom-plugin authors: implement the new optional
prepare_shutdowncallback if your module manages sockets or background threads โunloadis now a last-resort teardown. - ๐ Monitoring-only WEB deployments:
disable admin user = trueunder[/settings/WEB/server]suppresses the built-in admin even on first boot; define your own read-only users (or a tightly scopedanonymousrole).
0.12.4¶
- ๐ Icinga
check_nscp_apiworks again after upgrade with no config change. For a non-stock probe, set[/settings/WEB/server] legacy query auth user agentsto a substring of its User-Agent. For the strict 0.12.3 behaviour (no query-string credentials at all), set that key to empty.
0.12.3¶
- ๐ Audit
allowed hostson every node โ empty values now reject everything. - ๐
check_nt(NSClientServer) now defaults tossl = true; setssl = falseexplicitly if your clients don’t speak TLS. - ๐ Replace clients that call
/auth/tokenor/auth/logoutwith the/api/v2/loginflow, and any that pass?TOKEN=/?__TOKEN=in the query string with a header-based token. - Scheduler cron expressions on non-UTC hosts shift to local time โ update
them or set
[/settings/scheduler] timezone = utc. - Review
check_service/check_process/check_filesfilters that relied on the old (now corrected) behaviours. - Restart and review the log for new “refused alias” / “rejected connection” warnings โ configurations that were previously silently accepted.
0.11.33¶
- โ
No configuration migration required (new
proxykeys are opt-in). Thecheck_filesfixes change a few corner cases:max-depth=0now scans the top directory (#730); missing paths return UNKNOWN (#613); junction loops are not double-counted (#605); empty results return OK instead of UNKNOWN (#717). Review alerting that relied on the old corner-case behaviour.