Every CVE Search/ Get API key

CVE-2026-103030

Dio: Cross-origin redirect leaks sensitive request headers in `dio_http2_adapter`

7.5 HighFix available

Dio is a powerful HTTP client for Dart and Flutter. From 1.0.0 until 2.8.0, dio_http2_adapter follows redirects in Http2Adapter._fetch by copying the original RequestOptions.headers into the redirected HTTP/2 request without comparing the source and destination origins. A server contacted by an application can return a cross-origin Location redirect to a different-origin destination, which then receives preserved Authorization, Cookie, and Proxy-Authorization headers because RequestOptions.copyWith retains the full header map. The issue applies when applications use Http2Adapter for authenticated requests, and redirect following is enabled by default. This issue is fixed in version 2.8.0.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
None
User interaction
None

What an attacker can affect

Confidentiality
High
Integrity
None
Availability
None

Exploit likelihood

0.36%Unchanged since Oct 14, 2026
90%50%10%1%

What each source reports

CVE List Score used 7.5

Dio: Cross-origin redirect leaks sensitive request headers in `dio_http2_adapter`

Dio is a powerful HTTP client for Dart and Flutter. From 1.0.0 until 2.8.0, dio_http2_adapter follows redirects in Http2Adapter._fetch by copying the original RequestOptions.headers into the redirected HTTP/2 request without comparing the source and destination origins. A server contacted by an application can return a cross-origin Location redirect to a different-origin destination, which then receives preserved Authorization, Cookie, and Proxy-Authorization headers because RequestOptions.copyWith retains the full header map. The issue applies when applications use Http2Adapter for authenticated requests, and redirect following is enabled by default. This issue is fixed in version 2.8.0.

Record
CVE-2026-103030
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Weakness
CWE-200
Updated
2026-11-02
EUVDEUVD-2026-98921 7.5

Dio is a powerful HTTP client for Dart and Flutter. From 1.0.0 until 2.8.0, dio_http2_adapter follows redirects in Http2Adapter._fetch by copying the original RequestOptions.headers into the redirected HTTP/2 request without comparing the source and destination origins. A server contacted by an application can return a cross-origin Location redirect to a different-origin destination, which then receives preserved Authorization, Cookie, and Proxy-Authorization headers because RequestOptions.copyWith retains the full header map. The issue applies when applications use Http2Adapter for authenticated requests, and redirect following is enabled by default. This issue is fixed in version 2.8.0.

Record
EUVD-2026-98921
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Updated
2026-11-02
GitHub AdvisoriesGHSA-cr65-55v9-xhvv 7.5

Dio: Cross-origin redirect leaks sensitive request headers in `dio_http2_adapter`

Summary

dio_http2_adapter follows HTTP Location redirects without stripping sensitive request headers when the redirect target is a different origin. An attacker who can cause any origin server to return a cross-origin 302 redirect receives the victim's Authorization, Cookie, and Proxy-Authorization headers verbatim. This vulnerability has a CVSS v3.1 base score of 7.5 (High) because followRedirects is enabled by default, no authentication is required to exploit it, and the confidentiality impact is high.

Details

When Dio is configured to use Http2Adapter, the adapter's internal _fetch method constructs HTTP/2 request headers by unconditionally copying all entries from options.headers:

// plugins/http2_adapter/lib/src/http2_adapter.dart:111
headers.addAll(
  options.headers.entries.map((entry) {
    ...
    return Header.ascii(entry.key.toLowerCase(), v);
  }).toList(),
);

On receiving a 3xx response, the adapter reads the Location header and resolves the redirect target URI:

// plugins/http2_adapter/lib/src/http2_adapter.dart:254-263
final url = responseHeaders.value('location');
final uri = Uri.parse(url ?? '');
final String path = resolveRedirectUri(options.uri, uri).toString();
return _fetch(options.copyWith(path: path, maxRedirects: --options.maxRedirects), ...);

options.copyWith is called without an explicit headers argument; dio/lib/src/options.dart:629 therefore preserves the full original header map via headers ?? Map.from(this.headers). resolveRedirectUri (http2_adapter.dart:290) returns an attacker-controlled cross-origin URI without any origin comparison. The combination means that on every redirect, the full set of original sensitive headers — including Authorization, Cookie, and Proxy-Authorization — is forwarded to the new authority with no sanitization.

Data flow (source → sink):

  1. dio/lib/src/dio_mixin.dart:383 — public Dio.request<T>(String path, ...) entry point.
  2. dio/lib/src/options.dart:331 — base and per-request headers merged into RequestOptions.
  3. dio/lib/src/dio_mixin.dart:596 — httpClientAdapter.fetch(reqOpt, ...) dispatches to Http2Adapter.
  4. plugins/http2_adapter/lib/src/http2_adapter.dart:254 — Location header is read from the network response (attacker-controlled source).
  5. plugins/http2_adapter/lib/src/http2_adapter.dart:258 — redirect target URI resolved; cross-origin check absent.
  6. plugins/http2_adapter/lib/src/http2_adapter.dart:260 — options.copyWith(path: path, ...) called without headers override.
  7. dio/lib/src/options.dart:629 — copyWith preserves Map.from(this.headers) — all sensitive headers retained.
  8. plugins/http2_adapter/lib/src/http2_adapter.dart:111 — preserved headers emitted verbatim to the cross-origin HTTP/2 request (sink).

Suggested patch — strip sensitive headers before following a cross-origin redirect:

--- a/plugins/http2_adapter/lib/src/http2_adapter.dart
+++ b/plugins/http2_adapter/lib/src/http2_adapter.dart
+  static const _sensitiveRedirectHeaders = {
+    'authorization',
+    'cookie',
+    'proxy-authorization',
+  };
+
-      final String path = resolveRedirectUri(options.uri, uri).toString();
+      final redirectUri = resolveRedirectUri(options.uri, uri);
+      final redirectOptions = options.copyWith(
+        path: redirectUri.toString(),
+        maxRedirects: --options.maxRedirects,
+      );
+      if (!_sameOrigin(options.uri, redirectUri)) {
+        redirectOptions.headers.removeWhere(
+          (name, _) => _sensitiveRedirectHeaders.contains(name.toLowerCase()),
+        );
+      }
       return _fetch(
-        options.copyWith(path: path, maxRedirects: --options.maxRedirects),
+        redirectOptions,
         list != null ? Stream.fromIterable(list) : null,
         cancelFuture,
         redirects,
       );
+
+  static bool _sameOrigin(Uri a, Uri b) =>
+      a.scheme ==…
Record
GHSA-cr65-55v9-xhvv
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Weakness
CWE-200
Updated
2026-11-02
NVD 7.5

Dio is a powerful HTTP client for Dart and Flutter. From 1.0.0 until 2.8.0, dio_http2_adapter follows redirects in Http2Adapter._fetch by copying the original RequestOptions.headers into the redirected HTTP/2 request without comparing the source and destination origins. A server contacted by an application can return a cross-origin Location redirect to a different-origin destination, which then receives preserved Authorization, Cookie, and Proxy-Authorization headers because RequestOptions.copyWith retains the full header map. The issue applies when applications use Http2Adapter for authenticated requests, and redirect following is enabled by default. This issue is fixed in version 2.8.0.

Record
CVE-2026-103030
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Weakness
CWE-200
Updated
2026-11-02
OSV 7.5

Dio: Cross-origin redirect leaks sensitive request headers in `dio_http2_adapter`

Dio is a powerful HTTP client for Dart and Flutter. From 1.0.0 until 2.8.0, dio_http2_adapter follows redirects in Http2Adapter._fetch by copying the original RequestOptions.headers into the redirected HTTP/2 request without comparing the source and destination origins. A server contacted by an application can return a cross-origin Location redirect to a different-origin destination, which then receives preserved Authorization, Cookie, and Proxy-Authorization headers because RequestOptions.copyWith retains the full header map. The issue applies when applications use Http2Adapter for authenticated requests, and redirect following is enabled by default. This issue is fixed in version 2.8.0.

Record
CVE-2026-103030
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Weakness
CWE-200
Updated
2026-11-02
OSVGHSA-cr65-55v9-xhvv 7.5

Dio: Cross-origin redirect leaks sensitive request headers in `dio_http2_adapter`

Summary

dio_http2_adapter follows HTTP Location redirects without stripping sensitive request headers when the redirect target is a different origin. An attacker who can cause any origin server to return a cross-origin 302 redirect receives the victim's Authorization, Cookie, and Proxy-Authorization headers verbatim. This vulnerability has a CVSS v3.1 base score of 7.5 (High) because followRedirects is enabled by default, no authentication is required to exploit it, and the confidentiality impact is high.

Details

When Dio is configured to use Http2Adapter, the adapter's internal _fetch method constructs HTTP/2 request headers by unconditionally copying all entries from options.headers:

// plugins/http2_adapter/lib/src/http2_adapter.dart:111
headers.addAll(
  options.headers.entries.map((entry) {
    ...
    return Header.ascii(entry.key.toLowerCase(), v);
  }).toList(),
);

On receiving a 3xx response, the adapter reads the Location header and resolves the redirect target URI:

// plugins/http2_adapter/lib/src/http2_adapter.dart:254-263
final url = responseHeaders.value('location');
final uri = Uri.parse(url ?? '');
final String path = resolveRedirectUri(options.uri, uri).toString();
return _fetch(options.copyWith(path: path, maxRedirects: --options.maxRedirects), ...);

options.copyWith is called without an explicit headers argument; dio/lib/src/options.dart:629 therefore preserves the full original header map via headers ?? Map.from(this.headers). resolveRedirectUri (http2_adapter.dart:290) returns an attacker-controlled cross-origin URI without any origin comparison. The combination means that on every redirect, the full set of original sensitive headers — including Authorization, Cookie, and Proxy-Authorization — is forwarded to the new authority with no sanitization.

Data flow (source → sink):

  1. dio/lib/src/dio_mixin.dart:383 — public Dio.request<T>(String path, ...) entry point.
  2. dio/lib/src/options.dart:331 — base and per-request headers merged into RequestOptions.
  3. dio/lib/src/dio_mixin.dart:596 — httpClientAdapter.fetch(reqOpt, ...) dispatches to Http2Adapter.
  4. plugins/http2_adapter/lib/src/http2_adapter.dart:254 — Location header is read from the network response (attacker-controlled source).
  5. plugins/http2_adapter/lib/src/http2_adapter.dart:258 — redirect target URI resolved; cross-origin check absent.
  6. plugins/http2_adapter/lib/src/http2_adapter.dart:260 — options.copyWith(path: path, ...) called without headers override.
  7. dio/lib/src/options.dart:629 — copyWith preserves Map.from(this.headers) — all sensitive headers retained.
  8. plugins/http2_adapter/lib/src/http2_adapter.dart:111 — preserved headers emitted verbatim to the cross-origin HTTP/2 request (sink).

Suggested patch — strip sensitive headers before following a cross-origin redirect:

--- a/plugins/http2_adapter/lib/src/http2_adapter.dart
+++ b/plugins/http2_adapter/lib/src/http2_adapter.dart
+  static const _sensitiveRedirectHeaders = {
+    'authorization',
+    'cookie',
+    'proxy-authorization',
+  };
+
-      final String path = resolveRedirectUri(options.uri, uri).toString();
+      final redirectUri = resolveRedirectUri(options.uri, uri);
+      final redirectOptions = options.copyWith(
+        path: redirectUri.toString(),
+        maxRedirects: --options.maxRedirects,
+      );
+      if (!_sameOrigin(options.uri, redirectUri)) {
+        redirectOptions.headers.removeWhere(
+          (name, _) => _sensitiveRedirectHeaders.contains(name.toLowerCase()),
+        );
+      }
       return _fetch(
-        options.copyWith(path: path, maxRedirects: --options.maxRedirects),
+        redirectOptions,
         list != null ? Stream.fromIterable(list) : null,
         cancelFuture,
         redirects,
       );
+
+  static bool _sameOrigin(Uri a, Uri b) =>
+      a.scheme ==…
Record
GHSA-cr65-55v9-xhvv
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Weakness
CWE-200
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
dio_http2_adapter
Pub
1.0.0 to 2.7.1
2.8.0
dio_http2_adapter
Pub
1.0.0 up to 2.8.0, plus listed versions
1.0.12.0.02.0.0-beta12.0.0-beta22.0.0-prev1
Show 14 moreShow less
2.1.02.2.02.3.02.3.12.3.1+12.3.22.4.02.5.02.5.12.5.22.5.32.6.02.7.02.7.1
2.8.0

History

History
RecordedChangedSources
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-103030 is a high vulnerability (CVSS 7.5) in Cfug Dio, published October 13, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.36%, the 30th percentile. Fixed in dio_http2_adapter 2.8.0.

References

This page doesn't list everything

Left out here: the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open