Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spoofing of X-Forwarded-Host header is possible during redirect to HTTPS #13158

Open
617m4rc opened this issue Apr 4, 2025 · 1 comment
Open
Labels
kind/bug Categorizes issue or PR as related to a bug. needs-priority needs-triage Indicates an issue or PR lacks a `triage/foo` label and requires one.

Comments

@617m4rc
Copy link

617m4rc commented Apr 4, 2025

What happened:

It is possible to spoof the X-Forwarded-Host header during the HTTP to HTTPS redirect in Ingress NGINX. This may allow an attacker to manipulate the redirect behavior by providing a malicious or incorrect X-Forwarded-Host value.

What you expected to happen:

Ingress NGINX should properly handle the X-Forwarded-Host header and prevent it from being spoofed. X-Forwarded headers should only be considered safe from the CIDR ranges defined in property proxy-real-ip-cidr.

NGINX Ingress controller version (exec into the pod and run /nginx-ingress-controller --version):

-------------------------------------------------------------------------------
NGINX Ingress controller
  Release:       v1.12.1
  Build:         51c2b819690bbf1709b844dbf321a9acf6eda5a7
  Repository:    https://github.com/kubernetes/ingress-nginx
  nginx version: nginx/1.25.5

-------------------------------------------------------------------------------

Kubernetes version (use kubectl version): 1.32

Environment:

  • Cloud provider or hardware configuration: AWS EKS
  • OS (e.g. from /etc/os-release): Bottlerocket
  • Kernel (e.g. uname -a): Linux ingress-nginx-gh-controller-649f86695b-7bsm2 6.1.124 #1 SMP PREEMPT_DYNAMIC Sat Jan 25 00:17:27 UTC 2025 x86_64 Linux
  • Install tools:
    • Cluster deployed via Terraform
  • Basic cluster related info:

Client Version: v1.32.3 Kustomize Version: v5.5.0 Server Version: v1.32.2-eks-bc803b4

NAME                                                  STATUS   ROLES    AGE   VERSION               INTERNAL-IP    EXTERNAL-IP   OS-IMAGE                                KERNEL-VERSION                  CONTAINER-RUNTIME
xxx   Ready    <none>   9d    v1.32.0-eks-5ca49cb   10.0.204.226   <none>        Amazon Linux 2                          5.10.234-225.910.amzn2.x86_64   containerd://1.7.25
xxx     Ready    <none>   11d   v1.32.0-eks-5ca49cb   10.0.74.3      <none>        Amazon Linux 2                          5.10.234-225.910.amzn2.x86_64   containerd://1.7.25
xxx           Ready    <none>   11h   v1.32.0-eks-2e66e76   10.0.101.104   <none>        Bottlerocket OS 1.32.0 (aws-k8s-1.32)   6.1.124                         containerd://1.7.24+bottlerocket
xxx          Ready    <none>   11h   v1.32.0-eks-2e66e76   10.0.102.164   <none>        Bottlerocket OS 1.32.0 (aws-k8s-1.32)   6.1.124                         containerd://1.7.24+bottlerocket
xxx          Ready    <none>   11h   v1.32.0-eks-2e66e76   10.0.109.145   <none>        Bottlerocket OS 1.32.0 (aws-k8s-1.32)   6.1.124                         containerd://1.7.24+bottlerocket
xxx           Ready    <none>   11h   v1.32.0-eks-2e66e76   10.0.116.60    <none>        Bottlerocket OS 1.32.0 (aws-k8s-1.32)   6.1.124                         containerd://1.7.24+bottlerocket
xxx           Ready    <none>   11h   v1.32.0-eks-2e66e76   10.0.153.23    <none>        Bottlerocket OS 1.32.0 (aws-k8s-1.32)   6.1.124                         containerd://1.7.24+bottlerocket
xxx          Ready    <none>   11h   v1.32.0-eks-2e66e76   10.0.172.111   <none>        Bottlerocket OS 1.32.0 (aws-k8s-1.32)   6.1.124                         containerd://1.7.24+bottlerocket
xxx           Ready    <none>   11h   v1.32.0-eks-2e66e76   10.0.172.44    <none>        Bottlerocket OS 1.32.0 (aws-k8s-1.32)   6.1.124                         containerd://1.7.24+bottlerocket
xxx           Ready    <none>   11h   v1.32.0-eks-2e66e76   10.0.177.173   <none>        Bottlerocket OS 1.32.0 (aws-k8s-1.32)   6.1.124                         containerd://1.7.24+bottlerocket
xxx          Ready    <none>   11h   v1.32.0-eks-2e66e76   10.0.189.164   <none>        Bottlerocket OS 1.32.0 (aws-k8s-1.32)   6.1.124                         containerd://1.7.24+bottlerocket
xxx           Ready    <none>   11h   v1.32.0-eks-2e66e76   10.0.198.209   <none>        Bottlerocket OS 1.32.0 (aws-k8s-1.32)   6.1.124                         containerd://1.7.24+bottlerocket
xxx            Ready    <none>   11h   v1.32.0-eks-2e66e76   10.0.211.8     <none>        Bottlerocket OS 1.32.0 (aws-k8s-1.32)   6.1.124                         containerd://1.7.24+bottlerocket
xxx          Ready    <none>   11h   v1.32.0-eks-2e66e76   10.0.227.230   <none>        Bottlerocket OS 1.32.0 (aws-k8s-1.32)   6.1.124                         containerd://1.7.24+bottlerocket
xxx          Ready    <none>   11h   v1.32.0-eks-2e66e76   10.0.246.197   <none>        Bottlerocket OS 1.32.0 (aws-k8s-1.32)   6.1.124                         containerd://1.7.24+bottlerocket
xxx            Ready    <none>   11h   v1.32.0-eks-2e66e76   10.0.253.65    <none>        Bottlerocket OS 1.32.0 (aws-k8s-1.32)   6.1.124                         containerd://1.7.24+bottlerocket
xxx           Ready    <none>   11h   v1.32.0-eks-2e66e76   10.0.94.237    <none>        Bottlerocket OS 1.32.0 (aws-k8s-1.32)   6.1.124                         containerd://1.7.24+bottlerocket
  • How was the ingress-nginx-controller installed:

    • If helm was used then please show output of helm ls -A | grep -i ingress

ingress-nginx xxx 7 2025-03-06 05:24:31.654774386 +0000 UTC deployed ingress-nginx-4.12.0 1.12.0

  • If helm was used then please show output of helm -n <ingresscontrollernamespace> get values <helmreleasename>
USER-SUPPLIED VALUES:
controller:
  allowSnippetAnnotations: false
  config:
    enable-ocsp: true
    enable-owasp-modsecurity-crs: "true"
    enable-real-ip: true
    generate-request-id: true
    hsts-max-age: "31536000"
    http-snippet: ssl_conf_command Ciphersuites TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256;
    proxy-connect-timeout: "60"
    proxy-read-timeout: "1800"
    proxy-real-ip-cidr: 10.0.0.0/16
    proxy-send-timeout: "1800"
    real-ip-recursive: "on"
    ssl-ciphers: ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES256-GCM-SHA384
    ssl-protocols: TLSv1.2 TLSv1.3
    ssl-session-cache: "true"
    ssl-session-cache-size: 10m
    upstream-keepalive-requests: "1000"
    upstream-keepalive-timeout: "55"
    use-forwarded-headers: "true"
    use-http2: true
    use-proxy-protocol: "true"
    worker-shutdown-timeout: 60s
  service:
    annotations:
      service.beta.kubernetes.io/aws-load-balancer-access-log-emit-interval: "60"
      service.beta.kubernetes.io/aws-load-balancer-access-log-enabled: "true"
      service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-name: xxx
      service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags: xxx
      service.beta.kubernetes.io/aws-load-balancer-attributes: dns_record.client_routing_policy=availability_zone_affinity
      service.beta.kubernetes.io/aws-load-balancer-backend-protocol: tcp
      service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "false"
      service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: instance
      service.beta.kubernetes.io/aws-load-balancer-proxy-protocol: '*'
      service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
      service.beta.kubernetes.io/aws-load-balancer-type: nlb-ip
    externalTrafficPolicy: Local
  ...
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: xxx
    nginx.ingress.kubernetes.io/backend-protocol: HTTP
    nginx.ingress.kubernetes.io/enable-opentracing: "false"
    nginx.ingress.kubernetes.io/proxy-body-size: 0m
    nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
    nginx.ingress.kubernetes.io/service-upstream: "true"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
  creationTimestamp: "2025-02-25T08:32:21Z"
  generation: 1
  name: ingress
  namespace: xxx
spec:
  rules:
  - host: xxx.mysaas.com
    http:
      paths:
      - backend:
          service:
            name: xxx
            port:
              number: 80
        path: /
        pathType: Prefix
  tls:
  - hosts:
    - xxx.mysaas.com
    secretName: tls-secret
status:
  loadBalancer:
    ingress:
    - hostname: xxx

How to reproduce this issue:

  • Install Ingress NGINX via Helm chart and set parameter proxy-real-ip-cidr.
  • Create an ingress with annotation nginx.ingress.kubernetes.io/ssl-redirect: "true"
  • make a request with spoofed X-Forwarded-Host header

Note that the request needs to be via HTTP and not HTTPS to reproduce the redirect.

curl --path-as-is -i -s -k -v -X $'GET' -H $'Host: xxx.mysaas.com' -H $'X-Forwarded-Host: kubernetes.github.io/ingress-nginx' $'http://xxx.mysaas.com/'

Result:

HTTP/1.1 308 Permanent Redirect
Date: Fri, 04 Apr 2025 15:45:46 GMT
Content-Type: text/html
Content-Length: 164
Connection: keep-alive
Location: https://kubernetes.github.io/ingress-nginx

<html>
<head><title>308 Permanent Redirect</title></head>
<body>
<center><h1>308 Permanent Redirect</h1></center>
<hr><center>nginx</center>
</body>
</html>
@617m4rc 617m4rc added the kind/bug Categorizes issue or PR as related to a bug. label Apr 4, 2025
@k8s-ci-robot
Copy link
Contributor

This issue is currently awaiting triage.

If Ingress contributors determines this is a relevant issue, they will accept it by applying the triage/accepted label and provide further guidance.

The triage/accepted label can be added by org members by writing /triage accepted in a comment.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@k8s-ci-robot k8s-ci-robot added needs-triage Indicates an issue or PR lacks a `triage/foo` label and requires one. needs-priority labels Apr 4, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/bug Categorizes issue or PR as related to a bug. needs-priority needs-triage Indicates an issue or PR lacks a `triage/foo` label and requires one.
Projects
Development

No branches or pull requests

2 participants