From d8b2f78fc23916857deb0a2f3a80315c4013a055 Mon Sep 17 00:00:00 2001 From: jmestwa-coder Date: Sun, 14 Jun 2026 21:54:16 +0530 Subject: [PATCH] reject set-cookie domain that doesn't match the request host --- .../cookie/ThreadSafeCookieStore.java | 13 +++++++++++++ .../java/org/asynchttpclient/CookieStoreTest.java | 9 +++++++++ 2 files changed, 22 insertions(+) diff --git a/client/src/main/java/org/asynchttpclient/cookie/ThreadSafeCookieStore.java b/client/src/main/java/org/asynchttpclient/cookie/ThreadSafeCookieStore.java index 5832185cc5..ca58939ac1 100644 --- a/client/src/main/java/org/asynchttpclient/cookie/ThreadSafeCookieStore.java +++ b/client/src/main/java/org/asynchttpclient/cookie/ThreadSafeCookieStore.java @@ -165,6 +165,11 @@ private static boolean hasCookieExpired(Cookie cookie, long whenCreated) { } } + // rfc6265#section-5.1.3 + private static boolean domainsMatch(String cookieDomain, String requestDomain) { + return requestDomain.equals(cookieDomain) || requestDomain.endsWith('.' + cookieDomain); + } + // rfc6265#section-5.1.4 private static boolean pathsMatch(String cookiePath, String requestPath) { return Objects.equals(cookiePath, requestPath) || @@ -175,6 +180,14 @@ private void add(String requestDomain, String requestPath, Cookie cookie) { AbstractMap.SimpleEntry pair = cookieDomain(cookie.domain(), requestDomain); String keyDomain = pair.getKey(); boolean hostOnly = pair.getValue(); + + // rfc6265#section-5.3 step 6: ignore a cookie whose Domain attribute is not + // domain-matched by the request host, otherwise a host can plant cookies for + // unrelated domains (cookie tossing). + if (!hostOnly && !domainsMatch(keyDomain, requestDomain)) { + return; + } + String keyPath = cookiePath(cookie.path(), requestPath); CookieKey key = new CookieKey(cookie.name().toLowerCase(), keyPath); diff --git a/client/src/test/java/org/asynchttpclient/CookieStoreTest.java b/client/src/test/java/org/asynchttpclient/CookieStoreTest.java index fd65322c14..1864ad01a4 100644 --- a/client/src/test/java/org/asynchttpclient/CookieStoreTest.java +++ b/client/src/test/java/org/asynchttpclient/CookieStoreTest.java @@ -56,6 +56,7 @@ public void tearDownGlobal() { public void runAllSequentiallyBecauseNotThreadSafe() throws Exception { addCookieWithEmptyPath(); dontReturnCookieForAnotherDomain(); + dontStoreCookieForUnrelatedDomainAttribute(); returnCookieWhenItWasSetOnSamePath(); returnCookieWhenItWasSetOnParentPath(); dontReturnCookieWhenDomainMatchesButPathIsDifferent(); @@ -100,6 +101,14 @@ private static void dontReturnCookieForAnotherDomain() { assertTrue(store.get(Uri.create("http://www.bar.com")).isEmpty()); } + // rfc6265#section-5.3 step 6: a host must not be able to set a cookie for an unrelated domain + private static void dontStoreCookieForUnrelatedDomainAttribute() { + CookieStore store = new ThreadSafeCookieStore(); + store.add(Uri.create("http://www.evil.com/"), ClientCookieDecoder.LAX.decode("SID=attacker; Domain=victim.com")); + assertTrue(store.get(Uri.create("https://victim.com/account")).isEmpty()); + assertTrue(store.getAll().isEmpty()); + } + private static void returnCookieWhenItWasSetOnSamePath() { CookieStore store = new ThreadSafeCookieStore(); store.add(Uri.create("http://www.foo.com"), ClientCookieDecoder.LAX.decode("ALPHA=VALUE1; path=/bar/"));