garrytan / garrytan/gstack

cookie-import-browser: most cookies silently dropped — imports 3 of 22 for Arc Profile N

Open
#1,057 2 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
133k
Forks
19.9k
Avg merge
18h 46m
Merged PRs (30d)
26

Description

## Summary

`cookie-import-browser arc --domain --profile "Profile 14"` imports only 3 of 22 valid, non-expired cookies for `.slack.com`. The `d` cookie (Slack's session auth) is among the dropped ones, so downstream browse sessions get redirected to login on every authenticated URL.

All 22 cookies are `v10`-encrypted (plaintext Keychain password scheme). The failure is silent — the CLI only reports `Imported 3 cookies for slack.com from arc`, no indication that 19 failed.

## Environment

- gstack: `1.0.0.0` (upgraded from `0.17.0.0` during investigation — same behavior on both)
- macOS, Apple Silicon
- Arc: current stable, 5 profiles (`Default` + `Profile 11` — `Profile 14`)
- Arc fully running / logged-in to the target site in `Profile 14`

## Reproduction

```bash
# Confirm target profile has the cookies (all v10)
DB="$HOME/Library/Application Support/Arc/User Data/Profile 14/Cookies"
sqlite3 "$DB" "SELECT SUBSTR(encrypted_value,1,3) AS ver, COUNT(*) FROM cookies WHERE host_key LIKE '%slack%' GROUP BY ver"
# Output: v10|32

# Run the import
B=~/.claude/skills/gstack/browse/dist/browse
$B goto https://.slack.com
$B cookie-import-browser arc --domain slack.com --profile "Profile 14"
# Output: "Imported 3 cookies for slack.com from arc"
```

## Expected

All 22 unexpired `.slack.com` cookies are imported (or the CLI reports the `failed` count it already tracks internally — see `importCookies` line 283 in `cookie-import-browser.ts`).

## Actual

Only 3 cookies imported: `b`, `x`, `OptanonConsent`. The useful HttpOnly session cookies (`d`, `d-s`, and 17 others) are silently dropped.

Verified via `$B cookies | jq '.[] | select(.domain | test("slack"))'` after import.

## Pattern in the data

From `sqlite3 "$DB" "SELECT name, SUBSTR(encrypted_value,1,3) ver, LENGTH(encrypted_value) len, is_httponly, is_secure FROM cookies WHERE host_key = '.slack.com'"`:

| name | ver | len | httponly | secure | imported |
|---|---|---|---|---|---|
| b | v10 | 83 | 0 | 1 | ✅ |
| x | v10 | 83 | 0 | 1 | ✅ |
| OptanonConsent | v10 | 387 | 0 | 0 | ✅ |
| d | v10 | 275 | **1** | 1 | ❌ |
| d-s | v10 | 51 | **1** | 1 | ❌ |
| _cs_id | v10 | 131 | 0 | 1 | ❌ |
| _ga | v10 | 67 | 0 | 0 | ❌ |
| _ga_QTJQME5M5D | v10 | 83 | 0 | 0 | ❌ |
| ... 14 more dropped ... | | | | | |

The 3 imported vs 19 dropped split does not cleanly correlate with `is_httponly`, `is_secure`, or `length`. `b` and `_ga_QTJQME5M5D` are both length 83, `is_httponly=0`, `is_secure`=1/0 respectively — one imports, the other doesn't.

Hypothesis: Arc's Keychain password / key-derivation may have rotated, and the 3 successful decrypts are cookies written since the last rotation. The older cookies can't be decrypted with the current Keychain entry. gstack's `decryptCookieValue` throws and is caught silently at `cookie-import-browser.ts:282-284`:

```ts
try {
const value = decryptCookieValue(row, derivedKeys, match.platform);
const cookie = toPlaywrightCookie(row, value);
cookies.push(cookie);
domainCounts[row.host_key] = (domainCounts[row.host_key] || 0) + 1;
} catch {
failed++;
}
```

`failed` is tracked but never surfaced — the CLI and UI report only the success count.

## Suggested fixes (any one helps)

1. **Surface `failed` count in the CLI output** — at minimum log `Imported 3 cookies (19 failed to decrypt) for slack.com from arc` so the user knows something's off.
2. **Log the decrypt exception** (behind `DEBUG=1`) — helps diagnose per-cookie failures.
3. **Try multiple Keychain entries / fallback derivation schemes** if the primary password fails for some rows — matches what `decrypt-chrome-cookies` does.
4. **UI picker**: currently returns `Failed to fetch` when trying to import `.slack.com` — likely the same underlying decrypt error but wrapped as a server error. Should show partial success.

## Impact

Any gstack workflow that requires importing an authenticated session from Arc into headless browse (`/qa` on authenticated pages, Slack/Notion/internal-app QA, `setup-browser-cookies` skill) silently fails — the cookies are "imported" but the critical auth cookie is missing, so the next navigation 302s to login. User sees no error; only discovers the problem when auth doesn't work.

/cc anyone maintaining `src/cookie-import-browser.ts`

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.