⚠️ Action Required
Immediate patching required, especially for users of BackendTLSPolicy and istioctl analyze. Review other fixes to ensure stability and better support for your mesh.


πŸ“ Summary

Istio 1.30.5 brings vital security enhancements and critical stability improvements. Two significant security fixes address a BackendTLSPolicy vulnerability (GHSA-qm8v-g4f9-qhjx) that could lead to plaintext traffic, now safely failing closed. Additionally, istioctl analyze now sanitizes multi-cluster kubeconfig secrets, preventing arbitrary command execution.For Ambient Mesh users, this release delivers more predictable behavior with deterministic network gateway selection, eliminating unnecessary Workload Discovery Service (WDS) pushes. The CNI component benefits from a stable iptables backend detection, resolving flip-flopping issues across restarts. Workload Discovery Service (WDS) performance also sees a boost with pre-marshaled data and improved incremental update handling.Key fixes include ServiceEntries with empty selectors no longer matching all workloads, ensuring precise traffic control. JWKS resolution is more robust with default HTTP/2, and Envoy stats intervals now properly support sub-second and minute-plus configurations. The Gateway API’s ListenerSet status reporting is more accurate, providing clearer insights into resource health. Upgrade promptly to benefit from these crucial updates.


πŸ”’ Critical Security Fix: BackendTLSPolicy Fail-Closed for Unresolved CA Refs

πŸ”’ Security Advisory
CVE ID: GHSA-qm8v-g4f9-qhjx
CVSS Score: 6.5 (Medium)

This release addresses a critical fail-open vulnerability (GHSA-qm8v-g4f9-qhjx) in BackendTLSPolicy, ensuring that unresolved caCertificateRefs no longer lead to upstream traffic being sent in plaintext. This vital fix enhances the security posture of your mesh by making sidecar proxies fail closed, preventing unintended data exposure and enforcing your defined security policies.

Previously, if a BackendTLSPolicy’s caCertificateRefs could not be resolved, sidecar proxies would fallback to sending traffic without TLS, exposing it in plaintext. The fix ensures that such a configuration will now result in the traffic being blocked rather than downgraded to plaintext. Users can rely on this behavior to enforce secure communication strictly.

Source:

  • releasenotes/notes/backendtlspolicy-sidecar-failclosed.yaml (8-10)

πŸ”’ High-Severity Fix: istioctl analyze Multi-Cluster Kubeconfig Sanitization

A high-severity vulnerability has been addressed in istioctl analyze, safeguarding against potential arbitrary command execution. This fix prevents malicious multi-cluster secrets from compromising the machine running istioctl by ensuring all kubeconfig inputs are now sanitized, rejecting unsafe authentication methods.

The istioctl analyze command previously built Kubernetes clients directly from istio-system multi-cluster secrets without proper sanitization. This allowed specially crafted kubeconfigs to leverage exec credential plugins or other unsafe auth fields to run arbitrary commands on the istioctl host. The updated implementation now uses kube.NewUntrustedRestConfig to sanitize these kubeconfigs, rejecting unsafe fields and building the client from the sanitized configuration:

// Secrets in this namespace are untrusted input from the perspective of this
// process, exactly as istiod treats them in DefaultBuildClientsFromConfig. Sanitize
// the kubeconfig - rejecting exec, file-based, or other unsafe auth - and build the
// client from the sanitized rest.Config itself, not from the original bytes, so a
// gap between what's validated and what's used can't reopen this.
restConfig, err := kube.NewUntrustedRestConfig(cfg)
if err != nil {
	return nil, fmt.Errorf("kubeconfig in secret %s/%s is not allowed: %v", s.Namespace, s.Name, err)
}
rawConfig, err := clientcmd.Load(cfg)
if err != nil {
	return nil, err
}
// ...
client, err := kube.NewCLIClient(kube.NewClientConfigForRestConfig(restConfig),
	kube.WithRevision(revisionSpecified),
	kube.WithCluster(cluster.ID(curContext.Cluster)))

Source:

  • istioctl/pkg/analyze/analyze.go (551-568)
  • istioctl/pkg/analyze/analyze_test.go (19-115)
  • releasenotes/notes/analyze-multicluster-secret-sanitize.yaml (1-13)

✨ Ambient Mesh: Deterministic Network Gateway Selection

For Ambient Mesh users, this update brings enhanced predictability to network gateway selection. By ensuring a stable and deterministic order when a network has multiple gateway entries, this change eliminates random gateway assignments, which previously caused unnecessary Workload Discovery Service (WDS) pushes and could lead to inconsistent gateway addresses for workloads.

The LookupNetworkGateway function in the Ambient Index now consistently sorts the list of available network gateways by their resource name. This ensures that the selection order remains stable across recomputes and restarts, providing a more reliable and less noisy control plane.

func LookupNetworkGateway(
	ctx context.Context,
	id network.ID,
	gatewaysByNetwork krt.Index[network.ID, NetworkGateway],
) []NetworkGateway {
	res := gatewaysByNetwork.Fetch(ctx, id)
	// index lookups iterate a map and callers take the first entry, so the order must be stable
	slices.SortBy(res, NetworkGateway.ResourceName)
	return res
}

Source:

  • pilot/pkg/serviceregistry/ambient/ambientindex.go (811-813)
  • pilot/pkg/serviceregistry/ambient/networks_test.go (1-55)
  • releasenotes/notes/ambient-network-gateway-order.yaml (1-8)

πŸš€ Enhanced Performance & Stability for Workload Discovery (WDS) in Ambient

This release significantly improves the performance and reliability of Workload Discovery Service (WDS) in Ambient Mesh, particularly when AMBIENT_SCOPED_ADDRESS_PUSHES is enabled. It ensures that proxies receive all necessary incremental workload updates, preventing missed pushes and optimizing the efficiency of data synchronization between istiod and Envoy.

Several changes contribute to more robust WDS behavior. The AddressInfo struct now includes MarshaledWorkload to store pre-marshaled workload data, reducing serialization overhead. Critically, the DefaultProxyNeedsPush logic has been refined to correctly identify when WorkloadType subscribers require pushes based on address-only changes, and the WorkloadGenerator now properly handles nil subscriptions. This eliminates scenarios where proxies might miss crucial incremental updates.

type AddressInfo struct {
	*workloadapi.Address
	Marshaled *anypb.Any
	// MarshaledWorkload contains the pre-marshaled inner Workload, when present.
	MarshaledWorkload *anypb.Any
	// Version is a content-based hash of Marshaled, sent as the resource version over WDS.
	// Clients echo it back in InitialResourceVersions on reconnect, letting the server skip
	// resources the client already has; hashing the content keeps versions consistent across
	// pushes, even across Pilot restarts, when WorkloadAddress changes aren't published.
	Version string
}

// ...
	workloadsUpdated := len(req.AddressesUpdated) > 0 && proxy.GetWatchedResource(v3.WorkloadType) != nil
	return req, workloadsUpdated || len(req.ConfigsUpdated) > 0

Source:

  • pilot/pkg/model/service.go (1138-1153)
  • pilot/pkg/model/service_test.go (29-41)
  • pilot/pkg/serviceregistry/ambient/ambientindex.go (614-617)
  • pilot/pkg/serviceregistry/ambient/ambientindex_test.go (2897-2900)
  • pilot/pkg/xds/delta_test.go (238-269)
  • pilot/pkg/xds/proxy_dependencies.go (78-81, 130-132)
  • pilot/pkg/xds/proxy_dependencies_test.go (40-62)
  • pilot/pkg/xds/util_test.go (21-39)
  • pilot/pkg/xds/workload.go (104-107, 187-190)
  • releasenotes/notes/61648.yaml (1-8)

πŸ› Ambient CNI: Stabilized iptables Backend Detection

This release resolves a long-standing issue in ambient mode where the CNI node agent’s auto-detected iptables backend (legacy vs nft) could ‘flip-flop’ across restarts. This fix prevents the agent from misdetecting existing rules, eliminating the writing of duplicate redirect rules into already-enrolled pods and ensuring consistent, stable network configuration.

The hasExistingRules function, used to determine the correct iptables backend, was previously prone to misdetection. It would interpret an otherwise empty table (materialized by a kernel probe adding and deleting a no-op rule) as having existing rules, causing the backend to flip. The updated logic now specifically checks for actual rule lines (those starting with -A or -I ) rather than just counting the total number of lines in the iptables-save output. This ensures accurate and stable detection across restarts.

func hasExistingRules(rulesDump []byte) bool {
	for _, line := range strings.Split(string(rulesDump), "\n") {
		if strings.HasPrefix(line, "-A ") || strings.HasPrefix(line, "-I ") {
			return true
		}
	}
	return false
}

Source:

  • tools/istio-iptables/pkg/dependencies/implementation_linux.go (135-152)
  • tools/istio-iptables/pkg/dependencies/implementation_linux_test.go (27-61)
  • releasenotes/notes/61020.yaml (1-10)

πŸ› ServiceEntry: Empty Workload Selectors Now Match Nothing

This update corrects an important behavior in ServiceEntries, ensuring that those configured with a present but empty workload selector no longer inadvertently match all workloads within their namespace. This fix restores the intended precise control over traffic management, preventing unwanted service exposure and simplifying configuration for service owners.

Previously, a ServiceEntry with an empty WorkloadSelector (e.g., workloadSelector: {}) would implicitly match all workloads in its namespace. This behavior was unintended and could lead to broad, unmanaged traffic routing. The controller now explicitly checks if the WorkloadSelector.Labels map is non-empty before fetching workloads, ensuring that an empty selector correctly results in no workload matches.

		var selectedWorkloads []*model.WorkloadInstance

		// SE with empty workload selector will not select any workloads
		if len(se.WorkloadSelector.Labels) != 0 {
			selectedWorkloads = workloadsByNamespace.Fetch(
				ctx,
				cfg.Namespace,
				krt.FilterLabel(se.WorkloadSelector.Labels),
				krt.FilterGeneric(func(o any) bool {
					wi := o.(*model.WorkloadInstance)
					if wi.DNSServiceEntryOnly && !dnsService {
						return false
					}
					return true
				}),
			)
		}

Source:

  • pilot/pkg/serviceregistry/serviceentry/conversion.go (540-549)
  • pilot/pkg/serviceregistry/serviceentry/controller_test.go (716-729)
  • releasenotes/notes/serviceentry-empty-workload-selector.yaml (1-6)

⚑ Improved JWKS Resolution with Default HTTP/2

This release enhances the reliability of JSON Web Key Set (JWKS) resolution, particularly in environments with custom TLS configurations or certain HTTP CONNECT proxies. By explicitly enabling HTTP/2 by default for JWKS fetches, Istio ensures smoother communication and prevents failures that previously occurred due to automatic HTTP/1.1 fallback.

The Go net/http client, when configured with custom TLSClientConfig or DialContext (as used for TLS pinning and CIDR blocking), would previously disable automatic HTTP/2 negotiation via ALPN. This led to JWKS fetches failing over HTTP/1.1 in some scenarios. This update explicitly sets ForceAttemptHTTP2: true on the http.Transport for both secure and insecure JWKS resolvers, ensuring HTTP/2 is always attempted first, matching http.DefaultTransport’s behavior.

			Transport: &http.Transport{
				Proxy:             http.ProxyFromEnvironment,
				DisableKeepAlives: true,
				DialContext:       blockedCIDRDialContext,
				ForceAttemptHTTP2: true,
			},
		},

Source:


πŸ“Š Telemetry: Robust Envoy Stats Interval Configuration

Telemetry configurations for Envoy proxies are now more robust, with critical fixes that ensure statsFlushInterval and statsEvictionInterval annotations are correctly applied. This eliminates previous issues where sub-second or minute-plus durations would result in invalid Envoy bootstraps, preventing proxy startup failures and maintaining precise telemetry settings.

Envoy bootstrap generation had issues accurately rendering duration values for stats intervals, particularly for values of one minute or more, and for sub-second precision. The code now uses durationpb.New to correctly convert time.Duration values into durationpb.Duration protobuf messages, ensuring that Envoy receives valid configurations for its stats flushing and eviction intervals.

d, err := time.ParseDuration(v)
	if err == nil {
		statsFlushInterval = d
		options = append(options, option.EnvoyStatsFlushInterval(durationpb.New(statsFlushInterval)))
	} else {
		log.Warnf("Failed to parse stats flush interval %v: %v", v, err)
	}
// ...
	options = append(options, option.EnvoyStatsEvictionInterval(durationpb.New(statsEvictionInterval)))

Source:

  • pkg/bootstrap/config.go (322-337)
  • pkg/bootstrap/option/instances.go (308-311)
  • releasenotes/notes/fix-stats-interval-duration-rendering.yaml (1-11)
  • pkg/bootstrap/instance_test.go (227-235)

βœ… Gateway API: Accurate ListenerSet Status Reporting

This update significantly improves the transparency and accuracy of status reporting for ListenerSet resources within the Gateway API. Operations engineers can now quickly identify misconfigurations or issues, as a ListenerSet with no valid listeners will correctly reflect its state, providing clearer diagnostics.

Previously, ListenerSet-level conditions (Accepted, Programmed) could incorrectly remain True even when all of its individual listeners were invalid. This fix ensures that when a ListenerSet has no valid listeners, its Accepted and Programmed conditions are accurately reported as False with the reason ListenersNotValid. This provides a consistent and reliable signal about the usability of the ListenerSet.

status:
  conditions:
  - lastTransitionTime: fake
    message: None of the ListenerSet's listeners are valid
    reason: ListenersNotValid
    status: "False"
    type: Accepted
  - lastTransitionTime: fake
    message: None of the ListenerSet's listeners are valid
    reason: ListenersNotValid
    status: "False"
    type: Programmed

Source:

  • pilot/pkg/config/kube/gateway/testdata/listenerset-cross-namespace.status.yaml.golden (48-56)
  • pilot/pkg/config/kube/gateway/testdata/listenerset-cross-namespace.yaml (99-106)
  • releasenotes/notes/listenerset-listeners-not-valid.yaml (1-9)

Minor Updates & Housekeeping

This release includes routine maintenance and dependency updates. The BASE_VERSION has been updated to 1.30-2026-09-17T19-00-53, and PROXY_REPO_SHA and ZTUNNEL_REPO_SHA have been bumped for core components. Various Go modules were updated, including github.com/docker/cli, go.opentelemetry.io/otel components, google.golang.org/grpc, github.com/google/go-containerregistry, and github.com/containernetworking/cni for overall stability and security. Additionally, a fix prevents observedGeneration from getting stuck on stale values in the status work queue, ensuring status updates are not silently dropped.