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

dio_http2_adapter follows cross-origin 302 redirects without stripping Authorization/Cookie/Proxy-Authorization headers, leaking bearer tokens and session cookies to attacker-controlled servers.

- Payout: Research
- Severity: high
- Program: Dio
- Found by: EQSTLab, useworld
- Disclosed: 2026-10-15
- CVE: CVE-2026-103030
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-cr65-55v9-xhvv
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-cr65-55v9-xhvv
- Tags: area:oss domain:oss impact:data-leak kind:research platform:ghsa sev:high tech:rest technique:chained technique:source-review vuln:info-disclosure vuln:secrets-leak

**Target:** Dart HTTP/2 client adapter (dio_http2_adapter)
**Root cause:** On a 3xx response the adapter resolves the Location URI with no origin comparison and calls options.copyWith without a headers override, so copyWith preserves the full original header map; _fetch then emits all headers verbatim to the new authority.
**Steps:**
1. Configure Dio with Http2Adapter(ConnectionManager()) and followRedirects default true.
2. Send a request with sensitive headers: `Options(headers: {'Authorization': 'Bearer SECRET_TOKEN_12345', 'Cookie': 'sid=SECRET_SESSION_ABC', 'x-secret': 'internal-secret-value'})`.
3. Origin server returns `302 Location: http://127.0.0.1:18082/capture` (cross-origin).
4. Adapter resolves redirect via resolveRedirectUri with no same-origin check and calls `options.copyWith(path: path, maxRedirects: --options.maxRedirects)` without headers.
5. copyWith at options.dart:629 retains `Map.from(this.headers)`; _fetch at http2_adapter.dart:111 re-emits all headers to the attacker server.
6. Attacker h2c server logs `authorization: Bearer SECRET_TOKEN_12345` and `cookie: sid=SECRET_SESSION_ABC`.
**How found:** Code review of the redirect path: noticed resolveRedirectUri returns an attacker-controlled URI with no origin comparison, and that options.copyWith is invoked without a headers argument, so the header map is preserved across the redirect.
**Exploitation:** Attacker controls or compromises any HTTP server the victim app contacts and returns a 302 to an attacker-owned origin; the adapter follows it with the original Authorization, Cookie and Proxy-Authorization headers intact, letting the attacker capture bearer tokens, session cookies or proxy credentials and impersonate the victim.
**Insight:** When auditing HTTP client redirect handling, check whether the redirect-following code passes the original options/headers object through copyWith without an explicit headers override — the default-preserve semantics of copyWith silently forward credentials cross-origin even if a same-origin check exists elsewhere.

