Servers, proxies and network services

rsyslog: CVE-2026-92709 dynaFile path traversal

rsyslog dynaFile audit

rsyslog's omfile dynaFile feature builds an output file name from a template. When a template puts a value an outsider can influence into a path without secure-path handling, the path can escape the log directory (CVE-2026-92709). That value can be the HOSTNAME or program name of an incoming message, the message text or structured data. rsyslog usually runs as root or with wide write access to /var/log, so this becomes an arbitrary file write. The advisory and several trackers take it further to code execution.

CVE CVE-2026-92709 (GHSA-xmp9-244p-5ggv, published 22 October 2026)
Severity High, CVSS 8.1 (attack complexity high)
Affected rsyslog 1.15.0 through 8.2610.0, when a dynaFile template uses an untrusted value in a path component without secure-path handling
Remedy Run mitigate now and install the rsyslog release that fully patches CVE-2026-92709 when it is published
Defense The documented, recommended one, which works on every version: explicit secure-path handling for each untrusted value in a dynaFile path
Not limited to The RFC 5424 HOSTNAME field. Any untrusted value that reaches a path component creates the condition
Exploit A PoC reference is listed by one aggregator. The page we saw contained only the advisory text

The configuration decides your exposure, not the version, which is why this is a configuration audit. On the rsyslog 8.2312.0 default configuration it correctly reports that nothing builds a path from message data. The daily stable documentation describes new dynaFile controls and a rule that the path must stay under a fixed leading prefix, which hints that a fix is on the way. No release carries it yet, so do not wait for it.

The fix, validated

# string templates
template(name="DynFile" type="string"
         string="/var/log/hosts/%HOSTNAME:::secpath-replace%/%programname:::secpath-replace%.log")

# legacy syntax
$template DynFile,"/var/log/%HOSTNAME:::secpath-replace%/%programname:::secpath-replace%.log"

# list templates
template(name="DynFileList" type="list") {
  constant(value="/var/log/hosts/")
  property(name="hostname" securePath="replace")
  constant(value="/")
  property(name="programname" securePath="replace")
  constant(value=".log")
}

secpath-drop (remove the slashes) is the alternative to secpath-replace (replace them with underscores). All of these forms were validated with rsyslogd -N1 on a real rsyslog 8.2312.0.

Caution: do not copy global(compatibility.defaults.secure="strict") onto an older rsyslog. It defaults unprotected dynaFile fields to secpath-replace, but it is only known to newer versions. On 8.2312.0 rsyslogd -N1 rejects it with "parameter 'compatibility.defaults.secure' not known". Test every change with rsyslogd -N1 before you restart.

Quick start

  1. Download the script. The repository is mirrored on GitHub and Codeberg; pick a base URL.

    # BASE from GitHub:   https://raw.githubusercontent.com/PrivacySafe/security-patches/refs/heads/main
    # BASE from Codeberg: https://codeberg.org/PrivacySafe/security-patches/raw/branch/main
    # curl -fLO "$BASE/rsyslog/rsyslog-dynafile-audit.sh"
    curl -fLO https://raw.githubusercontent.com/PrivacySafe/security-patches/refs/heads/main/rsyslog/rsyslog-dynafile-audit.sh
    
  2. Read it before running it, then make it executable.

    less rsyslog-dynafile-audit.sh
    chmod +x rsyslog-dynafile-audit.sh
    
  3. Audit this host. It reads /etc/rsyslog.conf and everything it includes. No root is needed unless your configuration is unreadable to your user.

    ./rsyslog-dynafile-audit.sh audit
    

Commands

Command What it does
audit (default) Reads the rsyslog version, the main configuration and everything included through $IncludeConfig and include(file=...) (files, globs and directories, with a loop guard), finds templates used by dynaFile and by the legacy ?Template action, and lists every path component that comes from an untrusted property without secure-path handling. Reports whether network input modules are configured and which user rsyslogd runs as
mitigate [--dry-run] [--restart] Changes the host (root). For every template that a dynaFile action uses, adds secpath-replace to each untrusted property (%HOSTNAME% becomes %HOSTNAME:::secpath-replace%; in list templates securePath="replace" is added to the property). Never touches a template no dynaFile uses, or a property that already has secure-path handling. Copies every file first, checks the configuration with rsyslogd -N1 before and after, restores the originals at once if rsyslog rejects the result, restarts nothing unless you add --restart, then runs the audit again and tells you if anything was missed (a template written across lines with a backslash is not rewritten)
rollback [--dry-run] [--restart] Puts back every file mitigate changed
version Prints the script version

Environment: RSYSLOG_CONF (space separated files) replaces configuration discovery. STATE_DIR (default /var/lib/psf-security-patches/rsyslog) holds the backups and manifest.

On rsyslog 8.2312.0, rsyslogd -N1 accepts every form the rewrite produces (legacy $template strings, RainerScript string templates, list templates and property options such as %msg:1:5:lowercase,secpath-replace%). This is the defense rsyslog documents. A template used both as a file path and as a message format would have its message changed too, so look at what mitigate --dry-run would change first.

Exit codes: 0 no unprotected untrusted value in a dynaFile path, 1 at least one was found or could not be judged, 2 bad arguments.

Commands that change the host need root. Run them with sudo from an admin account, not from a root login, so the change is recorded against a person. The script stops and prints the exact command if you forget:

sudo ./rsyslog-dynafile-audit.sh mitigate --dry-run
sudo ./rsyslog-dynafile-audit.sh mitigate
sudo ./rsyslog-dynafile-audit.sh rollback

How it classifies properties

  • Treated as untrusted: hostname, source, fromhost, programname, app-name, syslogtag, msg, rawmsg, procid, msgid, structured-data, protocol-version, and any message variable starting $!.
  • Treated as not controllable by a sender: fromhost-ip, inputname, timegenerated, timereported, timestamp, now, the date parts, the priority and facility properties, and $now, $year, $month, $day, $hour, $minute, $myhostname.
  • Unrecognized: anything else, including local variables ($.name). The script warns, because it cannot tell whether a sender can influence the value, and exits 1.
  • Protected: a property whose options contain secpath-replace, secpath-drop or securepath, in string templates (%name:::options%) and list templates (securePath=).

How to read the result

  • Unprotected untrusted property: add secure-path handling to each one, test with rsyslogd -N1, then restart.
  • Strict mode set: shown as protected only by the global setting, with a warning to confirm your rsyslog accepts it.
  • A dynaFile template that is not defined in the files read, or a subtree or plugin template: reported for manual review, with exit 1.
  • No dynaFile at all: nothing here builds a path from message data. A template that is defined but never used by dynaFile is ignored.
  • Network input configured: senders you do not control can reach the templates. Local sources such as imuxsock and imjournal can still carry attacker-chosen program names.
  • rsyslogd running as root: a path escape writes as root. Run it as an unprivileged user and keep its writable area to the log directories. Debian and Ubuntu drop to syslog by default.

This is a text search over the configuration, not a full parser. Unusual layouts, generated configuration, and templates built through other mechanisms may be missed.

Sources

Before you run it

  • This is an audit of your configuration, not a version check. Run mitigate now, and install the rsyslog release that fully patches CVE-2026-92709 when it is published.
  • It only matters with an untrusted value in a path component. The flaw applies when a dynaFile template puts a value an outside party can influence (the hostname or program name of an incoming message, the message text, structured data) into a path component without secure-path handling.
  • The documented defense works on every version. Use explicit secure-path handling in the template. Rsyslog usually runs as root or with broad write access to /var/log, which is why an escape is an arbitrary file write.
  • There is no hunt. No indicators of exploitation have been published.

The Security Patches software and this documentation are dedicated to the public domain under CC0 1.0 Universal. Other pages on privacysafe.app/docs are CC BY-SA 4.0 unless the page says otherwise.

Edit this page on Codeberg

The PrivacySafe Ecosystem

Shop at Ivy Cyber

Ivy Cyber offers PrivacySafe products and services in the USA and has partnerships with 3NSoft in Canada and Kuip Limited in the European Union. Enterprise services and consulting are available at ivycyber.com

PrivacySafe Foundation is a 501(c)(3) nonprofit public charity that supports the development of the PrivacySafe applications, along with the components they rely upon: 3NWeb protocols, filesystem, documentation, and reference implementations.

PrivacySafe Foundation

Donations to PrivacySafe Foundation support education, research, documentation, and public code. Purchases from Ivy Cyber support PrivacySafe products, services, hosting, and technical support. Together, we're building a better web.