VYPR
Moderate severityNVD Advisory· Published Jan 14, 2020· Updated Sep 16, 2024

CVE-2018-1002104

CVE-2018-1002104

Description

Versions < 1.5 of the Kubernetes ingress default backend, which handles invalid ingress traffic, exposed prometheus metrics publicly.

AI Insight

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

Kubernetes ingress default backend before version 1.5 exposed Prometheus metrics publicly via the same port as the default service.

Vulnerability

CVE-2018-1002104 affects the Kubernetes ingress default backend (the "defaultbackend" component) prior to version 1.5. The default backend, which serves 404 pages for unmatched ingress traffic, exposed Prometheus metric endpoints (e.g., /metrics) on the same HTTP port (8080) as the main service, without any access control. This made sensitive operational telemetry publicly accessible to anyone who could reach that port [1][2][4].

Attack

Vector

An attacker who can make network requests to the default backend’s port 8080 (for example, through an external load balancer or a direct port-forward) can retrieve the metrics without authentication. No special privileges are needed beyond network connectivity to the service [2][4]. The issue was reported by users who noticed that querying /metrics on the default backend returned detailed Prometheus metrics [4].

Impact

The exposed metrics contain internal operational data such as request count, request duration histograms, and other instrumentation details. While this does not directly allow code execution or privilege escalation, it leaks information that could aid in reconnaissance or be used to infer application usage patterns and potential performance bottlenecks [1][4].

Mitigation

The fix, introduced in defaultbackend version 1.5, separated the metrics and health-check endpoints onto a different port (10254), isolating them from the main service port [2]. Users should update to version 1.5 or later of the default backend component. The Kubernetes ingress-nginx project also recommends using the updated image and has since moved the default backend to a dedicated image that follows this secure-by-design pattern [3].

AI Insight generated on May 21, 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
k8s.io/ingress-nginxGo
< 1.51.5

Affected products

17

Patches

1
d487a50e3991

[404-server] conceal /metrics behind port 10254

https://github.com/kubernetes/ingress-nginxJonathan PulsiferSep 26, 2018via ghsa
3 files changed · +75 24
  • images/404-server/cloudbuild.yaml+1 1 modified
    @@ -3,7 +3,7 @@ timeout: 10800s
     substitutions:
       { "_ARCH": "amd64",
         "_REGISTRY": "gcr.io/k8s-image-staging",
    -    "_TAG": "1.4" }
    +    "_TAG": "1.5" }
     
     steps:
     - name: gcr.io/cloud-builders/git
    
  • images/404-server/Makefile+1 1 modified
    @@ -20,7 +20,7 @@
     
     all: push
     
    -TAG?=1.4
    +TAG?=1.5
     PREFIX?=gcr.io/google_containers/defaultbackend
     ARCH?=amd64
     
    
  • images/404-server/server.go+73 22 modified
    @@ -32,17 +32,71 @@ import (
     	"github.com/prometheus/client_golang/prometheus/promhttp"
     )
     
    -var port = flag.Int("port", 8080, "Port number to serve default backend 404 page.")
    -
     func init() {
     	// Register the summary and the histogram with Prometheus's default registry.
     	prometheus.MustRegister(requestCount)
     	prometheus.MustRegister(requestDuration)
     }
     
     func main() {
    +	// command line arguments
    +	port := flag.Int("port", 8080, "Port number to serve default backend 404 page.")
    +	healthPort := flag.Int("svc-port", 10254, "Port number to serve /healthz and /metrics.")
    +
    +	timeout := flag.Duration("timeout", 5*time.Second, "Time in seconds to wait before forcefully terminating the server.")
    +
     	flag.Parse()
    -	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    +
    +	notFound := newHTTPServer(fmt.Sprintf(":%d", *port), notFound())
    +	metrics := newHTTPServer(fmt.Sprintf(":%d", *healthPort), metrics())
    +
    +	// start the the healthz and metrics http server
    +	go func() {
    +		err := metrics.ListenAndServe()
    +		if err != http.ErrServerClosed {
    +			fmt.Fprintf(os.Stderr, "could not start healthz/metrics http server: %s\n", err)
    +			os.Exit(1)
    +		}
    +	}()
    +
    +	// start the main http server
    +	go func() {
    +		err := notFound.ListenAndServe()
    +		if err != http.ErrServerClosed {
    +			fmt.Fprintf(os.Stderr, "could not start http server: %s\n", err)
    +			os.Exit(1)
    +		}
    +	}()
    +
    +	waitShutdown(notFound, *timeout)
    +}
    +
    +type server struct {
    +	mux *http.ServeMux
    +}
    +
    +func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    +	s.mux.ServeHTTP(w, r)
    +}
    +
    +func newHTTPServer(addr string, handler http.Handler) *http.Server {
    +	return &http.Server{
    +		Addr:              addr,
    +		Handler:           handler,
    +		ReadTimeout:       10 * time.Second,
    +		ReadHeaderTimeout: 10 * time.Second,
    +		WriteTimeout:      10 * time.Second,
    +		IdleTimeout:       10 * time.Second,
    +	}
    +}
    +func notFound(options ...func(*server)) *server {
    +	s := &server{mux: http.NewServeMux()}
    +	// TODO: this handler exists only to avoid breaking existing deployments
    +	s.mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
    +		w.WriteHeader(http.StatusOK)
    +		fmt.Fprint(w, "ok")
    +	})
    +	s.mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
     		start := time.Now()
     		w.WriteHeader(http.StatusNotFound)
     		fmt.Fprint(w, "default backend - 404")
    @@ -55,32 +109,29 @@ func main() {
     		requestCount.WithLabelValues(proto).Inc()
     		requestDuration.WithLabelValues(proto).Observe(duration)
     	})
    -	http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
    +	return s
    +}
    +
    +func metrics() *server {
    +	s := &server{mux: http.NewServeMux()}
    +	s.mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
     		w.WriteHeader(http.StatusOK)
     		fmt.Fprint(w, "ok")
     	})
    -	http.Handle("/metrics", promhttp.Handler())
    -
    -	srv := &http.Server{
    -		Addr: fmt.Sprintf(":%d", *port),
    -	}
    -
    -	go func() {
    -		err := srv.ListenAndServe()
    -		if err != http.ErrServerClosed {
    -			fmt.Fprintf(os.Stderr, "could not start http server: %s\n", err)
    -			os.Exit(1)
    -		}
    -	}()
    +	s.mux.Handle("/metrics", promhttp.Handler())
    +	return s
    +}
     
    +func waitShutdown(s *http.Server, timeout time.Duration) {
     	stop := make(chan os.Signal, 1)
    -	signal.Notify(stop, syscall.SIGTERM)
    +	signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
     	<-stop
     
    -	ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
    +	fmt.Fprintf(os.Stdout, "stopping http server...\n")
    +	ctx, cancel := context.WithTimeout(context.Background(), timeout)
     	defer cancel()
    -	err := srv.Shutdown(ctx)
    -	if err != nil {
    -		fmt.Fprintf(os.Stderr, "could not graceful shutdown http server: %s\n", err)
    +
    +	if err := s.Shutdown(ctx); err != nil {
    +		fmt.Fprintf(os.Stderr, "could not gracefully shutdown http server: %s\n", err)
     	}
     }
    

Vulnerability mechanics

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

References

5

News mentions

0

No linked articles in our index yet.