Skip to content

feat(express): add host-scoped CA trust and SPKI pinning for BitGo connections - #10033

Draft
zahin-mohammad wants to merge 2 commits into
masterfrom
zahinmohammad/wcn-3731-host-scoped-ca-trust-spki-pinning
Draft

zahin-mohammad wants to merge 2 commits into
masterfrom
zahinmohammad/wcn-3731-host-scoped-ca-trust-spki-pinning

Conversation

@zahin-mohammad

Copy link
Copy Markdown
Contributor

Summary

Implements WCN-3731. Adds an opt-in outbound TLS policy to BitGo Express that applies only to BitGo hostnames. Everything else (external signer, block explorers, KMS, etc.) keeps the system CA store.

  • BITGO_CA_BUNDLE_PATH / --bitgocabundlepath: PEM of the only CAs trusted for BitGo hosts (replaces, not extends, the system store for them).
  • BITGO_SPKI_PINS / --bitgospkipins: base64 SHA-256 SPKI pins; one certificate in the presented chain must match. Pinning a CA/intermediate key survives leaf rotation; include a backup pin.
  • BITGO_TLS_HOSTS / --bitgotlshosts: extra covered hostnames. The host of the configured BITGO_ENV / BITGO_CUSTOM_ROOT_URI is always covered.
  • sdk-api: new tlsPolicy option plus createBitGoTlsPolicy, enforced in BitGoAPI.getAgentRequest, the single builder for BitGo-bound requests (covers requestPatch, /client/constants and asset requests).
  • README: config table rows, runbook (pin generation, rotation, rollback, ownership/monitoring).

Design decisions to review

  • Redirects are not followed for policy hosts (redirects(0)). superagent keeps ca/agent on the request across hops, so following a redirect could not re-evaluate the host policy. Cost: any 3xx from BitGo becomes an error when the policy is on.
  • Incompatible with BITGO_USE_PROXY. A proxy agent owns the TLS socket and would silently bypass the policy, so Express refuses to start and the SDK constructor throws.
  • Fail fast: an unreadable bundle or one with no certificates stops startup instead of falling back to the system store.
  • Opt-in and off by default; no behavior change unless configured.

Out of scope / follow-ups

  • Hosts that bypass BitGoAPI (external signer calls, sdk-api/src/v1/wallet.ts explorer call, coin-module explorers) are intentionally unaffected; they are not BitGo hosts.
  • Ticket items not covered by code: inventorying real CA chains per BitGo endpoint (CDN, regional, DR) to build the production bundle and pin set, and the alerting on bundle expiry. The default host is only the configured API host; other BitGo hostnames must be added via BITGO_TLS_HOSTS.

Testing

  • sdk-api test/unit/tlsPolicy.ts (real local HTTPS servers, certs from two separate CAs generated with openssl): approved CA accepted, unapproved CA rejected, SPKI pin match / CA-key pin / mismatch, non-BitGo host stays on default trust, redirect off-host not followed, proxy conflict, host matching (evilbitgo.com, bitgo.com.evil.example, http).
  • express test/unit/tlsPolicy.ts and config.ts precedence for the new options.
  • Express suite: 1983 passing. sdk-api suite run before opening.

TICKET: WCN-3731

🤖 Generated with Claude Code

…nnections

Add an opt-in outbound TLS policy applied only to BitGo hostnames. A CA
bundle (BITGO_CA_BUNDLE_PATH) replaces the system trust store for those
hosts, and optional SPKI pins (BITGO_SPKI_PINS) must match a certificate
in the presented chain. All other destinations keep the system store.

The policy is attached in BitGoAPI.getAgentRequest, the single builder
for BitGo-bound requests. Requests to policy hosts do not follow
redirects, and the policy cannot be combined with BITGO_USE_PROXY since a
proxy agent would bypass it.

TICKET: WCN-3731
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@linear-code

linear-code Bot commented Oct 22, 2026

Copy link
Copy Markdown
Contributor

WCN-3731

Other sdk-api suites call nock.disableNetConnect() globally, which
blocked the local HTTPS servers when the full suite ran.

TICKET: WCN-3731
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@zahin-mohammad

Copy link
Copy Markdown
Contributor Author

@claude

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Claude encountered an error —— View job


I'll analyze this and get back to you.

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

⚠️ Unit tests are failing on Node 26.x (Current release line, non-blocking). This is not an LTS version yet, so it does not block merge, but it signals an incompatibility to fix before Node 26.x becomes LTS.

View run

This branch has not been deployed

No deployments
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.

1 participant