[BUG] Chrome cookie import fails: Safe Storage key queried in data-protection keychain, but Chrome stores it in the legacy login keychain (macOS)
Summary
The built-in browser's "Import cookies from your browser" feature fails for Google Chrome on macOS with:
Couldn't read Google Chrome's data. Quit Google Chrome and try again.
The error message is misleading. Chrome running is not the cause, and quitting Chrome does not help. The actual failure is a keychain routing mismatch: the app looks up Chrome's Chrome Safe Storage AES key in the data-protection keychain (secd), but Chrome stores that item in the legacy file-based login keychain (securityd, login.keychain-db). The lookup returns errSecItemNotFound (-25300), the app cannot derive the AES key, and every v10 cookie fails to decrypt.
A Touch ID prompt appears and succeeds during the attempt, which makes this look like a permissions problem. It is not — the app authenticates against a SecAccessControl it constructed for the data-protection keychain, and then finds nothing there.
Environment
| | |
|---|---|
| Claude desktop (Cowork) | 2.110.1 (com.anthropic.claudefordesktop) |
| macOS | 27.0 (build 26A428) |
| Hardware | Apple silicon (arm64) |
| Google Chrome | 153.0.8010.48 |
| Chrome profile | Default (only profile present) |
| Cookie DB | ~/Library/Application Support/Google/Chrome/Default/Cookies, 360448 bytes |
| Cookie encryption | v10 × 675 (no v20 / no app-bound encryption) |
Steps to reproduce
- Use Chrome on macOS as the primary browser so
Chrome Safe Storageis created in the login keychain. - Open the Claude desktop app → built-in browser → Import cookies from your browser.
- Source: Google Chrome, profile: Default. Start the import.
- Authenticate at the Touch ID prompt (reason string: "list the sites you're signed into in Google Chrome, to bring them into Cowork's browser"). Authentication succeeds.
- Import fails with "Couldn't read Google Chrome's data. Quit Google Chrome and try again."
Reproduces identically whether Chrome is running or fully quit.
Expected vs actual
Expected: cookies are read from the Default profile, decrypted using the Chrome Safe Storage key from the login keychain, and imported.
Actual: import fails. The keychain lookup misses, no decryption is attempted, and the user is shown an error that blames Chrome running — an unrelated and non-reproducing condition.
Evidence
1. The item is in the legacy keychain only
$ security find-generic-password -s "Chrome Safe Storage"
keychain: "/Users/<user>/Library/Keychains/login.keychain-db"
class: "genp"
"acct"<blob>="Chrome"
"svce"<blob>="Chrome Safe Storage"
Same query issued both ways via SecItemCopyMatching (attributes only, no secret read):
LEGACY (kSecUseDataProtectionKeychain=FALSE) -> 0 (errSecSuccess)
DATA-PROTECTION (=TRUE) -> -25300 (errSecItemNotFound)
2. The app only ever talks to the data-protection keychain
Unified-log capture across the whole import (log stream --level debug), counting keychain daemon operations attributed to the app's main process:
secd[632] (data-protection keychain) ops from Claude[2394]: 6
securityd[391] (legacy login keychain) ops from Claude[2394]: 0
Every operation takes the _ios / data-protection path:
Claude[2394]: (Security) Created Activity ID: 0x4fc05, Description: SecItemCopyMatching
Claude[2394]: (Security) Created Activity ID: 0x4fc06, Description: SecItemCopyMatching_ios
Claude[2394]: (Security) [com.apple.securityd:xpc] not using system keychain
secd[632]: [com.apple.securityd:serverxpc] XPC [Claude[2394]/1#13 LF=0] operation: copy_matching (1)
The legacy keychain daemon securityd[391] is never consulted by the app. (The only securityd[391] entries mentioning "claude" in the capture belong to the bundled claude-code CLI at an unrelated PID, from the investigation tooling itself.)
3. Touch ID succeeds, against the wrong keychain
Claude[2394]: (LocalAuthentication) [Client,Interactive] evaluateAccessControl:
<SecAccessControlRef: aku;ock(cpo(DeviceOwnerAuthentication));
osgn(cpo(DeviceOwnerAuthentication));odel(true);okd(cpo(DeviceOwnerAuthentication));oa(true)>
operation:3 options:{
1096 = 1;
2 = "list the sites you\U2019re signed into in Google Chrome, to bring them into Cowork\U2019s browser";
}
coreautha[1605]: [com.apple.LocalAuthentication:UI] ... {
CallerId = "com.anthropic.claudefordesktop";
CallerName = Claude;
Constraint = { cpo = DeviceOwnerAuthentication; };
ConstraintOp = osgn;
}
Claude[2394]: (LocalAuthentication) evaluateAccessControl on LAContext[...] returned {
14 = 1;
1 = 1;
8 = 501;
} <-- success
aku and SecAccessControl are data-protection keychain constructs. Chrome's item is a legacy genp entry guarded by a keychain ACL, not by a SecAccessControl. After this successful authentication at 13:49:22.07, the app issues no further keychain operation of any kind — it does not retry against the legacy keychain.
4. Everything the error message implicates is healthy
Chrome running does not lock the database. With Chrome fully running (33 processes, network service holding the file open):
sqlite3 "file:.../Default/Cookies?mode=ro" "SELECT COUNT(*) FROM cookies;" -> 675 exit=0
sqlite3 ".../Default/Cookies" "BEGIN IMMEDIATE; SELECT 1; COMMIT;" -> 1 exit=0
BEGIN IMMEDIATE acquires an exclusive write lock successfully, so no reader is being blocked.
Database is well-formed (checked on a copy, never the original):
PRAGMA integrity_check; -> ok
675 cookies across 186 distinct hosts, 0 rows with empty encrypted_value
encrypted_value prefix distribution: v10 = 675
No app-bound encryption: Local State has no os_crypt section at all, and no app_bound_encrypted_key.
Ruled out by the capture as well:
- No TCC denial. No
tccddenial forcom.anthropic.claudefordesktopanywhere in 41,152 captured lines. - No sandbox denial. The app is not App-Sandboxed (no
com.apple.security.app-sandbox); noSandbox: ... denyline names it. - Not
errSecAuthFailed/errSecInteractionNotAllowed. Authentication returned success. - Not wrong path or wrong profile.
Defaultis the only profile and does contain the populatedCookiesDB.
Secondary issues
No app-side diagnostics. Nothing about the import is logged. ~/Library/Logs/Claude/in-app-browser.log contains only an unrelated React hydration warning. Grepping main.log (4.4 MB), coworkd.log, swift.log and claude.ai-web.log for cookie|safe.?storage|keychain|import|decrypt returns zero hits. The failing path should log the OSStatus it got back.
The error message misdirects. "Quit Google Chrome and try again" sends users down a dead end for a failure that has nothing to do with Chrome running. It should distinguish "couldn't find the decryption key in your keychain" from "couldn't open the cookie database".
Possible follow-on. Full Disk Access on this machine is held by com.anthropic.claude-code, not by com.anthropic.claudefordesktop; the desktop app has no kTCCServiceSystemPolicyAllFiles entry. This did not cause the reported failure — no TCC denial was logged, because the import fails at the keychain step before file access matters. But it may surface as a second failure once the keychain bug is fixed, and it is worth noting that both bundles appear as "Claude" in System Settings, which makes granting the wrong one easy.
Suggested fix
Query the legacy keychain for Chrome Safe Storage — either SecKeychainFindGenericPassword, or SecItemCopyMatching with kSecUseDataProtectionKeychain = false — with service Chrome Safe Storage and account Chrome. Chromium's own OSCrypt on macOS uses the legacy keychain, so the import must match it. Falling back from the data-protection keychain to the legacy keychain on errSecItemNotFound would also work and would cover Chromium variants that store the key elsewhere. The same mismatch likely affects Brave, Edge, Vivaldi and other Chromium browsers, which use the same scheme with different service names.
---
Log excerpts trimmed to the relevant subsystems. Cookie values, hostnames, account identifiers, audit tokens, authentication blobs, metrics client IDs and LAN addresses are excluded; only aggregate counts are reported. Usernames replaced with <user>.
3 Comments
me also
Same here, on an almost identical setup:
"Import cookies from your browser" → Chrome fails with "Couldn't read Google Chrome's data. Quit Google Chrome and try again."
Two data points from this machine:
security find-generic-password -s "Chrome Safe Storage"lists the item in the legacy file keychain (keychain: "~/Library/Keychains/login.keychain-db"). That matches the root cause above: a lookup that only queries the data-protection keychain will not find it.Operation not permittedonls ~/Library/Application Support/Google/Chrome/. So on macOS 27 the app may also be blocked from reading Chrome's profile folder without Full Disk Access. If that is part of the failure, the importer should ask for that permission instead of telling the user to quit Chrome.Either way the error message sends users in the wrong direction. Falling back to the legacy keychain (
kSecUseDataProtectionKeychain = falseorSecKeychainFindGenericPassword) and showing a clear permission prompt when the profile folder can't be read would fix both.Possibly related, in case it helps others. On my Mac (Claude for Mac 2.31226.1, macOS 27.0.1) the "Import cookies" dialog initially listed only Microsoft Edge, even though Chrome and Firefox are installed. Chrome and Firefox appeared only after I enabled them under System Settings > Privacy & Security > Files & Folders > Claude. After that, importing from Chrome worked for me, and I have not seen the keychain error described here. I filed the missing-browsers part separately as #101720.