fix: prevent macOS keychain writes from exposing API keys in process list#245
Open
bukinoshita wants to merge 3 commits intomainfrom
Open
fix: prevent macOS keychain writes from exposing API keys in process list#245bukinoshita wants to merge 3 commits intomainfrom
bukinoshita wants to merge 3 commits intomainfrom
Conversation
…list - Replace /usr/bin/security add-generic-password (which passes secret as CLI arg visible in ps) with JXA script piped via stdin to osascript, using the Security framework (SecItemAdd/SecItemUpdate) directly. The secret never appears in process arguments. - Remove auto-migration from resolveApiKeyAsync: read-only commands (whoami, doctor, etc.) no longer trigger credential writes. Migration now only happens through explicit write paths (login, storeApiKeyAsync). - Add macOS backend unit tests verifying secret is passed via stdin. - Add config-async test verifying no auto-migration on read paths. Co-authored-by: Bu Kinoshita <bukinoshita@users.noreply.github.com>
bukinoshita
commented
Apr 9, 2026
bukinoshita
commented
Apr 9, 2026
bukinoshita
commented
Apr 9, 2026
…ckend Co-authored-by: Bu Kinoshita <bukinoshita@users.noreply.github.com>
Member
Author
|
@cubic-dev-ai review this PR? |
Contributor
@bukinoshita I have started the AI code review. It will take a few minutes to complete. |
felipefreitag
requested changes
Apr 10, 2026
Contributor
felipefreitag
left a comment
There was a problem hiding this comment.
This isn't working for me:
◇ Enter your Resend API key:
│ ▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪
✔ API key is valid (full access)
│
◇ Save API key to which profile?
│ qa-test-pr245 (overwrite)
Error: Failed to store credential in macOS Keychain: execution error: Error: Error: Keychain error: -50 (-2700)
ELIFECYCLE Command failed with exit code 1.
Likely problem:
- $.kSec* constants don't work as NSDictionary keys in JXA. They're opaque Ref objects that all hash to the same key, so the dictionary ends up with 1 entry instead of 4. SecItemAdd returns -50 (errSecParam). Fix: use the raw string values ($("class"),
$("genp"), $ ("svce"),$("acct"), $ ("v_Data")) instead of$.kSecClass, $ .kSecClassGenericPassword, etc.
I investigated a bit and got past that error, but then any attempt to read the key keps prompting for keychain access and failing.
- ACL mismatch between set() and get(). Items written by osascript via SecItemAdd get an ACL that only trusts /usr/bin/osascript. But get() still uses /usr/bin/security find-generic-password -w, which is a different binary — so macOS shows a keychain authorization prompt, the 5s timeout fires, and get() fails with exit code null. Either get() needs to also use JXA/SecItemCopyMatching, or the set() script needs to add /usr/bin/security as a trusted application in the ACL.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Resolves BU-628: macOS keychain writes expose API keys in process list.
The
MacOSBackend.set()method was passing the API key as a command-line argument to/usr/bin/security add-generic-password -w <secret>, making it visible to any process listing tool (ps, endpoint monitoring, etc.) during the write.Summary by cubic
Secure macOS Keychain writes so API keys never appear in process args, and stop auto-migrating credentials during reads. Fixes BU-628.
Bug Fixes
/usr/bin/osascript, callingSecItemAdd/SecItemUpdatewith secrets sent over stdin.resolveApiKeyAsync; reads never write credentials. Added tests for stdin-only handling and no auto-migration.Refactors
Written for commit 5241187. Summary will update on new commits.