# Root Cause Analysis: CVE-2026-82209

## Summary

CVE-2026-82209 is a cookie-scope information disclosure in curl/libcurl builds that use libpsl. When an HTTP origin whose hostname is itself a Public Suffix List (PSL) entry returns a `Set-Cookie` header with an explicit `Domain` equal to that hostname, vulnerable curl accepts the cookie as domain-scoped. It subsequently sends the cookie to sibling hosts under the public suffix. This run confirmed the behavior through real HTTP endpoints and the curl command-line product at the exact parent of the fix, then showed that the fixed commit retains the cookie only for the exact origin.

## Impact

- **Package/component affected:** curl/libcurl HTTP cookie engine when built with libpsl.
- **Affected versions:** curl 7.46.0 through and including 8.21.0. Versions before 7.46.0 and versions 8.22.0 or later are not affected according to the curl advisory.
- **Risk level and consequences:** Low severity, CWE-201. A cookie issued by a public-suffix apex can be disclosed in an outbound request to an arbitrary sibling beneath that suffix. The apex must issue the cookie; an attacker cannot plant it directly. The same curl client must later contact an attacker-controlled sibling, a plausible condition for shared-hosting or dynamic-DNS suffixes on the PSL.

## Impact Parity

- **Disclosed/claimed maximum impact:** Information leak.
- **Reproduced impact from this run:** The sibling endpoint `attacker.github.io` received `Cookie: sid=DOMAIN_SECRET` after `github.io` issued `Set-Cookie: sid=DOMAIN_SECRET; Domain=github.io; Path=/` to vulnerable curl.
- **Parity:** full.
- **Not demonstrated:** No greater impact, such as authentication bypass or code execution, was claimed or tested. The proof uses a marker cookie rather than a real credential.

## Root Cause

`Curl_cookie_add()` parses a response cookie and gives a cookie with an explicit `Domain` attribute the `tailmatch` property. In the vulnerable parent (`f8992b6a177a2ccfb5dc04137088534bad68681c`), `is_public_suffix()` treats the exact-origin case as acceptable according to `psl_is_cookie_domain_acceptable()`, but it cannot change the `const struct Cookie *co`. The cookie therefore remains tail-matching even when `co->domain` and the request domain are the same PSL entry. Curl's normal domain matching then sends it to siblings.

The fix, commit [`95c1e8915dce64606bd753fd47fc0bd236e31cd6`](https://github.com/curl/curl/commit/95c1e8915dce64606bd753fd47f), makes the cookie mutable in `is_public_suffix()` and clears `co->tailmatch` when all of these hold:

1. libpsl accepts the cookie-domain relationship;
2. the parsed cookie would otherwise tail-match;
3. the cookie domain exactly equals the response origin; and
4. `psl_is_public_suffix()` confirms that domain is a public suffix.

The fixed cookie is thus host-only rather than discarded: it is sent back to `github.io` but not to `attacker.github.io`. The patch also moves PSL handling earlier in `Curl_cookie_add()` and adds upstream regression test 2318.

## Reproduction Steps

1. Run `bundle/repro/reproduction_steps.sh` from any directory (optionally set `PRUVA_ROOT` to the bundle path).
2. The script reads the prepared cache context, checks out the exact fixed commit and its parent in separate worktrees, verifies that the patch hunk is absent/present as expected, and builds both curl products with libpsl enabled.
3. For each of two vulnerable and two fixed attempts, it starts an isolated localhost HTTP endpoint and runs the real curl CLI with `--resolve` mappings for the canonical PSL entry `github.io` and sibling `attacker.github.io`. The endpoint issues the domain cookie at `/set` and records the subsequent `/sibling` and `/origin-check` requests.
4. Success requires both vulnerable attempts to disclose `DOMAIN_SECRET` to the sibling, both fixed attempts to withhold it from the sibling, and all four attempts to retain it for the exact origin. The script validates and hashes every immutable proof artifact before exiting 0.

## Evidence

- **Runtime manifest:** `bundle/repro/runtime_manifest.json`
- **Vulnerable endpoint transcripts:**
  - `bundle/repro/vulnerable-server-1.log`
  - `bundle/repro/vulnerable-server-2.log`
- **Fixed negative controls:**
  - `bundle/repro/fixed-server-1.log`
  - `bundle/repro/fixed-server-2.log`
- **Full curl request/response traces:** `bundle/repro/vulnerable-attempt-{1,2}.log` and `bundle/repro/fixed-attempt-{1,2}.log`
- **Source, feature, and loader identity:** `bundle/repro/target-identity.log`
- **Build/session diagnostics:** `bundle/logs/reproduction_steps.log`, `bundle/logs/cmake-{vulnerable,fixed}.log`, and `bundle/logs/build-{vulnerable,fixed}.log`

Key vulnerable endpoint evidence:

```json
{"cookie": "sid=DOMAIN_SECRET", "event": "request", "host": "attacker.github.io:<port>", "path": "/sibling"}
```

Key fixed negative-control evidence:

```json
{"cookie": null, "event": "request", "host": "attacker.github.io:<port>", "path": "/sibling"}
{"cookie": "sid=DOMAIN_SECRET", "event": "request", "host": "github.io:<port>", "path": "/origin-check"}
```

`target-identity.log` proves that both binaries expose the `PSL` feature, link to `libpsl.so.5`, and load their intended worktree-specific `libcurl.so.4`. The tested vulnerable identity is repository `https://github.com/curl/curl` at commit `f8992b6a177a2ccfb5dc04137088534bad68681c`; its canonical source identity digest is recorded in the runtime manifest as `e677ed09f427dd41bac4cb6f8de6e53aa64d3e05fafd927d2d839caf380ed643`. No sanitizer was used.

## Recommendations / Next Steps

- Upgrade to curl 8.22.0 or newer.
- If upgrading is not possible, backport commit `95c1e8915dce64606bd753fd47fc0bd236e31cd6`.
- Retain libpsl support; disabling PSL enforcement is not an appropriate fix.
- Add regression coverage for exact PSL-domain cookies, ordinary registrable domains, sibling requests, trailing-dot host/domain forms, redirects, cookie persistence/reload, and curl's API as well as CLI paths.
- Applications that cannot update immediately should avoid accepting or persisting sensitive cookies from hosts that are themselves public suffixes.

## Additional Notes

- **Idempotency:** Confirmed. The complete reproduction script passed twice consecutively. Each script run itself executes two isolated vulnerable attempts and two isolated fixed attempts.
- **Environment:** Linux x86-64; curl source builds used libpsl 0.21.2. HTTP DNS names were mapped with curl's `--resolve`, so no public DNS or `/etc/hosts` modification was required.
- **Limitations:** The test uses `github.io`, the canonical PSL domain from upstream test 2318, and a marker cookie over localhost HTTP. The exploitability precondition that the PSL apex supplies the cookie remains essential.
