Skip to content

feat: add Linux cookie import support (GNOME Keyring)#39

Open
amine-amaach wants to merge 4 commits intogarrytan:mainfrom
amine-amaach:feat/linux-cookie-import
Open

feat: add Linux cookie import support (GNOME Keyring)#39
amine-amaach wants to merge 4 commits intogarrytan:mainfrom
amine-amaach:feat/linux-cookie-import

Conversation

@amine-amaach
Copy link

@amine-amaach amine-amaach commented Mar 14, 2026

Summary

  • Add Linux support for Chromium cookie import (Chrome, Chromium, Brave, Edge)
  • Linux v10 cookies decrypted with hardcoded "peanuts" key (Chromium default)
  • Linux v11 cookies decrypted via GNOME Keyring (python3 + gi.repository.Secret, pre-installed on GNOME desktops)
  • Fix --profile flag in cookie-import-browser command (was silently ignored, always read from Default profile)
  • All macOS behavior preserved exactly as-is

Addresses the "Linux/Windows cookie decryption" item in TODO.md.

What changed

  • Browser registry (Linux): Chrome, Chromium, Brave, Edge
  • Config base dir (Linux): ~/.config/
  • Secret retrieval (Linux): python3 gi.repository.Secret (GNOME Keyring)
  • PBKDF2 iterations (Linux): 1 (macOS: 1003)
  • Cookie prefixes (Linux): v10 (hardcoded "peanuts") + v11 (keyring). macOS: v10 only
  • URL opener (Linux): xdg-open. macOS: open
  • Default browser (Linux): chrome. macOS: comet

Platform auto-detected via os.platform() at module load. Graceful fallback when keyring is unavailable (v10 cookies still work, v11 fail individually).

--profile flag fix

cookie-import-browser chrome --domain localhost --profile "Profile 1" now correctly reads from the specified Chrome profile directory instead of always defaulting to Default. Output includes (profile: Profile 1) when a non-default profile is used.

Test plan

  • bun test — 22 tests pass (was 18, added v11 round-trip + platform helper tests)
  • bun run build — binary compiles cleanly
  • Linux end-to-end: Chrome detected, tested with localhost cookies imported and decrypted successfully
  • Cookie picker UI loads and works on Linux (xdg-open)
  • --profile flag: verified importing from Chrome Profile 1 vs Default returns different cookies and authenticates as the correct user
  • macOS: verify cookie import from Chrome still works (v10 prefix, Keychain, 1003 iterations)

Cross-platform cookie import for macOS and Linux Chromium browsers.

Platform detection via os.platform() selects the right browser
registry, config directory, PBKDF2 iteration count, and secret
retrieval method at module load.

macOS (unchanged behavior):
  - Browsers: Comet, Chrome, Arc, Brave, Edge
  - Config: ~/Library/Application Support/
  - Secret: macOS Keychain via `security` CLI
  - PBKDF2: 1003 iterations
  - Prefix: v10 only

Linux (new):
  - Browsers: Chrome, Chromium, Brave, Edge
  - Config: ~/.config/
  - Secret: GNOME Keyring via python3 gi.repository.Secret
  - PBKDF2: 1 iteration
  - Prefixes: v10 (hardcoded "peanuts") + v11 (keyring)
  - Graceful fallback if keyring unavailable

Also updates write-commands.ts to use platform-aware helpers for
default browser selection and URL opening (open vs xdg-open).
- Platform-aware test key: uses 1003 iterations on macOS, 1 on Linux
- Fixture cookies use v11 prefix on Linux, v10 on macOS
- Mock intercepts both macOS `security` and Linux `python3` spawns
- Renamed keychainService → secretId in Browser Registry test
- Unknown Browser test checks for 'Chrome' (present on both platforms)
- New: v11 encryption/decryption round-trip test
- New: getOpenCommand() and getDefaultBrowser() platform helper tests
- New: platform consistency test (xdg-open/chrome on Linux, open/comet on macOS)

22 tests (was 18), all passing on Linux.
- setup-browser-cookies/SKILL.md: add Linux browsers, keyring notes
- TODO.md: mark Linux cookie decryption done, add Windows as separate item
- CHANGELOG.md: add 0.3.2 entry for Linux support and CORS fix
@amine-amaach amine-amaach force-pushed the feat/linux-cookie-import branch from 38b01ee to 212d5b9 Compare March 14, 2026 15:15
…mmand

The --profile argument was accepted but never parsed, so
cookie-import-browser always read from Chrome's Default profile.
Copy link

@argusdev-bot argusdev-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Argus Code Review

Score: 85/100

Reviewed 3 files. Found 2 issues. 1 high. Score: 85/100.


Additional Findings

These findings are on lines outside the diff and cannot be shown inline.

  • [MEDIUM] Profile name validation insufficient for path traversal prevention

Profile name validation blocks slashes and dots but doesn't prevent absolute paths or symlink attacks, potentially allowing access to arbitrary cookie databases.

Justification: validateProfile function only checks for slashes, dots, and control characters, but doesn't prevent absolute paths or other traversal methods. The profile name is used directly in path.join() on line 246, which could allow path manipulation.

Validation: Line 234-241: validateProfile uses regex /[/\]|../ to block slashes and dots, but doesn't prevent absolute paths like '/etc/passwd'. Line 246: path.join(baseDir, browser.dataDir, profile, 'Cookies') directly uses the profile parameter without verifying it's a simple directory name.

Suggestion: Use path.resolve() to normalize the path and ensure it's within the expected browser data directory, then compare against the expected base path. (browse/src/cookie-import-browser.ts:234)

@@ -269,20 +269,25 @@ export async function handleWriteCommand(

case 'cookie-import-browser': {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[HIGH] Cookie import from browser lacks domain validation, enabling cross-domain cookie injection

The cookie-import-browser command imports cookies without validating that imported cookie domains match the target domain, allowing injection of cookies for arbitrary domains.

Justification: Lines 285-287 import cookies based on a user-provided domain argument and add them directly to the page context without checking if the cookie domains are appropriate for the current page.

Validation: Line 285: const result = await importCookies(browser, [domain], profile); imports cookies for the specified domain. Line 287: await page.context().addCookies(result.cookies); adds all returned cookies without domain validation.

Suggestion: Add domain validation before adding cookies: only allow cookies whose domain matches the current page's domain or is a subdomain of it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants