Preserve cookie security attributes in updateCookies round-trip
All checks were successful
CI / build (push) Successful in 1m18s
CI / vet (push) Successful in 1m17s
CI / test (push) Successful in 1m19s

Chromium's Cookies() API can lose or normalize Secure, SameSite, and
HttpOnly attributes during the AddCookies → navigate → Cookies()
round-trip. This caused cookies like cf_clearance (set with
Secure=true, SameSite=None) to be overwritten with Chromium's defaults
(Secure=false, SameSite=Lax).

Now updateCookies() looks up existing cookies in the jar first. For
cookies that already exist, only Value and Expires are updated —
security attributes are preserved from the original. New cookies from
the server are still written with all their attributes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-17 02:37:47 +00:00
parent adefaaef36
commit 3b6d864330

View File

@@ -219,11 +219,35 @@ func (b playWrightBrowser) updateCookies(_ context.Context, page playwright.Page
return fmt.Errorf("error getting cookies from browser: %w", err)
}
// Build a lookup of existing cookies so we can preserve their security
// attributes. Chromium's Cookies() API can lose or normalize Secure,
// SameSite, and HttpOnly during the AddCookies → navigate → Cookies()
// round-trip, so we only update Value and Expires for cookies that
// already exist in the jar.
existing, err := b.cookieJar.Get(page.URL())
if err != nil {
return fmt.Errorf("error getting existing cookies from jar: %w", err)
}
type cookieKey struct{ Name, Path string }
existingMap := make(map[cookieKey]Cookie, len(existing))
for _, c := range existing {
existingMap[cookieKey{c.Name, c.Path}] = c
}
for _, cookie := range cookies {
// TODO: add support for deleting cookies from the jar which are deleted in the browser
err = b.cookieJar.Set(playwrightCookieToCookie(cookie))
c := playwrightCookieToCookie(cookie)
if err != nil {
if prev, ok := existingMap[cookieKey{c.Name, c.Path}]; ok {
// Preserve the original security attributes; only update
// Value and Expires which are the fields that legitimately
// change during navigation.
c.Secure = prev.Secure
c.HttpOnly = prev.HttpOnly
c.SameSite = prev.SameSite
}
if err = b.cookieJar.Set(c); err != nil {
return fmt.Errorf("error setting cookie in cookie jar: %w", err)
}
}