From 45a145a1e52012dcb7e0e32520db1659d01a2438 Mon Sep 17 00:00:00 2001 From: basavaraj-sm05 Date: Sun, 16 Aug 2026 19:04:21 +0530 Subject: [PATCH 1/2] downgrade a public-suffix Domain cookie to host-only --- okhttp/src/commonJvmAndroid/kotlin/okhttp3/Cookie.kt | 12 +++++++----- okhttp/src/jvmTest/kotlin/okhttp3/CookieTest.kt | 11 +++++++++++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Cookie.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Cookie.kt index 0b36b3f908c0..0cca11933a4c 100644 --- a/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Cookie.kt +++ b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Cookie.kt @@ -560,11 +560,13 @@ class Cookie private constructor( return null // No domain match? This is either incompetence or malice! } - // If the domain is a suffix of the url host, it must not be a public suffix. - if (urlHost.length != domain.length && - PublicSuffixDatabase.get().getEffectiveTldPlusOne(domain) == null - ) { - return null + // A public suffix can't be used as a cookie domain. If it's the request host itself the + // cookie is downgraded to host-only; if it's a proper suffix of the host it's refused. + if (PublicSuffixDatabase.get().getEffectiveTldPlusOne(domain) == null) { + if (urlHost.length != domain.length) { + return null + } + hostOnly = true } // If the path is absent or didn't start with '/', use the default path. It's a string like diff --git a/okhttp/src/jvmTest/kotlin/okhttp3/CookieTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/CookieTest.kt index 7f00f30e4c75..11454b8fed58 100644 --- a/okhttp/src/jvmTest/kotlin/okhttp3/CookieTest.kt +++ b/okhttp/src/jvmTest/kotlin/okhttp3/CookieTest.kt @@ -323,6 +323,17 @@ class CookieTest { assertThat(parse(punycode, "a=b; domain=xn--8ltr62k.jp")).isNull() } + @Test fun domainEqualToRequestHostThatIsPublicSuffixIsHostOnly() { + val url = "https://github.io/".toHttpUrl() + val cookie = parse(url, "a=b; domain=github.io") + assertThat(cookie).isNotNull() + assertThat(cookie!!.hostOnly).isTrue() + assertThat(cookie.domain).isEqualTo("github.io") + // The cookie stays with the request host and doesn't leak to other hosts under the suffix. + assertThat(cookie.matches("https://victim.github.io/".toHttpUrl())).isFalse() + assertThat(cookie.matches(url)).isTrue() + } + @Test fun hostOnly() { assertThat(parse(url, "a=b")!!.hostOnly).isTrue() assertThat( From 229ed7b18cd536205362b01933c198ffa5a4399f Mon Sep 17 00:00:00 2001 From: basavaraj-sm05 Date: Wed, 19 Aug 2026 11:42:45 +0530 Subject: [PATCH 2/2] only consult the public suffix list when a Domain attribute is present --- .../commonJvmAndroid/kotlin/okhttp3/Cookie.kt | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Cookie.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Cookie.kt index 0cca11933a4c..f914b2d52914 100644 --- a/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Cookie.kt +++ b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Cookie.kt @@ -556,17 +556,19 @@ class Cookie private constructor( val urlHost = url.host if (domain == null) { domain = urlHost - } else if (!domainMatch(urlHost, domain)) { - return null // No domain match? This is either incompetence or malice! - } + } else { + if (!domainMatch(urlHost, domain)) { + return null // No domain match? This is either incompetence or malice! + } - // A public suffix can't be used as a cookie domain. If it's the request host itself the - // cookie is downgraded to host-only; if it's a proper suffix of the host it's refused. - if (PublicSuffixDatabase.get().getEffectiveTldPlusOne(domain) == null) { - if (urlHost.length != domain.length) { - return null + // A public suffix can't be used as a cookie domain. If it's the request host itself the + // cookie is downgraded to host-only; if it's a proper suffix of the host it's refused. + if (PublicSuffixDatabase.get().getEffectiveTldPlusOne(domain) == null) { + if (urlHost.length != domain.length) { + return null + } + hostOnly = true } - hostOnly = true } // If the path is absent or didn't start with '/', use the default path. It's a string like