VYPR
High severityNVD Advisory· Published Nov 12, 2019· Updated Aug 5, 2024

CVE-2019-18817

CVE-2019-18817

Description

Istio 1.3.x before 1.3.5 allows Denial of Service because continue_on_listener_filters_timeout is set to True, a related issue to CVE-2019-18836.

AI Insight

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

Istio 1.3.x before 1.3.5 has a Denial of Service vulnerability because continue_on_listener_filters_timeout is set to True, allowing high CPU usage.

Vulnerability

Overview

CVE-2019-18817 is a Denial of Service (DoS) vulnerability in Istio versions 1.3.x prior to 1.3.5. The root cause is that the configuration parameter continue_on_listener_filters_timeout is set to True, which causes Envoy proxies to continue processing requests even when listener filters timeout. This leads to a state where the sidecar proxy can consume excessive CPU resources, effectively creating a DoS condition [1][4].

Exploitation

Details

The vulnerability can be triggered without requiring authentication or special network position, as it affects the default behavior of Istio's sidecar proxy. An attacker can exploit this by sending requests that cause listener filters to timeout, which under the vulnerable configuration will not abort the connection but instead allow processing to continue. This results in the proxy entering a high-CPU loop, as observed in reported user issues where the istio-proxy CPU usage was pinned at 1.0 core [2]. The issue manifests particularly in deployments with multiple containers per pod, where the sidecar processes traffic for multiple services.

Impact

Successful exploitation leads to a Denial of Service condition where the affected Istio sidecar consumes nearly all available CPU resources, degrading or completely blocking traffic for the associated application workload. This can impact the availability of services within the service mesh, affecting multiple pods in the same deployment [2].

Mitigation

The Istio project has fixed this vulnerability in version 1.3.5. The fix involves recovering from panics in the patching of Envoy filters, ensuring that when filters timeout the proxy does not enter an infinite loop [1]. Users are advised to upgrade to Istio 1.3.5 or later. There are no known workarounds for versions prior to 1.3.5.

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

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
istio.io/istioGo
>= 1.3.0, < 1.3.51.3.5

Affected products

2

Patches

1
7570a1f5b56c

Recover panics from patching envoyfilters (#17292) (#18536)

https://github.com/istio/istioJohn HowardNov 6, 2019via ghsa
8 files changed · +90 22
  • pilot/pkg/networking/core/v1alpha3/envoyfilter/cluster_patch.go+12 2 modified
    @@ -19,14 +19,24 @@ import (
     	"github.com/gogo/protobuf/proto"
     
     	networking "istio.io/api/networking/v1alpha3"
    +	"istio.io/pkg/log"
     
     	"istio.io/istio/pilot/pkg/model"
    +	"istio.io/istio/pilot/pkg/networking/util"
     	"istio.io/istio/pkg/config/host"
     )
     
     // ApplyClusterPatches applies patches to CDS clusters
    -func ApplyClusterPatches(patchContext networking.EnvoyFilter_PatchContext, proxy *model.Proxy,
    -	push *model.PushContext, clusters []*xdsapi.Cluster) []*xdsapi.Cluster {
    +func ApplyClusterPatches(
    +	patchContext networking.EnvoyFilter_PatchContext,
    +	proxy *model.Proxy,
    +	push *model.PushContext,
    +	clusters []*xdsapi.Cluster) (out []*xdsapi.Cluster) {
    +	defer util.HandleCrash(func() {
    +		log.Errorf("clusters patch caused panic, so the patches did not take effect")
    +	})
    +	// In case the patches cause panic, use the clusters generated before to reduce the influence.
    +	out = clusters
     
     	envoyFilterWrappers := push.EnvoyFilters(proxy)
     	clustersRemoved := false
    
  • pilot/pkg/networking/core/v1alpha3/envoyfilter/listener_patch.go+13 2 modified
    @@ -22,14 +22,25 @@ import (
     	"github.com/gogo/protobuf/proto"
     	"github.com/gogo/protobuf/types"
     
    +	"istio.io/pkg/log"
    +
     	networking "istio.io/api/networking/v1alpha3"
     	"istio.io/istio/pilot/pkg/model"
     	"istio.io/istio/pilot/pkg/networking/util"
     )
     
     // ApplyListenerPatches applies patches to LDS output
    -func ApplyListenerPatches(patchContext networking.EnvoyFilter_PatchContext,
    -	proxy *model.Proxy, push *model.PushContext, listeners []*xdsapi.Listener, skipAdds bool) []*xdsapi.Listener {
    +func ApplyListenerPatches(
    +	patchContext networking.EnvoyFilter_PatchContext,
    +	proxy *model.Proxy,
    +	push *model.PushContext,
    +	listeners []*xdsapi.Listener,
    +	skipAdds bool) (out []*xdsapi.Listener) {
    +	defer util.HandleCrash(func() {
    +		log.Errorf("listeners patch caused panic, so the patches did not take effect")
    +	})
    +	// In case the patches cause panic, use the listeners generated before to reduce the influence.
    +	out = listeners
     
     	envoyFilterWrappers := push.EnvoyFilters(proxy)
     	return doListenerListOperation(proxy, patchContext, envoyFilterWrappers, listeners, skipAdds)
    
  • pilot/pkg/networking/core/v1alpha3/envoyfilter/rc_patch.go+12 3 modified
    @@ -24,11 +24,20 @@ import (
     
     	networking "istio.io/api/networking/v1alpha3"
     	"istio.io/istio/pilot/pkg/model"
    +	"istio.io/istio/pilot/pkg/networking/util"
    +	"istio.io/pkg/log"
     )
     
    -func ApplyRouteConfigurationPatches(patchContext networking.EnvoyFilter_PatchContext,
    -	proxy *model.Proxy, push *model.PushContext,
    -	routeConfiguration *xdsapi.RouteConfiguration) *xdsapi.RouteConfiguration {
    +func ApplyRouteConfigurationPatches(
    +	patchContext networking.EnvoyFilter_PatchContext,
    +	proxy *model.Proxy,
    +	push *model.PushContext,
    +	routeConfiguration *xdsapi.RouteConfiguration) (out *xdsapi.RouteConfiguration) {
    +	defer util.HandleCrash(func() {
    +		log.Errorf("listeners patch caused panic, so the patches did not take effect")
    +	})
    +	// In case the patches cause panic, use the route generated before to reduce the influence.
    +	out = routeConfiguration
     
     	envoyFilterWrappers := push.EnvoyFilters(proxy)
     	for _, efw := range envoyFilterWrappers {
    
  • pilot/pkg/networking/util/util.go+21 0 modified
    @@ -18,6 +18,7 @@ import (
     	"fmt"
     	"math"
     	"net"
    +	"runtime"
     	"sort"
     	"strconv"
     	"strings"
    @@ -520,3 +521,23 @@ func MergeAnyWithAny(dst *types.Any, src *types.Any) (*types.Any, error) {
     
     	return retVal, nil
     }
    +
    +// logPanic logs the caller tree when a panic occurs.
    +func logPanic(r interface{}) {
    +	// Same as stdlib http server code. Manually allocate stack trace buffer size
    +	// to prevent excessively large logs
    +	const size = 64 << 10
    +	stacktrace := make([]byte, size)
    +	stacktrace = stacktrace[:runtime.Stack(stacktrace, false)]
    +	log.Errorf("Observed a panic: %#v (%v)\n%s", r, r, stacktrace)
    +}
    +
    +// HandleCrash catches the crash and calls additional handlers.
    +func HandleCrash(handlers ...func()) {
    +	if r := recover(); r != nil {
    +		logPanic(r)
    +		for _, handler := range handlers {
    +			handler()
    +		}
    +	}
    +}
    
  • pilot/pkg/networking/util/util_test.go+29 0 modified
    @@ -615,3 +615,32 @@ func TestMergeAnyWithStruct(t *testing.T) {
     		t.Errorf("Merged HCM does not match the expected output")
     	}
     }
    +
    +func TestHandleCrash(t *testing.T) {
    +	defer func() {
    +		if x := recover(); x != nil {
    +			t.Errorf("Expected no panic ")
    +		}
    +	}()
    +
    +	defer HandleCrash()
    +	panic("test")
    +}
    +
    +func TestCustomHandleCrash(t *testing.T) {
    +	ch := make(chan struct{}, 1)
    +	defer func() {
    +		select {
    +		case <-ch:
    +			t.Logf("crash handler called")
    +		case <-time.After(1 * time.Second):
    +			t.Errorf("Custom handler not called")
    +		}
    +	}()
    +
    +	defer HandleCrash(func() {
    +		ch <- struct{}{}
    +	})
    +
    +	panic("test")
    +}
    
  • pilot/pkg/proxy/envoy/v2/cds.go+1 5 modified
    @@ -15,7 +15,6 @@
     package v2
     
     import (
    -	"fmt"
     	"time"
     
     	xdsapi "github.com/envoyproxy/go-control-plane/envoy/api/v2"
    @@ -75,14 +74,11 @@ func (s *DiscoveryServer) generateRawClusters(node *model.Proxy, push *model.Pus
     
     	for _, c := range rawClusters {
     		if err := c.Validate(); err != nil {
    -			retErr := fmt.Errorf("CDS: Generated invalid cluster for node %v: %v", node, err)
     			adsLog.Errorf("CDS: Generated invalid cluster for node:%s: %v, %v", node.ID, err, c)
     			cdsBuildErrPushes.Increment()
     			totalXDSInternalErrors.Increment()
     			// Generating invalid clusters is a bug.
    -			// Panic instead of trying to recover from that, since we can't
    -			// assume anything about the state.
    -			panic(retErr.Error())
    +			// Instead of panic, which will break down the whole cluster. Just ignore it here, let envoy process it.
     		}
     	}
     	return rawClusters
    
  • pilot/pkg/proxy/envoy/v2/lds.go+1 5 modified
    @@ -15,7 +15,6 @@
     package v2
     
     import (
    -	"fmt"
     	"time"
     
     	xdsapi "github.com/envoyproxy/go-control-plane/envoy/api/v2"
    @@ -51,13 +50,10 @@ func (s *DiscoveryServer) generateRawListeners(con *XdsConnection, push *model.P
     
     	for _, l := range rawListeners {
     		if err := l.Validate(); err != nil {
    -			retErr := fmt.Errorf("LDS: Generated invalid listener for node %v: %v", con.modelNode, err)
     			adsLog.Errorf("LDS: Generated invalid listener for node:%s: %v, %v", con.modelNode.ID, err, l)
     			ldsBuildErrPushes.Increment()
     			// Generating invalid listeners is a bug.
    -			// Panic instead of trying to recover from that, since we can't
    -			// assume anything about the state.
    -			panic(retErr.Error())
    +			// Instead of panic, which will break down the whole cluster. Just ignore it here, let envoy process it.
     		}
     	}
     	return rawListeners
    
  • pilot/pkg/proxy/envoy/v2/rds.go+1 5 modified
    @@ -15,7 +15,6 @@
     package v2
     
     import (
    -	"fmt"
     	"time"
     
     	xdsapi "github.com/envoyproxy/go-control-plane/envoy/api/v2"
    @@ -57,13 +56,10 @@ func (s *DiscoveryServer) generateRawRoutes(con *XdsConnection, push *model.Push
     	// Now validate each route
     	for _, r := range rawRoutes {
     		if err := r.Validate(); err != nil {
    -			retErr := fmt.Errorf("RDS: Generated invalid route %s for node %v: %v", r.Name, con.modelNode, err)
     			adsLog.Errorf("RDS: Generated invalid routes for route:%s for node:%v: %v, %v", r.Name, con.modelNode.ID, err, r)
     			rdsBuildErrPushes.Increment()
     			// Generating invalid routes is a bug.
    -			// Panic instead of trying to recover from that, since we can't
    -			// assume anything about the state.
    -			panic(retErr.Error())
    +			// Instead of panic, which will break down the whole cluster. Just ignore it here, let envoy process it.
     		}
     	}
     	return rawRoutes
    

Vulnerability mechanics

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

References

7

News mentions

0

No linked articles in our index yet.