VYPR
Medium severityNVD Advisory· Published May 28, 2026· Updated May 28, 2026

CVE-2026-41184

CVE-2026-41184

Description

In Calico, the install-cni init container logs the rendered CNI configuration to standard output. When the configuration template uses the __SERVICEACCOUNT_TOKEN__ placeholder (Canal/Flannel-Calico deployments), the installer substitutes the live Kubernetes ServiceAccount bearer token before logging, exposing the token to any authenticated user with pods/log permission in the namespace with calico-node. The token holds patch privileges on pods/status, enabling annotation-based attacks against cluster workloads. The default kubeconfig-based authentication path is not affected. This is a direct regression of TTA-2018-001.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

In Calico, the install-cni init container logs the live Kubernetes ServiceAccount token when using the __SERVICEACCOUNT_TOKEN__ placeholder, exposing it to anyone with pods/log permission in the calico-node namespace.

Vulnerability

The install-cni init container in Calico logs the rendered CNI configuration to standard output [1][2]. When the configuration template uses the __SERVICEACCOUNT_TOKEN__ placeholder (typical in Canal/Flannel-Calico deployments), the installer substitutes the live Kubernetes ServiceAccount bearer token before logging [2]. This exposes the token to any authenticated user with pods/log permission in the namespace where calico-node runs [1][2]. The default kubeconfig-based authentication path is not affected [2]. This is a direct regression of TTA-2018-001 [2]. Affected versions include all releases prior to the patch in branches 3.31 and 3.32 [1][2][3].

Exploitation

An attacker needs only read access to pod logs in the namespace where calico-node is deployed (typically kube-system or a dedicated namespace) [1][2]. The token is logged each time the install-cni container runs, so the attacker can retrieve it from the container logs [2]. The token has patch privileges on pods/status, which enables annotation-based attacks against cluster workloads [2]. No additional authentication or network position is required beyond the initial pods/log permission [1][2].

Impact

An attacker who retrieves the ServiceAccount token can use the token's patch pods/status permission to modify pod annotations [2]. This capability can be leveraged to tamper with running workloads, potentially escalating privileges or disrupting cluster operations [2]. The token does not grant full cluster-admin access, but the annotation-based attack surface is significant for workloads that rely on certain annotations for security or configuration [2].

Mitigation

The fix sanitizes the log output in the CNI plugin to redact the ServiceAccount token before logging [1][2][3]. The fix has been backported to release branches 3.31 and 3.32 [1][3]. Users should upgrade to patched versions: for the 3.31 branch, apply the backport PR #12527 [1]; for the 3.32 branch, apply the backport PR #12526 [3]. Alternatively, users can switch to the default kubeconfig-based authentication path, which is not affected [2]. As of the publication date, the CVE is not listed in the CISA Known Exploited Vulnerabilities (KEV) catalog.

AI Insight generated on May 28, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

1

Patches

3
da9ea3a13927

Merge pull request #12527 from Behnam-Shobiri/fix-logs31

https://github.com/projectcalico/calicoBehnam-ShobiriApr 17, 2026via nvd-ref
2 files changed · +10 9
  • cni-plugin/internal/pkg/azure/azure.go+7 2 modified
    @@ -30,7 +30,8 @@ func MutateConfigAdd(args *skel.CmdArgs, network AzureNetwork) error {
     	if err != nil {
     		return err
     	}
    -	logrus.Infof("Updated CNI network configuration for Azure Add: %#v", stdinData)
    +	// Don't log the entire stdinData here because it may contain sensitive information
    +	logrus.WithField("subnet", network.Subnets[0]).Info("Updated CNI network configuration for Azure Add")
     	return nil
     }
     
    @@ -67,6 +68,10 @@ func MutateConfigDel(args *skel.CmdArgs, network AzureNetwork, endpoint AzureEnd
     	if err != nil {
     		return err
     	}
    -	logrus.Infof("Updated CNI network configuration for Azure Del: %#v", stdinData)
    +	// Don't log the entire stdinData here because it may contain sensitive information
    +	logrus.WithFields(logrus.Fields{
    +		"subnet":    network.Subnets[0],
    +		"ipAddress": splits[0],
    +	}).Info("Updated CNI network configuration for Azure Del")
     	return nil
     }
    
  • cni-plugin/pkg/install/install.go+3 7 modified
    @@ -376,7 +376,8 @@ func writeCNIConfig(c config) {
     
     	err = isValidJSON(netconf)
     	if err != nil {
    -		logrus.Fatalf("%s is not a valid json object\nerror: %s", netconf, err)
    +		// Don't log the entire config/netconf here because it may contain sensitive information
    +		logrus.Fatalf("CNI config is not valid JSON: %v", err)
     	}
     
     	// Write out the file.
    @@ -401,13 +402,8 @@ func writeCNIConfig(c config) {
     		logrus.Fatal(err)
     	}
     
    -	content, err := os.ReadFile(path)
    -	if err != nil {
    -		logrus.Fatal(err)
    -	}
    +	// Do not log the config file (path) contents here — it may contain sensitive credentials.
     	logrus.Infof("Created %s", winutils.GetHostPath(fmt.Sprintf("/host/etc/cni/net.d/%s", name)))
    -	text := string(content)
    -	fmt.Println(text)
     
     	// Remove any old config file, if one exists.
     	oldName := getEnv("CNI_OLD_CONF_NAME", "10-calico.conflist")
    
0ca653db0ae7

Merge pull request #12526 from Behnam-Shobiri/fix-logs32

https://github.com/projectcalico/calicoBehnam-ShobiriApr 17, 2026via nvd-ref
2 files changed · +10 9
  • cni-plugin/internal/pkg/azure/azure.go+7 2 modified
    @@ -30,7 +30,8 @@ func MutateConfigAdd(args *skel.CmdArgs, network AzureNetwork) error {
     	if err != nil {
     		return err
     	}
    -	logrus.Infof("Updated CNI network configuration for Azure Add: %#v", stdinData)
    +	// Don't log the entire stdinData here because it may contain sensitive information
    +	logrus.WithField("subnet", network.Subnets[0]).Info("Updated CNI network configuration for Azure Add")
     	return nil
     }
     
    @@ -67,6 +68,10 @@ func MutateConfigDel(args *skel.CmdArgs, network AzureNetwork, endpoint AzureEnd
     	if err != nil {
     		return err
     	}
    -	logrus.Infof("Updated CNI network configuration for Azure Del: %#v", stdinData)
    +	// Don't log the entire stdinData here because it may contain sensitive information
    +	logrus.WithFields(logrus.Fields{
    +		"subnet":    network.Subnets[0],
    +		"ipAddress": splits[0],
    +	}).Info("Updated CNI network configuration for Azure Del")
     	return nil
     }
    
  • cni-plugin/pkg/install/install.go+3 7 modified
    @@ -381,7 +381,8 @@ func writeCNIConfig(c config) {
     
     	err = isValidJSON(netconf)
     	if err != nil {
    -		logrus.Fatalf("%s is not a valid json object\nerror: %s", netconf, err)
    +		// Don't log the entire config/netconf here because it may contain sensitive information
    +		logrus.Fatalf("CNI config is not valid JSON: %v", err)
     	}
     
     	// Write out the file.
    @@ -406,13 +407,8 @@ func writeCNIConfig(c config) {
     		logrus.Fatal(err)
     	}
     
    -	content, err := os.ReadFile(path)
    -	if err != nil {
    -		logrus.Fatal(err)
    -	}
    +	// Do not log the config file (path) contents here — it may contain sensitive credentials.
     	logrus.Infof("Created %s", winutils.GetHostPath(fmt.Sprintf("/host/etc/cni/net.d/%s", name)))
    -	text := string(content)
    -	fmt.Println(text)
     
     	// Remove any old config file, if one exists.
     	oldName := getEnv("CNI_OLD_CONF_NAME", "10-calico.conflist")
    
cd73bc2cea0f

Merge pull request #12502 from Behnam-Shobiri/fix-logs

https://github.com/projectcalico/calicoBehnam-ShobiriApr 17, 2026via nvd-ref
2 files changed · +10 9
  • cni-plugin/internal/pkg/azure/azure.go+7 2 modified
    @@ -30,7 +30,8 @@ func MutateConfigAdd(args *skel.CmdArgs, network AzureNetwork) error {
     	if err != nil {
     		return err
     	}
    -	logrus.Infof("Updated CNI network configuration for Azure Add: %#v", stdinData)
    +	// Don't log the entire stdinData here because it may contain sensitive information
    +	logrus.WithField("subnet", network.Subnets[0]).Info("Updated CNI network configuration for Azure Add")
     	return nil
     }
     
    @@ -67,6 +68,10 @@ func MutateConfigDel(args *skel.CmdArgs, network AzureNetwork, endpoint AzureEnd
     	if err != nil {
     		return err
     	}
    -	logrus.Infof("Updated CNI network configuration for Azure Del: %#v", stdinData)
    +	// Don't log the entire stdinData here because it may contain sensitive information
    +	logrus.WithFields(logrus.Fields{
    +		"subnet":    network.Subnets[0],
    +		"ipAddress": splits[0],
    +	}).Info("Updated CNI network configuration for Azure Del")
     	return nil
     }
    
  • cni-plugin/pkg/install/install.go+3 7 modified
    @@ -381,7 +381,8 @@ func writeCNIConfig(c config) {
     
     	err = isValidJSON(netconf)
     	if err != nil {
    -		logrus.Fatalf("%s is not a valid json object\nerror: %s", netconf, err)
    +		// Don't log the entire config/netconf here because it may contain sensitive information
    +		logrus.Fatalf("CNI config is not valid JSON: %v", err)
     	}
     
     	// Write out the file.
    @@ -406,13 +407,8 @@ func writeCNIConfig(c config) {
     		logrus.Fatal(err)
     	}
     
    -	content, err := os.ReadFile(path)
    -	if err != nil {
    -		logrus.Fatal(err)
    -	}
    +	// Do not log the config file (path) contents here — it may contain sensitive credentials.
     	logrus.Infof("Created %s", winutils.GetHostPath(fmt.Sprintf("/host/etc/cni/net.d/%s", name)))
    -	text := string(content)
    -	fmt.Println(text)
     
     	// Remove any old config file, if one exists.
     	oldName := getEnv("CNI_OLD_CONF_NAME", "10-calico.conflist")
    

Vulnerability mechanics

Root cause

"The install-cni init container logs the rendered CNI configuration to stdout after substituting the live Kubernetes ServiceAccount bearer token, exposing the token in plaintext logs."

Attack vector

An attacker with pods/log permission in the namespace running calico-node can read the install-cni init container logs. The init container substitutes the __SERVICEACCOUNT_TOKEN__ placeholder with the live Kubernetes ServiceAccount bearer token before writing the CNI configuration, then logs the rendered configuration to stdout [ref_id=1]. The exposed token holds patch privileges on pods/status, enabling annotation-based attacks against cluster workloads. The default kubeconfig-based authentication path is not affected; only Canal/Flannel-Calico deployments using the __SERVICEACCOUNT_TOKEN__ placeholder are vulnerable.

Affected code

The vulnerable code is in cni-plugin/pkg/install/install.go, which logs the full CNI config content during JSON validation and after writing the conflist [ref_id=1]. The Azure CNI mutation code in cni-plugin/internal/pkg/azure/azure.go also dumps full stdin JSON via %#v formatting [ref_id=1].

What the fix does

The patches [patch_id=2961930] [patch_id=2961931] [patch_id=2961932] sanitize CNI plugin log output by removing full config content from fatal logs and stopping the printing of generated CNI config file contents after writing the conflist [ref_id=1]. In the Azure CNI path, the fix replaces %#v dumps of stdinData with structured logs containing only selected fields, avoiding emission of the full config payload [ref_id=1]. These changes prevent the ServiceAccount token from appearing in log output.

Preconditions

  • authAttacker must have pods/log permission in the namespace running calico-node.
  • configDeployment must use the __SERVICEACCOUNT_TOKEN__ placeholder (Canal/Flannel-Calico deployments).
  • networkAttacker must be able to access the Kubernetes API server to read pod logs.

Generated on May 28, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.