From 31cc155b3ff3639d8a855660344a612bae7262d8 Mon Sep 17 00:00:00 2001 From: K3UL Date: Sat, 24 Oct 2026 16:46:14 +0200 Subject: [PATCH 1/2] Exclude Brotli from default AutomaticDecompression (CVE-2026-111497) The Brotli decoder vendored in the .NET runtime (System.IO.Compression.Native) has an out-of-bounds write, CVE-2026-111497, reachable from a crafted Content-Encoding: br response. No fixed runtime has shipped. With AutomaticDecompression defaulting to All, every RestClient built with default options advertised br and routed untrusted responses through that decoder. Default is now GZip | Deflate on .NET. Opting back in is one line: AutomaticDecompression = DecompressionMethods.All. .NET Framework default (GZip) is unchanged. --- docs/docs/advanced/configuration.md | 16 +++++++- docs/docs/changelog.md | 6 +++ src/RestSharp/Options/RestClientOptions.cs | 11 +++++- .../CompressionTests.cs | 39 +++++++++++++++++++ 4 files changed, 69 insertions(+), 3 deletions(-) diff --git a/docs/docs/advanced/configuration.md b/docs/docs/advanced/configuration.md index bc8a59037..4f3f51d01 100644 --- a/docs/docs/advanced/configuration.md +++ b/docs/docs/advanced/configuration.md @@ -160,7 +160,7 @@ RestSharp allows configuring `RestClient` using client options, as mentioned at | `Credentials` | Instance of `ICredentials` used for NTLM or Kerberos authentication. Not supported in browsers. | | `UseDefaultCredentials` | Whether to use default OS credentials for NTLM or Kerberos authentication. Not supported in browsers. | | `DisableCharset` | When set to `true`, the `Content-Type` header won't have the `charset` portion. Some older web servers don't understand the `charset` portion in the header and fail to process the request. | -| `AutomaticDecompression` | Allows customizing supported decompression methods. Default is `All` except for .NET Framework that only support `GZip`. Not supported in browsers. | +| `AutomaticDecompression` | Allows customizing supported decompression methods. Default is `GZip \| Deflate` on .NET and `GZip` on .NET Framework. Brotli is not enabled by default, see the [note below](#brotli-decompression). Not supported in browsers. | | `MaxRedirects` | The number of redirects to follow. Delegates to `RedirectOptions.MaxRedirects`. Default is 50. | | `ClientCertificates` | A collection of X.509 client certificates to be used for authentication. Not supported in browsers. | | `Proxy` | Can be used if the client needs to use an explicit, non-default proxy. Not supported in browsers, on iOS and tvOS. | @@ -195,6 +195,20 @@ Some of the options are used by RestSharp code, but some are only used to config If setting these options to non-default values produce no desirable effect, check if your framework and platform supports them. RestSharp doesn't change behaviour based on values of those options. ::: +### Brotli decompression + +:::warning +Brotli (`DecompressionMethods.Brotli`) is excluded from the default `AutomaticDecompression` value because the Brotli decoder bundled with the .NET runtime is affected by [CVE-2026-111497](https://nvd.nist.gov/vuln/detail/CVE-2026-111497), an out-of-bounds write that a malicious server can trigger with a crafted `Content-Encoding: br` response. The decoder is part of the runtime, not of RestSharp, so RestSharp cannot fix it; it can only avoid reaching it. + +Servers that support Brotli also support gzip, so responses arrive gzip-encoded instead. If you need Brotli and your runtime includes the fix, opt in explicitly: + +```csharp +var client = new RestClient(new RestClientOptions("https://api.example.com") { + AutomaticDecompression = DecompressionMethods.All +}); +``` +::: + The `IRestClient` interface exposes the `Options` property, so any option can be inspected at runtime. However, RestSharp converts the options object provided to the client constructor to an immutable object. Therefore, no client option can be changed after the client is instantiated. It's because changing client options at runtime can produce issues in concurrent environments, effectively rendering the client as not thread-safe. Apart from that, changing the options that are used to create the message handler would require re-creating the handler, and also `HttpClient`, which should not be done at runtime. ## Configuring requests diff --git a/docs/docs/changelog.md b/docs/docs/changelog.md index 13d1dd504..d7e992d71 100644 --- a/docs/docs/changelog.md +++ b/docs/docs/changelog.md @@ -10,6 +10,12 @@ For release notes of previous versions, please check the [Releases page](https:/ Changes between major versions are documented in the documentation for each version on this website. +## v114.2 + +### Behavior changes + +* **Brotli removed from the default `AutomaticDecompression`** — `RestClientOptions.AutomaticDecompression` now defaults to `GZip | Deflate` on .NET (previously `All`). The Brotli decoder bundled with the .NET runtime is affected by [CVE-2026-111497](https://nvd.nist.gov/vuln/detail/CVE-2026-111497), reachable from a crafted `Content-Encoding: br` response, and no patched runtime is available yet. Clients built with default options no longer advertise `br` and no longer route responses through that decoder. Set `AutomaticDecompression = DecompressionMethods.All` to restore the previous behavior. The .NET Framework default (`GZip`) is unchanged. See [Brotli decompression](advanced/configuration.md#brotli-decompression). + ## v114.1 ### New features diff --git a/src/RestSharp/Options/RestClientOptions.cs b/src/RestSharp/Options/RestClientOptions.cs index 5cd8b09a2..1f33afe08 100644 --- a/src/RestSharp/Options/RestClientOptions.cs +++ b/src/RestSharp/Options/RestClientOptions.cs @@ -98,11 +98,18 @@ public RestClientOptions(string baseUrl) : this(new Uri(Ensure.NotEmptyString(ba public bool DisableCharset { get; set; } /// - /// Set the decompression method to use when making requests + /// Set the decompression methods the client advertises in Accept-Encoding and applies to responses. /// + /// + /// The default is GZip | Deflate on .NET and GZip on .NET Framework. + /// Brotli is not enabled by default: the Brotli decoder bundled with the .NET runtime is affected by + /// CVE-2026-111497, an out-of-bounds write reachable from a crafted Content-Encoding: br response, + /// and no fixed runtime has shipped at the time of this release. Set this property to + /// to opt in once your runtime is patched. + /// #if NET [UnsupportedOSPlatform("browser")] - public DecompressionMethods AutomaticDecompression { get; set; } = DecompressionMethods.All; + public DecompressionMethods AutomaticDecompression { get; set; } = DecompressionMethods.GZip | DecompressionMethods.Deflate; #else public DecompressionMethods AutomaticDecompression { get; set; } = DecompressionMethods.GZip; #endif diff --git a/test/RestSharp.Tests.Integrated/CompressionTests.cs b/test/RestSharp.Tests.Integrated/CompressionTests.cs index c20526423..0284e4bdd 100644 --- a/test/RestSharp.Tests.Integrated/CompressionTests.cs +++ b/test/RestSharp.Tests.Integrated/CompressionTests.cs @@ -68,4 +68,43 @@ public async Task Can_Handle_Uncompressed_Content() { response.Content.Should().Be(value); } + +#if NET8_0_OR_GREATER + // Brotli is excluded from the default AutomaticDecompression because the Brotli decoder + // bundled with the .NET runtime is affected by CVE-2026-111497. See docs/advanced/configuration.md. + [Fact] + public async Task Default_Client_Does_Not_Advertise_Or_Decode_Brotli() { + const string value = "This is some brotli content"; + using var server = WireMockServer.Start(); + + var body = await GetBody(s => new BrotliStream(s, CompressionMode.Compress, true), value); + ConfigureServer(server, body, "br"); + + using var client = new RestClient(server.Url!); + var request = new RestRequest(""); + var response = await client.ExecuteAsync(request); + + var acceptEncoding = server.LogEntries.Single().RequestMessage.Headers!["Accept-Encoding"].ToString(); + acceptEncoding.Should().NotContain("br"); + + // The body is returned as-is: the Brotli decoder is never invoked + response.RawBytes.Should().Equal(body); + response.Content.Should().NotBe(value); + } + + [Fact] + public async Task Can_Handle_Brotli_Compressed_Content_When_Opted_In() { + const string value = "This is some brotli content"; + using var server = WireMockServer.Start(); + + var body = await GetBody(s => new BrotliStream(s, CompressionMode.Compress, true), value); + ConfigureServer(server, body, "br"); + + using var client = new RestClient(server.Url!, options => options.AutomaticDecompression = DecompressionMethods.All); + var request = new RestRequest(""); + var response = await client.ExecuteAsync(request); + + response.Content.Should().Be(value); + } +#endif } \ No newline at end of file From 90c3011c900c46d817f47733c8f5c5ae011cc43c Mon Sep 17 00:00:00 2001 From: Mickael Vest Date: Sat, 24 Oct 2026 17:07:38 +0200 Subject: [PATCH 2/2] Docs: qualify the gzip fallback; a br response from a non-compliant server is returned undecoded --- docs/docs/advanced/configuration.md | 2 +- src/RestSharp/Options/RestClientOptions.cs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/docs/advanced/configuration.md b/docs/docs/advanced/configuration.md index 4f3f51d01..b2a87c76f 100644 --- a/docs/docs/advanced/configuration.md +++ b/docs/docs/advanced/configuration.md @@ -200,7 +200,7 @@ If setting these options to non-default values produce no desirable effect, chec :::warning Brotli (`DecompressionMethods.Brotli`) is excluded from the default `AutomaticDecompression` value because the Brotli decoder bundled with the .NET runtime is affected by [CVE-2026-111497](https://nvd.nist.gov/vuln/detail/CVE-2026-111497), an out-of-bounds write that a malicious server can trigger with a crafted `Content-Encoding: br` response. The decoder is part of the runtime, not of RestSharp, so RestSharp cannot fix it; it can only avoid reaching it. -Servers that support Brotli also support gzip, so responses arrive gzip-encoded instead. If you need Brotli and your runtime includes the fix, opt in explicitly: +In practice servers that support Brotli also support gzip and honour `Accept-Encoding`, so responses arrive gzip-encoded instead. A server that sends `Content-Encoding: br` regardless of what the client advertised is not decoded by default: `RawBytes` holds the compressed body, `Content` is not meaningful, and `RestResponse.ContentEncoding` reports `br`. If you need Brotli and your runtime includes the fix, opt in explicitly: ```csharp var client = new RestClient(new RestClientOptions("https://api.example.com") { diff --git a/src/RestSharp/Options/RestClientOptions.cs b/src/RestSharp/Options/RestClientOptions.cs index 1f33afe08..34b16ea20 100644 --- a/src/RestSharp/Options/RestClientOptions.cs +++ b/src/RestSharp/Options/RestClientOptions.cs @@ -106,6 +106,7 @@ public RestClientOptions(string baseUrl) : this(new Uri(Ensure.NotEmptyString(ba /// CVE-2026-111497, an out-of-bounds write reachable from a crafted Content-Encoding: br response, /// and no fixed runtime has shipped at the time of this release. Set this property to /// to opt in once your runtime is patched. + /// A br response from a server that ignores Accept-Encoding is returned undecoded. /// #if NET [UnsupportedOSPlatform("browser")]