Skip to content

CDP import and Set-Cookie normalize the domain differently, the same cookie sits twice in the jar #648

Description

@aech

The Problem

The cookie jar has two entrances, and they handle the domain differently.

Network.setCookies stores the domain unchanged, including the leading dot. The Set-Cookie path strips the dot before constructing the key. If the same cookie is sent via both paths, it ends up under two different keys. Both match during lookup, and the request carries the name twice with different values.

This affects every imported session. Playwright's storageState writes domain cookies with the dot. Any cookie that the page later renews via Set-Cookie with the Domain= attribute thus becomes a duplicate entry instead of replacing the old one.

Environment

  • obscura main, commit 94374e638cda7084ecab9cfb08b100efee8f9a04
  • Build: render, without stealth (cargo build --release -p obscura-cli --bins --features render)
  • Linux x86_64 (WSL2)

Reproduction

A cookie is sent via CDP with a dot, after which the server sets the same name via Set-Cookie with the Domain= attribute.

  1. Network.setCookies with [{name: "sid", value: "one", domain: ".example.com", path: "/"}]
  2. Load a page at https://app.example.com/, whose response contains Set-Cookie: sid=two; Domain=example.com; Path=/
  3. The Cookie header of the next request to app.example.com

Expected: sid=two, once.
Observed: sid=one; sid=two, the name appears twice.

Demonstrated directly in the jar, without a server, as a test case:

let jar = CookieJar::new();
let url = Url::parse("https://app.example.com/").unwrap();

jar.set_cookies_from_cdp(vec![CookieInfo {
    name: "sid".into(), value: "one".into(),
    domain: ".example.com".into(), path: "/".into(),
    secure: false, http_only: false, same_site: String::new(), expires: None,
}]);
jar.set_cookie("sid=two; Domain=example.com; Path=/", &url);

// Expects 1, but actually returns 2
assert_eq!(jar.get_all_cookies().iter().filter(|c| c.name == "sid").count(), 1);

Chromium for Comparison

Chromium 151.0.7922.34, headless, same sequence using the same CDP methods. The response with the Set-Cookie header was generated offline so that it would be processed by Chromium's own parser.

https://app.example.com/ -> 1 entry   domain=.example.com value=two
https://example.com/     -> 1 entry   domain=.example.com value=two

Chromium keeps one cookie. The Set-Cookie with the Domain= attribute also creates a domain cookie and replaces the imported one.

What is explicitly NOT the error case

Two consecutive Network.setCookies calls, one for .example.com and one for example.com, are not evidence of the issue. Chromium keeps two cookies there, and that is correct: in CDP, the leading dot encodes the domain cookie, while the dotless form encodes a host-only cookie. According to RFC 6265 5.3, these are different cookies.

Measured:

https://app.example.com/ -> 1   domain=.example.com value=one
https://example.com/     -> 2   domain=example.com  value=two
                                domain=.example.com value=one

The issue, therefore, is not that obscura retains the dot, but rather that the two entrances are inconsistent.

Side Note

The three deletion paths already work around this inconsistency: set_cookies_from_cdp, delete_cookie, and delete_cookies_filtered each try three different spellings of the domain to find a match. If you canonicalize during insertion, this becomes unnecessary.

Separately: set_cookies_from_cdp sets host_only: false for every import. obscura therefore does not map the host-only flag from CDP at all. This is a separate gap and not part of this report.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions