# Security operations playbook This document expands on the top-level [SECURITY.md](../SECURITY.md) with implementation details. ## Secrets handling - bkt never stores plaintext credentials under version control. Tokens are stored in the OS keychain (macOS Keychain Access, Windows Credential Manager, Linux Secret Service) or an encrypted local file backend. Host metadata lives in `config.yml` in the bkt config directory with permissions `0600`. The `BKT_TOKEN` environment variable provides runtime-only injection for CI/headless use. - bkt's Bitbucket Cloud OAuth consumer key and secret are in source (`pkg/oauth/cloud.go`). A secret shipped inside a native app cannot stay confidential (RFC 8252 ยง8.5), so it is public-client material, not a user secret; the GitHub CLI and Git Credential Manager ship theirs the same way. A user's access is protected by their consent in the browser and by the tokens in their keychain. Two consumer settings make a public secret safe; keep them: - Marked **public** on Bitbucket, so the secret cannot mint `client_credentials` tokens that act as the consumer's owner. - Callback restricted to the loopback host. Bitbucket matches the `redirect_uri` host exactly and allows any port, so codes reach only the listener bkt binds on `127.0.0.1` before it opens the browser. - Bitbucket grants a token every permission configured on the consumer, whatever scopes bkt requests, so the consumer's permissions decide what a bkt login can do. Grant only what bkt's Cloud commands use. - Residual risks of a shared public consumer: Bitbucket Cloud ignores PKCE, so local malware that captures an authorization code on the loopback port can redeem it; anyone can show bkt's consent screen; and API quota is counted per consumer. Stealing a user's tokens still requires access to their keychain. If the consumer is ever revoked, users log in again with `--web-token`, or set `BKT_OAUTH_CLIENT_ID` and `BKT_OAUTH_CLIENT_SECRET` to their own consumer. - For development, set `BKT_CONFIG_DIR` to a throwaway directory. - Never commit test credentials. Unit tests use `t.TempDir()` with `BKT_CONFIG_DIR`. ## Dependency updates - Dependabot is enabled for Go modules and GitHub Actions (`.github/dependabot.yml`). - Run `go list -m -u all` periodically to spot stale modules. - CI runs [OpenSSF Scorecard](https://github.com/ossf/scorecard) weekly. ## Supply chain - Release artifacts are built with GoReleaser (`.goreleaser.yaml`) from the verified merge commit on `master`. - Each release publishes a checksum manifest, a CycloneDX SBOM generated by Syft, and GitHub build provenance attestations (`gh attestation verify --repo avivsinai/bitbucket-cli`). - macOS binaries are signed with a Developer ID and notarized by Apple (`scripts/codesign-macos.sh`). ## Incident response 1. Triage the report and reproduce the issue. 2. Assign a severity (CVSS) and determine the affected versions. 3. Prepare a patch on a private branch. Request a security review from another maintainer. 4. Cut a release PR with the fix, update `CHANGELOG.md` with mitigation steps, and let CI create the release tag after the merge validates. 5. Notify the reporter and disclose publicly within seven days of the fix. ## Contact Email **avivsinai@gmail.com**. We prefer coordinated disclosure.