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

CVE-2026-41185

CVE-2026-41185

Description

When Calico is configured with the Azure IPAM plugin, the Calico CNI binary mutates the incoming CNI configuration to attach subnet information before delegating to the IPAM plugin. After mutating, the Azure IPAM helper logs the entire unmarshaled configuration map (stdinData) at INFO level to /var/log/calico/cni/cni.log on every CNI ADD and DEL invocation — once per pod scheduled or terminated on the node. When the cluster is deployed using token-based Kubernetes authentication, this log entry contains the ServiceAccount token, client key, and certificate authority in plaintext. Any principal with read access to /var/log/calico/cni/cni.log on a node  can read these logs and extract the credentials, which grant cluster-wide Calico networking admin privileges.

AI Insight

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

Calico CNI with Azure IPAM logs Kubernetes ServiceAccount tokens and credentials in plaintext, allowing local privilege escalation to Calico admin.

Vulnerability

When Calico is configured with the Azure IPAM plugin, the Calico CNI binary mutates the incoming CNI configuration to attach subnet information before delegating to the IPAM plugin. After mutating, the Azure IPAM helper logs the entire unmarshaled configuration map (stdinData) at INFO level to /var/log/calico/cni/cni.log on every CNI ADD and DEL invocation — once per pod scheduled or terminated on the node. When the cluster is deployed using token-based Kubernetes authentication, this log entry contains the ServiceAccount token, client key, and certificate authority in plaintext. Affected versions include all Calico releases prior to the fixes in pull requests #12502, #12527 (release 3.31), and #12526 (release 3.32). [1][2][3]

Exploitation

An attacker needs only read access to /var/log/calico/cni/cni.log on any node in the cluster. No additional authentication or network position is required. The log is written on every pod creation (CNI ADD) and deletion (CNI DEL), so the attacker can repeatedly observe the log file. By parsing the log entries, the attacker can extract the ServiceAccount token, client key, and CA certificate embedded in the configuration map. [1][2]

Impact

Successful extraction of the credentials grants the attacker cluster-wide Calico networking admin privileges. With these credentials, the attacker can manipulate Calico network policies, routing, and potentially disrupt or monitor all cluster network traffic. The compromise is at the Calico admin level, which can affect the entire Kubernetes cluster's network security. [1][2]

Mitigation

The vulnerability is fixed in Calico releases 3.31 and 3.32 via pull requests #12527 and #12526 respectively, which sanitize the log output to remove sensitive credentials. [1][2][3] Users should upgrade to these patched versions. If an immediate upgrade is not possible, restrict read access to /var/log/calico/cni/cni.log to only root or the Calico components. No known listing in CISA's Known Exploited Vulnerabilities (KEV) catalog as of publication date.

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

2

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 Azure IPAM helper logs the entire unmarshaled CNI configuration map (stdinData) at INFO level, which includes ServiceAccount tokens, client keys, and certificate authority material when token-based Kubernetes authentication is used."

Attack vector

When Calico is configured with the Azure IPAM plugin, the CNI binary mutates the incoming configuration to attach subnet information before delegating to the IPAM plugin. After mutation, the Azure IPAM helper logs the entire unmarshaled configuration map (stdinData) at INFO level to /var/log/calico/cni/cni.log on every CNI ADD and DEL invocation [ref_id=1]. In clusters using token-based Kubernetes authentication, this log entry contains the ServiceAccount token, client key, and certificate authority in plaintext. Any principal with read access to that log file on a node can extract these credentials, which grant cluster-wide Calico networking admin privileges.

Affected code

cni-plugin/internal/pkg/azure/azure.go — the Azure IPAM helper logs the entire stdinData map using %#v formatting [ref_id=1]. cni-plugin/pkg/install/install.go — the install helper outputs full config/netconf content in fatal logs and prints the generated CNI config file contents after writing it [ref_id=1].

What the fix does

The patch in [patch_id=2961927] (backported via [patch_id=2961929]) replaces the %#v dump of stdinData in cni-plugin/internal/pkg/azure/azure.go with structured logs that emit only selected fields, avoiding the full config payload [ref_id=1]. The companion patch [patch_id=2961928] removes full config/netconf output from fatal logs and stops printing config file contents after writing the CNI conflist in cni-plugin/pkg/install/install.go [ref_id=1]. Together these changes prevent sensitive credentials embedded in the CNI configuration from being written to logs.

Preconditions

  • configCalico must be configured with the Azure IPAM plugin.
  • configThe cluster must use token-based Kubernetes authentication (so the ServiceAccount token, client key, and CA are present in the CNI config).
  • authThe attacker must have read access to /var/log/calico/cni/cni.log on a node.

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.