Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,7 @@
- [ServiceNow](network-services-pentesting/pentesting-web/servicenow.md)
- [Spring Actuators](network-services-pentesting/pentesting-web/spring-actuators.md)
- [Symfony](network-services-pentesting/pentesting-web/symphony.md)
- [Traefik HTTP/3 Slow-Body Timeout Testing](network-services-pentesting/pentesting-web/traefik.md)
- [Tomcat](network-services-pentesting/pentesting-web/tomcat/README.md)
- [Telerik Ui Aspnet Ajax Unsafe Reflection Webresource Axd](network-services-pentesting/pentesting-web/telerik-ui-aspnet-ajax-unsafe-reflection-webresource-axd.md)
- [Uncovering CloudFlare](network-services-pentesting/pentesting-web/uncovering-cloudflare.md)
Expand Down
1 change: 1 addition & 0 deletions src/network-services-pentesting/pentesting-web/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ Some **tricks** for **finding vulnerabilities** in different well known **techno
- [**ServiceNow**](servicenow.md)
- [**Spring Actuators**](spring-actuators.md)
- [**Symphony**](symphony.md)
- [**Traefik / HTTP/3 slow-body timeouts**](traefik.md)
- [**Tomcat**](tomcat/index.html)
- [**VMWare**](vmware-esx-vcenter....md)
- [**Web API Pentesting**](web-api-pentesting.md)
Expand Down
74 changes: 74 additions & 0 deletions src/network-services-pentesting/pentesting-web/traefik.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Traefik HTTP/3 Slow-Body Timeout Testing

{{#include ../../banners/hacktricks-training.md}}

## HTTP/3 slow-body resource exhaustion

Traefik normally applies `entryPoints.<name>.transport.respondingTimeouts.readTimeout` to the TCP connection used by HTTP/1.1 and HTTP/2. HTTP/3 uses QUIC instead: in the affected implementation, Traefik copied the HTTPS `Handler` into a separate quic-go `http3.Server` but did not carry over an equivalent request-read deadline. The timeout could therefore appear in parsed configuration and DEBUG output while remaining ineffective for HTTP/3.<sup>[[1]](#references)[[3]](#references)</sup>

An attacker can start a valid HTTP/3 upload and then send body bytes very slowly, or stop sending without closing the stream. If the reverse proxy has already opened a connection to an application that reads the complete body before responding, every incomplete request can pin one upstream connection. Many low-bandwidth requests can consequently exhaust a bounded backend connection pool without requiring a traffic-volume flood.<sup>[[1]](#references)[[3]](#references)</sup>

This protocol-differential bug affected Traefik `v2.8.2` through `v2.11.55` and `v3.0.0` through `v3.7.11`; the maintained fixes are `v2.11.56` and `v3.7.12`.<sup>[[1]](#references)</sup>

## Differential validation

Test only an authorized environment and begin with one request per protocol. The backend used for validation **must consume the complete request body before responding** and log when its accepted connection is released; otherwise Traefik may release the upstream immediately and hide whether a resource was retained. Client-side waiting by itself proves only that the client has not received a response.<sup>[[1]](#references)[[3]](#references)</sup>

For a short lab run, enable HTTP/3 and reduce the incoming read timeout on the same HTTPS entrypoint:<sup>[[1]](#references)</sup>

```yaml
entryPoints:
websecure:
address: ":8443"
http3:
advertisedPort: 8443
transport:
respondingTimeouts:
readTimeout: 5s
```

Then send identical uploads over HTTP/1.1 and HTTP/3. Ensure that the total body duration exceeds the configured timeout; a curl build with HTTP/3 support is required for `--http3-only`.<sup>[[1]](#references)[[3]](#references)</sup>

```bash
URL='https://localhost:8443/'
slow_body() { for _ in $(seq 1 8); do printf x; sleep 4; done; }

slow_body | curl -vk -T - --http1.1 "$URL"
slow_body | curl -vk -T - --http3-only "$URL"
```

Interpret the test using both proxy output and backend connection-lifetime logs:<sup>[[1]](#references)[[3]](#references)</sup>

| Observation | Meaning |
| --- | --- |
| HTTP/1.1 releases the upstream near 5 seconds, but HTTP/3 retains it for the complete upload | The control proves that the setting is active while the QUIC request path bypasses it. |
| Both protocols release the upstream near 5 seconds | Equivalent request-read enforcement is probably present. |
| Both protocols outlive 5 seconds | The control failed; recheck the active entrypoint, configuration, route, and backend behavior. |
| `--http3-only` cannot connect | HTTP/3 was not demonstrated on that endpoint; this does not test the condition. |

For the default 60-second setting, increase the upload window beyond one minute. The original reproducer used 23 bytes separated by four-second pauses and observed the upstream leg rather than inferring retention from curl alone.<sup>[[1]](#references)[[3]](#references)</sup>

## White-box review checklist

Treat timeout configuration as a claim to verify, not proof of enforcement. Review each protocol-specific server construction and follow the value to the primitive that interrupts body reads:<sup>[[1]](#references)[[3]](#references)</sup>

- A `SetReadDeadline` call on a TCP socket cannot constrain a QUIC stream.
- Reusing an `http.Handler` does not automatically inherit the source `http.Server` timeouts, limits, or cancellation behavior.
- A deadline implementation must interrupt a `Read` that is **already blocked** waiting for the next body byte. Merely checking elapsed time after `Read` returns remains bypassable when the peer stops transmitting.
- With a custom quic-go body wrapper, expiry must close or cancel the HTTP/3 body/stream; closing quic-go's HTTP/3 body cancels the stream read and unblocks the handler.

The Traefik fix wraps the HTTP/3 handler and uses `http.NewResponseController(rw).SetReadDeadline(...)` for requests that may carry a body. It also propagates `IdleTimeout` and `MaxHeaderBytes` to `http3.Server`, providing a useful review pattern for protocol-parity regressions.<sup>[[2]](#references)</sup>

## Operational signals and remediation

Slow bodies are syntactically valid and transfer little data, so byte-rate or request-rate alerts alone may miss them. Correlate protocol (`h3`), unusually long request-body duration, active upstream connections, pool wait time, and requests terminated with deadline errors. A growing backend pool with long-lived HTTP/3 uploads is more useful evidence than a client that simply remains connected.<sup>[[1]](#references)[[3]](#references)</sup>

Upgrade affected installations to Traefik `v2.11.56`, `v3.7.12`, or a later maintained release. Unsupported affected branches require migration rather than waiting for a branch-specific patch.<sup>[[1]](#references)</sup>

## References

- [1] [Traefik security advisory GHSA-7ghq-v6jf-g56c](https://github.com/traefik/traefik/security/advisories/GHSA-7ghq-v6jf-g56c)
- [2] [Traefik patch: apply read timeout, idle timeout, and maximum header size to HTTP/3](https://github.com/traefik/traefik/commit/a8d0bc425859dde7481a6c9a324e610b81d754d0)
- [3] [Bishop Fox - Traefik HTTP/3 Request Read Timeout Bypass Through Version 3.7.11](https://bishopfox.com/blog/traefik-version-through-3-7-11)

{{#include ../../banners/hacktricks-training.md}}