2026-06-02
v10.33.3
Summary
Added the
mustaction for converting ignored required action results to rejects.Structured logging for EAP-TLS, EAP-TTLS, EAP-PEAP and EAP-TEAP handshakes
Added metadata to configuration export and backup ZIP files so imports and restore dialogs can show archive version, creator, timestamps, and deployment changes.
Configuration import now previews ZIP archive metadata and warnings before import, including missing metadata, version mismatch, and missing selected content directories.
JSON file backend
mappingblock now accepts an optional JSONPath selector argument for per-element iterationAdd
secretparameter with full filter pipeline support topap,backend,yubikey,hotp, andtotpactions, plus a dedicatedyubikey()OTP helper filterLDAP search filters now accept readable multiline formatting in triple-quoted config strings without causing LDAP filter parse errors
Add PBKDF2-HMAC password hashing (SHA-1, SHA-256, SHA-512)
Added TACACS+ trace-level packet logging and per-server packet size controls
Files page backup restore moved to the overflow menu, backup timestamps now follow the encoded backup name, and empty directory changes now survive deploy and restore flows.
Lowered the default
connectionsfor RADIUS backend servers from1024to10The template render CLI now includes Management UI template metadata headers by default.
The template CLI can now verify template files and generated files against template metadata checksums.
Fixed a documentation search highlighting crash that could break docs pages after opening highlighted search results.
Servers can now use
@pre-clienttogether withclientsduring migration from static to dynamic client matchingAdded RFC 9887-compatible TACACS+ over TLS settings, except certificate revocation checking
ipmap now always starts population in the background at backend creation time, and lookups reject until the first snapshot is available.
The Management API ipmap populate endpoint now triggers repopulation asynchronously instead of waiting for completion.
Added PROXY protocol v2 support before TLS handshakes on RADIUS/RadSec and TACACS+ TLS listeners.
Fixed Management UI sidebar links to configuration files so filename and template query parameters are preserved.
Missing configuration files now show the not-found state immediately instead of waiting for retries.
Counter and histogram history retention default extended from 24 hours to 7 days
Statistics API and Prometheus
/metricsnow expose floating-point gauges (e.g. load averages, rates, fractional ratios)Scalar counter values returned by the
/statisticsJSON endpoints may now be fractional.Improved the documentation index layout, navigation scroll position, and linkable docs search.
must Action
Added the must action for wrapping another action that should produce a
decision. If the wrapped action returns ignore, must converts the result to
reject and sets aaa.reason.
must pap;
Structured EAP-TLS handshake logging
EAP-TLS and the EAP methods that tunnel TLS inside it (EAP-TTLS, EAP-PEAP, EAP-TEAP) now emit a structured logging scope around the inner TLS handshake. The new records make it easier to follow one supplicant's handshake, inspect the negotiated TLS session and peer certificate chain, and understand why a handshake failed.
Successful handshakes are logged at Debug, handshake failures at Warn, and
fragment metadata at Trace. Failure logs also cover EAP response timeouts and
unexpected EAP response type/id while the TLS handshake is active. Fragment
records do not include payload bytes.
See server TLS - EAP-TLS handshake logging for concrete JSON examples and the complete field reference.
No configuration changes are required.
Configuration Archive Metadata
Configuration export and backup ZIP files now include .radiator-archive-metadata.json at the archive root. The metadata records the radiator-server version that created the archive, when it was created, and the management user involved when available.
Automatic deployment backups also record the deployed files and their change types. The Management UI shows this information in the backup restore dialog, and configuration import responses now include a non-blocking warning when an archive was created by a different radiator-server version.
The configuration import dialog now inspects a selected ZIP archive before import and shows archive metadata plus the same warnings that the import would return. This lets operators review missing or unreadable metadata, version mismatch, and missing selected content directories before creating or replacing pending configuration. See Configuration Import and Export.
JSONPath selector argument for jsonfile mapping
The mapping block in jsonfile queries now accepts an optional JSONPath expression
argument. When provided, the expression selects elements from the JSON document and
the inner field mappings execute once per matched element with doc bound to each
element individually.
query "FIND_USER" {
mapping "$.users[?(@.username == '%{aaa.identity}')]" {
user.username = doc | jsonpath("$.username");
user.password = doc | jsonpath("$.password");
}
}
This eliminates repeated filter expressions in field mappings and enables use cases that require repeating mapping executions, such as populating the ipmap backend from a JSON file.
See jsonfile documentation for details.
Filter pipelines on authentication actions and a YubiKey OTP helper filter
The pap, backend, yubikey, hotp, and totp actions now accept a
secret parameter that takes a full context expression, including the
filter pipeline. The expression result replaces the
protocol PAP response that the action would otherwise read, so any context
attribute can be shaped (for example with substring(), uppercase(),
reveal, or any other filter) into the value to authenticate. This gives
one consistent way to express two-factor extraction, attribute-driven
authentication, and cross-protocol routing across all five actions:
# Validate the static password portion of a combined <password><totp> field
pap {
secret radius.request.password | substring(0, -6);
}
# Validate the trailing 6 digits as the TOTP code
totp {
secret radius.request.password | substring(-6);
}
# Forward only the password portion to an upstream RADIUS server
backend {
name "UPSTREAM_RADIUS";
secret radius.request.password | substring(0, -6);
}
Masked password values such as radius.request.password are now revealed
automatically along the action pipeline so substring() and similar string
filters return the cleartext slice rather than the mask placeholder.
Radiator also includes a dedicated yubikey() filter for common password +
OTP deployments so they do not need hard-coded substring() offsets. The
filter takes a placement (where the OTP sits in the input) and an extract
(which component to return). For example,
radius.request.password | yubikey(password-otp, public-uid) validates
the trailing 44 characters as a Yubico OTP and returns the 12-character public
UID. Other extract values are otp (full 44-character OTP), ciphertext
(encrypted 32-character payload), and password (the static password sitting
next to the OTP in a combined PAP field). Combined with the new secret
parameter this becomes:
pap {
secret radius.request.password | yubikey(password-otp, password);
}
backend {
name "YUBIKEY_CLOUD_OTP";
secret radius.request.password | yubikey(password-otp, otp);
}
For YubiKey cloud validation with a local SQL ownership check, extract the presented public UID before the backend lookup and reject malformed input immediately:
modify vars.presented_yubikey_public_uid = radius.request.password | yubikey(password-otp, public-uid) | recover(none);
if all {
vars.presented_yubikey_public_uid == none;
} then {
reject "Malformed YubiKey OTP";
}
See YubiKey Authentication and Filters for usage examples and configuration guidance.
Readable multiline LDAP search filters
LDAP search filters now tolerate line breaks and indentation when you write them
as triple-quoted strings in Radiator configuration. Before this change,
triple-quoted strings preserved formatting exactly, which meant a readable filter
such as a multiline (&...) expression could fail before the LDAP search was
sent because RFC 4515 does not allow whitespace between filter components.
Radiator now strips layout-only whitespace from multiline LDAP filters before parsing and sending the search. This lets you format long compound filters for readability without changing the effective LDAP filter expression.
search "FIND_USER" {
base "dc=example,dc=com";
scope sub;
filter """
(&
(uid=%{aaa.identity})
(objectClass=inetOrgPerson)
)
""";
mapping {
user.username = uid;
}
}
See LDAP search operation for the updated filter documentation.
PBKDF2 password hashing
Radiator now verifies PBKDF2-HMAC-SHA1, PBKDF2-HMAC-SHA256 and
PBKDF2-HMAC-SHA512 stored passwords on all backends. The
{pbkdf2-sha512}, {pbkdf2-sha256}, {pbkdf2-sha1} and legacy
{pbkdf2} prefixes are accepted (case-insensitive, per RFC 2307bis) in
both PHC string format and the LDAP <iter>$<b64-salt>$<b64-hash>
layout. Iteration count and salt embedded in the hash are honoured.
See Password Hashing for details.
TACACS+ trace logging and packet size controls
Radiator now emits structured TACACS+ packet dissections at TRACE level for
incoming and outgoing TACACS+ traffic. TACACS+ servers also support per-server
max-packet-size, with a default of 4096 bytes and a maximum of 65536
bytes. Oversized frames are rejected, counted, and upsampled from Debug to
Warn at most once per minute.
See TACACS+ Authentication, Authorization, and Accounting
for the trace log format, a real packet example, and the operational guidance
for max-packet-size.
Files, Backups, and Empty Directories
The management files page no longer shows a pending-changes banner when there are no actual pending changes. Restoring from backup remains available from the files page overflow menu.
Backup list timestamps now follow the timestamp encoded in the backup name, including the newer server-ID-prefixed backup naming scheme.
Empty directory trees now behave as real configuration changes in pending configuration workflows. They are counted as deployable changes, survive deployment, and are preserved across backup download/import and backup restore flows.
RADIUS Backend connections Default Lowered to 10
The default value of connections in a RADIUS backend server (and in the
server-template of a radius-dns-sd backend) has been lowered from 1024 to
10. The previous default predated per-server connection accounting and was
larger than what almost any deployment actually used.
The new default matches the SQL backend defaults and keeps backend resource
usage predictable when min-connections is also configured.
How to migrate
If you previously relied on the implicit 1024 pool size, set connections
explicitly on each affected RADIUS backend server:
backends {
radius "UPSTREAM" {
server "primary" {
host "radius.example.com";
secret "mysecret";
connections 1024;
}
}
}
If you have not configured connections and your traffic comfortably fits in
10 concurrent connections, no action is required.
See connections for sizing guidance.
Template Render CLI Metadata Headers
radiator template render now writes the same generated-template metadata header that Management UI uses when it creates a configuration from a template. The header records the source template filename, template checksum, and template values so Management UI can later identify and edit the generated configuration through the template form.
Use --no-header when a script needs the previous body-only rendered output.
radiator template verify validates template metadata and template syntax. When given both a template file and a generated configuration file, it also verifies the generated file metadata, checksum, and rendered content.
@pre-client and clients Client Matching Changes
This release changes how servers resolve clients and tightens configuration validation for the affected server types: HTTP, RADIUS (UDP, TCP, TLS, reverse) and TACACS+ (TCP, TLS).
@pre-client and clients can co-exist
Servers that support @pre-client can now be configured with both
@pre-client and clients at the same time.
Radiator tries @pre-client first. If @pre-client does not select a
client, or returns an error, Radiator falls back to clients. This is
probably most useful for migrations from a static clients list to
dynamic matching, or as a failover path when the dynamic source is
temporarily unavailable.
See @pre-client and clients for details.
Breaking: servers require clients or @pre-client to start
The affected servers now refuse to start unless at least one of clients
or @pre-client is configured.
Previously, a RADIUS UDP server with neither setting started up and
logged a WARN "Radius UDP server has no clients configured" but
accepted no requests. The other servers returned generic startup errors
that did not clearly explain the missing setting.
From this release, every affected server fails configuration loading with:
<server> starting failed: either '@pre-client' or 'clients' must be configured
How to migrate
Audit your configuration for any server clauses that have no clients
binding and no @pre-client pipeline. Either:
- Reference an existing static clients list, or
- Add a @pre-client pipeline.
Server clauses commented out or relying on the previous "no clients" warning must be updated before upgrading.
TACACS+ RFC 9887 compatibility
Radiator can now be configured for an RFC 9887-compatible TACACS+ over TLS
deployment. Use TLS 1.3, mutual TLS, obfuscation disabled;, and
protocol-error-reply true; to match the RFC 9887 profile.
Certificate revocation checking is not supported, so CRL and OCSP validation remain outside this compatibility scope.
See TACACS+ Authentication, Authorization, and Accounting for setup examples and more details.
ipmap Startup and Populate Behavior Changes
This release changes how ipmap performs its initial population and how
manual repopulation is reported through the Management API.
Startup population now runs in the background
Radiator now always starts one ipmap populate run automatically when the
backend is created. That startup populate runs in the background.
Lookups do not wait for startup population to finish. Until the first
successful snapshot has been published, ipmap queries run against an empty
map and reject if no prefix matches.
This change avoids retaining request waiters during startup and keeps memory usage more predictable when the populate pipeline is large.
For startup-critical uses such as dynamic client resolution in @pre-client,
expect connecting clients to retry until the first snapshot is available.
See ipmap.
Breaking: prepopulate was removed
prepopulate true; is no longer supported in ipmap configuration.
Remove the setting from existing configurations:
backends {
ipmap "RADIUS_CLIENTS" {
interval 5m;
@populate {
backend {
name "SQLITE";
query "POPULATE_CLIENTS";
}
}
}
}
Radiator now performs startup population automatically, so no replacement setting is required.
Breaking: first lookup no longer triggers synchronous population
Earlier releases could populate ipmap on first use and make initial callers
wait for the populate pipeline to complete. That no longer happens.
If the first snapshot is not ready yet, early lookups reject. Review startup
paths that depend on ipmap and make sure clients can retry during startup.
Management API populate requests are now asynchronous
POST /api/v1/backends/{backend_name}/ipmap/populate now queues a manual
repopulation request and returns HTTP 200 immediately.
The HTTP response confirms that the request was accepted by the Management API. It does not mean that repopulation has completed successfully.
Check logs to confirm when repopulation succeeds or fails.
See ipmap.
PROXY Protocol Before TLS
Radiator now accepts proxy-protocol v2; together with tls { ... } on RADIUS/RadSec and TACACS+ TLS listeners.
See PROXY Protocol Support and servers.listen.proxy-protocol for configuration details.
Management UI Sidebar File Links
Sidebar items that open configuration files now keep file-related query parameters intact when navigating. This prevents links without a template-hint from turning the query string into part of the filename when opening or editing template-generated configuration files.
The configuration file details view also stops retrying file loads after a 404 response, so missing files show the not-found state immediately while transient failures still use the existing retry behavior.
Counter history retention extended to 7 days
The built-in default retention for counter and histogram history is now 7 days at 5 minute intervals (was 24 hours at 1 minute). Memory usage per counter is unchanged.
To keep the previous 1 minute granularity, set it explicitly:
statistics-counter {
samples 1440;
interval 60;
}
Floating-point gauges in statistics
Statistics endpoints previously returned only whole-number counters and silently filtered out floating-point gauges. Floating-point gauges are now returned alongside integer counters everywhere counter values appear:
GET /statistics/counters/{path}GET /statistics/counters/{path}/timeseriesGET /statistics/counters/{path}/childrenGET /statistics/counters/{path}/children/timeseriesGET /statistics/counters
Reset endpoints still operate only on integer counters; floating-point gauges have no reset operation and are skipped.
Prometheus /metrics renders non-finite values as NaN, +Inf, and
-Inf.
Documentation Index Usability
The documentation index now keeps card content aligned to the top, hides missing-description placeholders, and opens documentation pages at the top when you navigate from the index. Documentation search also accepts ?q=<term> links, so shared documentation URLs can open with a search term already filled in.
AAA side-effect actions preserve action results
Several AAA actions that only update context state or perform other side effects now preserve the previous action result instead of changing it. This prevents configurations such as ignore; modify { ... } or ignore; log "AUTHENTICATION" { ... } from accidentally turning the request into an accept.
This may be a minor breaking change for configurations that relied on these side-effect actions to set the result. However, using them for accept/reject/ignore decisions was a poor security practice; use explicit result-setting actions instead.
The corrected actions are modify, log, rewrite, message, reason, reject_errors, cache, and RADIUS proxy copy / filter.