Skip to content

Commit 5922553

Browse files
Add macos keyring security doc (cli#13960)
1 parent 01b79dd commit 5922553

1 file changed

Lines changed: 37 additions & 0 deletions

File tree

docs/macos-keyring.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# macOS Keyring Security
2+
3+
This document describes how the GitHub CLI uses the macOS keyring, and related security notes.
4+
5+
The GitHub CLI updates the keyring on the following commands:
6+
* `gh auth login` (store a new token)
7+
* `gh auth refresh` (store a new token)
8+
* `gh auth logout` (delete a token)
9+
* `gh auth switch` (swap the token for the "active" account)
10+
11+
Additionally, it reads from the keyring on any command that requires a token.
12+
13+
### Implementation
14+
15+
Keyring support is provided by the [zalando/go-keyring](https://github.com/zalando/go-keyring) module. On MacOS, this [execs the `/usr/bin/security` binary](https://github.com/zalando/go-keyring/blob/v0.2.8/keyring_darwin.go#L44-L48) to interact with the keyring. Alternatives to this approach involve `cgo`, as per [ByteNess/go-keychain](https://github.com/ByteNess/go-keychain/blob/c96c38f7f906df0da922f9422a049c550084ce9f/keychain.go#L10) or `purego` as per [lstoll/keychain](https://github.com/lstoll/keychain). Choosing between these options has tradeoffs as described below.
16+
17+
### Consequences of using `/usr/bin/security`
18+
19+
Access to keyring items is protected via an ACL (Access Control List). When an application attempts to access an item, the user is prompted to `allow`, `deny`, or `always allow`. In the case of `always allow`, this decision is persisted for future access attempts by the same application.
20+
21+
Since the binary accessing the `gh` keyring items is `/usr/bin/security`, calling `security` directly from a terminal can also access the stored `gh` tokens for a given host and user.
22+
23+
Historically, this has not been a significant concern with downsides to the alternatives (see below), primarily because `gh` offers direct access to the token via `gh auth token`. There is an argument to be made that `gh` should be less _surprising_ in this behaviour, and with the rise in agentic development, this probably has more merit.
24+
25+
### Consequences of using Apple native APIs
26+
27+
Aside from the increased maintenance burden of introducing `cgo` or `purego`, there is a significant consequence for Homebrew distributions. Trusted applications in the keyring ACL are identified differently depending on whether they are codesigned with a stable identity. For an application signed with a certificate (e.g. a Developer ID), the identity remains stable across artifacts signed by the same certificate. For an application without a stable signing identity - either unsigned, or ad-hoc signed as the Go toolchain does for Apple Silicon binaries - the identity is determined by a hash of the code bytes (its `cdhash`). Therefore, for such applications, any change invalidates the keyring ACL.
28+
29+
Our primary distribution mechanism for MacOS is `homebrew`, which [builds `gh` as part of the packaging/installation pipeline](https://github.com/Homebrew/homebrew-core/blob/922e24021672a1627218fe4bb2af67bcd20d86df/Formula/g/gh.rb#L42), resulting in an artifact without a stable signing identity (unsigned on x86_64, ad-hoc signed on Apple Silicon). The consequence of this is that on every upgrade of the homebrew package, users will be prompted for keyring access.
30+
31+
This may additionally affect anyone else building for MacOS either for distribution (e.g. `conda`, `flox`, `macports`, `spack`, `webi`) or personally (e.g. `go install`).
32+
33+
For homebrew, resolving this would involve moving `gh` to a `cask` distribution, where `gh` builds and signs the application. It's not clear the full consequences of moving from a formula to a cask, but homebrew maintainers recommend formulas where possible.
34+
35+
### Conclusion
36+
37+
The GitHub CLI interacts with the keyring in a surprising manner, leaving a narrow (but increasing, due to agent adoption) opportunity for a token to be obtained unexpectedly. As maintainers, we currently believe the convenience for distributors and users outweighs the risks proposed.

0 commit comments

Comments
 (0)