GHSA-fmxf-pm6p-7xgm CVE-2026-45300
async-http-client: Cookie header not stripped on cross-origin redirect
- Severity
- 7.4 / 10
- High · CVSS 3.1
- Exploit chance (EPSS)
- 0.40%
- Chance of exploitation in the next 30 days. Higher than 34.15% of scored vulnerabilities.
- Known exploited
- No
- Not in CISA's catalog
- Weakness
- CWE-200 Exposure of Sensitive Information to an Unauthorized Actor
- Fix
3.0.10- Upgrade org.asynchttpclient:async-http-client to this version or later
Description
Summary
async-http-client leaks Cookie headers to cross-origin redirect targets. When following a redirect across a security boundary (different origin, or HTTPS→HTTP downgrade), the propagatedHeaders() method in Redirect30xInterceptor.java strips Authorization and Proxy-Authorization headers but does not strip Cookie, so session cookies and other sensitive cookie values are forwarded to the redirect target — which may be attacker-controlled.
Details
The vulnerability is in client/src/main/java/org/asynchttpclient/netty/handler/intercept/Redirect30xInterceptor.java.
The caller computes stripAuth on each redirect:
boolean sameBase = request.getUri().isSameBase(newUri);
boolean stripAuth = !sameBase || schemeDowngrade || stripAuthorizationOnRedirect;
// ...
requestBuilder.setHeaders(propagatedHeaders(request, realm, keepBody, stripAuth));
stripAuth is true whenever the redirect crosses an origin, downgrades the scheme, or the caller opted in via AsyncHttpClientConfig#isStripAuthorizationOnRedirect().
In the vulnerable version, propagatedHeaders() only removes Authorization and Proxy-Authorization in that branch — Cookie is left untouched:
private static HttpHeaders propagatedHeaders(Request request, Realm realm, boolean keepBody, boolean stripAuthorization) {
HttpHeaders headers = request.getHeaders()
.remove(HOST)
.remove(CONTENT_LENGTH);
if (!keepBody) {
headers.remove(CONTENT_TYPE);
}
if (stripAuthorization || (realm != null && (realm.getScheme() == AuthScheme.NTLM
|| realm.getScheme() == AuthScheme.SCRAM_SHA_256))) {
headers.remove(AUTHORIZATION)
.remove(PROXY_AUTHORIZATION);
// BUG: COOKIE is not removed here, so cookies leak across the security boundary.
}
return headers;
}
The companion test class RedirectCredentialSecurityTest covers Authorization / Proxy-Authorization stripping on cross-origin redirects and scheme downgrades, but has no coverage for Cookie, which is why the regression went unnoticed.
Proof of concept
import org.asynchttpclient.*;
AsyncHttpClient client = asyncHttpClient();
// trusted-api.com responds 302 -> https://evil.com
Request request = new RequestBuilder("GET")
.setUrl("https://trusted-api.com/endpoint")
.setHeader("Cookie", "session=abc123; csrf=xyz789; api_key=secret")
.setHeader("Authorization", "Bearer token123")
.build();
client.executeRequest(request).get();
// Request seen by evil.com after the redirect:
// Authorization: <stripped>
// Cookie: session=abc123; csrf=xyz789; api_key=secret <-- leaked
Impact
- Session hijacking — leaked session cookies allow impersonation.
- CSRF token theft — CSRF tokens carried in cookies are disclosed.
- API key theft — API keys stored in cookies are disclosed.
- Privacy — tracking identifiers leak to third-party origins.
Realistic attack paths:
- Open-redirect in a trusted API endpoint.
- Compromised CDN or API gateway injecting redirects.
- MITM on a plaintext hop in the redirect chain.
Fix
Add COOKIE to the headers removed alongside AUTHORIZATION / PROXY_AUTHORIZATION on the security-boundary branch:
if (stripAuthorization) {
headers.remove(AUTHORIZATION)
.remove(PROXY_AUTHORIZATION)
.remove(COOKIE);
} else if (realm != null && (realm.getScheme() == AuthScheme.NTLM
|| realm.getScheme() == AuthScheme.SCRAM_SHA_256)) {
headers.remove(AUTHORIZATION)
.remove(PROXY_AUTHORIZATION);
}
Note that the URI-scoped CookieStore will re-add any cookies that legitimately match the new target after propagatedHeaders returns, so legitimate cross-origin sessions tracked by the client are not broken.
Fixed in 3.0.10 and 2.15.0 by commit 3b0e3e9e.
Affected versions
Maven
| Package | Vulnerable | Fixed in |
|---|---|---|
| org.asynchttpclient:async-http-client | >= 3.0.0.Beta1, < 3.0.10 |
3.0.10 |
| org.asynchttpclient:async-http-client | >= 2.0.0, < 2.15.0 |
2.15.0 |
How to fix
Move to the fixed version or later with your package manager, update the lockfile, and run your tests. If the package only arrives through another dependency, upgrade that dependency first. If none of its releases pulls a fixed version yet, force the version with your package manager's override.
org.asynchttpclient:async-http-client Maven → 3.0.10
- maven
<dependency><groupId>org.asynchttpclient</groupId><artifactId>async-http-client</artifactId><version>3.0.10</version></dependency>- gradle
implementation("org.asynchttpclient:async-http-client:3.0.10")
Severity breakdown
CVSS 3.1 7.4
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N
- Attack vector
- Network
- Attack complexity
- Low
- Privileges required
- None
- User interaction
- Required
- Scope
- Changed
- Confidentiality
- High
- Integrity
- None
- Availability
- None
Weakness
CWE-200: Exposure of Sensitive Information to an Unauthorized Actor
The product exposes sensitive information to an actor that is not explicitly authorized to have access to that information.
How to prevent it
- Architecture and Design: Compartmentalize the system to have "safe" areas where trust boundaries can be unambiguously drawn. Do not allow sensitive data to go outside of the trust boundary and always be careful when interfacing with a compartment outside of the safe area. Ensure that appropriate compartmentalization is built into the system design, and the compartmentalization allows for and reinforces privilege separation functionality. Architects and designers should rely on the principle of least privilege to decide the appropriate time to use privileges and the time to drop privileges.
References
Advisories
Packages
Other links
Timeline
- Published
- Last updated by the source
- Latest EPSS score
Related advisories
| Advisory | Severity | Why it's related |
|---|---|---|
| GHSA-p2jm-6hj6-9rjg AsyncHttpClient: Cookies received over plaintext HTTP can plant, overwrite or delete Secure cookies set over HTTPS | Medium | Also affects org.asynchttpclient:async-http-client |
| GHSA-3wp9-xfwm-rjjf AsyncHttpClient: WebSocket proxy credentials sent to the origin server over a CONNECT tunnel | Medium | Also affects org.asynchttpclient:async-http-client |
| GHSA-mfj3-87qq-382v AsyncHttpClient: Digest authentication cnonce generated with a non-cryptographic random source | Low | Also affects org.asynchttpclient:async-http-client |
| GHSA-jmqq-x5g9-9p2w AsyncHttpClient: Replay to a different host sends the original host request and credentials to the new host | Critical | Also affects org.asynchttpclient:async-http-client |
| GHSA-f9m8-cv68-674w AsyncHttpClient: Cookie Domain attribute is not checked against the public suffix list, so a cookie can be set for co.uk | Medium | Also affects org.asynchttpclient:async-http-client |
| GHSA-rqf5-2wxv-rjf4 AsyncHttpClient: Digest challenge without a usable nonce downgrades to Basic and sends the password in cleartext | High | Also affects org.asynchttpclient:async-http-client |
| GHSA-v2j5-22fr-j62r AsyncHttpClient: Pooled connections can still be shared across NTLM, Negotiate and proxy logins | High | Also affects org.asynchttpclient:async-http-client |
| GHSA-2jwh-9rmr-j4xf AsyncHttpClient CookieStore Silently Overrides Caller's Explicit Cookie Header via setHeader (Bypass of CVE-2024-53990 Fix) | Medium | Also affects org.asynchttpclient:async-http-client |
MergeHarbor checks every repository's dependencies against this database, ranks what matters by exploitability and reachability, routes it to the owning team and opens the fix pull request.
Check your repos with MergeHarbor