You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@flink.apache.org by "Dennis-Mircea Ciupitu (Jira)" <ji...@apache.org> on 2026/08/18 15:34:00 UTC

[jira] [Created] (FLINK-40414) Autoscaler state ConfigMap is treated as trusted input

Dennis-Mircea Ciupitu created FLINK-40414:
---------------------------------------------

             Summary: Autoscaler state ConfigMap is treated as trusted input
                 Key: FLINK-40414
                 URL: https://issues.apache.org/jira/browse/FLINK-40414
             Project: Flink
          Issue Type: Bug
          Components: Autoscaler, Kubernetes Operator
            Reporter: Dennis-Mircea Ciupitu


h1. Summary

The autoscaler persists its state in a per-resource ConfigMap ({{autoscaler-<name>}}): scaling history, collected metrics, scaling tracking, delayed scale-down, parallelism overrides and config overrides. The operator reads that ConfigMap back on every cycle and acts on its contents, but treats it as trusted input. The ConfigMap is writable by any workload in the namespace, so a poisoned or corrupt entry can break a reconcile or influence a managed deployment.

h1. Trust boundary

The autoscaler state ConfigMap is created and owned by the operator, but the default Flink job Role grants the job service account {{create/update/patch/delete}} on {{configmaps}} in its namespace (required for Kubernetes HA). Tenant code running in a TaskManager or JobManager pod can therefore write any ConfigMap in the namespace, including the autoscaler state of another job.

Among the ConfigMaps the operator handles, only the autoscaler state ConfigMap has its content deserialized and acted upon. The generated cluster config and pod-template ConfigMaps are write-only from the operator, and the Kubernetes HA ConfigMaps are read only by name and key presence, never by value. The autoscaler state ConfigMap is the operator's untrusted-input surface.

h1. Problems

h2. Reads are not uniformly fail-closed

The six read paths handle a bad stored value inconsistently:

* {{getParallelismOverrides}} has no error handling. A malformed value throws out of the read and into the reconcile loop.
* {{getConfigChanges}} falls back to empty on a bad value but does not discard the poisoned entry, so it is re-read and re-parsed every cycle.
* The remaining four discard the bad entry and fall back to empty.

So the same class of input is variously ignored, re-read, or allowed to propagate an exception.

h2. Config overrides are applied to the deployment spec unfiltered

When memory tuning is enabled, the config overrides read from the ConfigMap are merged into {{spec.flinkConfiguration}} with no key filtering. A poisoned entry can therefore inject arbitrary Flink configuration, for example {{env.java.opts}} or a pod template, into a managed deployment. This is an escalation from "write one ConfigMap" to influencing how and what the managed cluster runs, potentially across jobs within a namespace.

h2. No value sanity

Values read from the ConfigMap, such as the per-vertex parallelism overrides, are applied without basic validity checks.

h1. Impact

* Integrity and availability: a crafted entry can break a reconcile through an unhandled exception, or feed the autoscaler bogus history and metrics that steer scaling for that job or a co-tenant.
* Config injection: with memory tuning enabled, arbitrary Flink configuration reaches the managed deployment spec.
* Current exposure is bounded by {{job.autoscaler.memory.tuning.enabled}} (default off) for the injection path, but the design flaw is independent of that flag.

This is not a deserialization remote-code-execution issue. The mapper uses no default typing and binds to concrete types, so malformed input fails to bind rather than instantiating arbitrary classes. The risk is integrity, availability and config injection.

h1. Scope

This completes the autoscaler-adjacent security review alongside FLINK-40400 (artifact fetch SSRF) and FLINK-40401 (decompression bomb on the compressed state fields). Those two harden individual fields or paths as issues surfaced. This item addresses the general untrusted-read boundary of the state ConfigMap so the class of problem is closed rather than one instance.

h1. Proposed approach

At a high level:

* Treat every read from the autoscaler state ConfigMap as untrusted: deserialize uniformly and fail closed, discarding the offending entry and falling back to empty on any failure, plus light value sanity on the values that are applied.
* Filter config overrides on apply against the set of keys memory tuning is actually allowed to set, so that only memory-tuning keys can reach the deployment spec.

Out of scope: deeper hardening of scaling decisions against plausible but wrong metrics, and the decompression size bound owned by FLINK-40401.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)