Skip to main content
Scopes a v1 audit and the release-blocker gate. Every blocker maps to a verification command.

Scope (in)

The SDK packages - core, accounts/oz-contract, signers/passkey, relayer/buckspay-facilitator, react - and the facilitator’s new contract endpoints + the relay from=C-address path. Focus areas: auth-entry construction, the __check_auth secp256r1 signature format, expiration/nonce handling, the relayer trust boundary, and the BFF key boundary. Also in scope: the deployed minimal-passkey-account smart-account wrapper (spikes/passkey-contract/contract/src/lib.rs) - buckspay-authored __constructor/__check_auth around OZ’s audited verifier; see Contract provenance.

Scope (out / deferred)

OpenZeppelin’s audited WebAuthn/secp256r1 verifier (stellar_accounts::verifiers::webauthn::verify)
  • we pin the wasm that calls it and do not re-audit OZ’s verifier; the buckspay wrapper around it is in scope (above). Also out of scope: the wallet/authenticator implementations (Freighter, platform WebAuthn) and the gasless features (token-gas, batch, sessions, social login).

Contracts vs SDK boundary

buckspay deploys + authorizes against a smart-account contract. It does not author the cryptographic verifier (OZ’s audited verify), but it does author the thin minimal-passkey-account wrapper around it (__constructor/__check_auth) - that wrapper is in audit scope (see Contract provenance). The SDK’s off-chain responsibility ends at producing correct, bounded, validated auth entries and never holding secrets. The on-chain __check_auth (wrapper) -> verify (OZ) is the sole signature verifier.

Transitive risks from @creit.tech/stellar-wallets-kit (status)

Its multi-wallet connectors (Trezor/xBull/LOBSTR/Near/Hot/WalletConnect/ethereumjs) pull deps that are not buckspay code:
  • Advisories - RESOLVED (high + critical). All 5 high + 1 critical were protobufjs <7.6.1. Pinned to the patched >=7.6.1 <8 via a pnpm overrides entry in pnpm-workspace.yaml (kept on the 7.x line to avoid a major bump). pnpm audit --audit-level=high --prod is now clean; the full workspace suite stays green. Remaining: 1 low + 1 moderate, accepted - not high-severity, no patch path that doesn’t churn the connector tree; re-checked weekly by CI.
  • Copyleft/Unknown licenses - ACCEPTED (confined + CI-locked). AGPL ua-parser-js, LGPL rpc-websockets, GPL @lobstrco/*, MPL @ethereumjs/*, plus several Unknown (Trezor/Near/ Hot/xBull connectors). All are hard transitive deps of @creit.tech/stellar-wallets-kit - connector modules the Stellar gasless path never exercises; they are not redistributed as part of any @buckspay/* package. Finding: narrowing the runtime module set does not remove them - they are declared by the umbrella package, so importing it pulls the whole tree regardless of which modules are instantiated (the signer already wires only Freighter/xBull/ LOBSTR). The license gate exempts exactly this set with a per-package reason (scripts/check-licenses.mjs), and a guard locks the acceptance: any copyleft/Unknown dep outside the known wallets-kit set fails CI (pnpm --filter @buckspay/signers exec vitest run no-unexpected-copyleft). Clean-slate fix (deferred, deliberate product decision): vendor a Freighter-only connector via @stellar/freighter-api and drop @creit.tech/stellar-wallets-kit entirely - this removes the copyleft tree but loses multi-wallet (xBull/LOBSTR) support, so it was not taken.

Release-blocker checklist

BlockerVerification command
Threat model presentbash scripts/check-threat-model.sh
No secrets in srcbash scripts/check-no-secrets-in-src.sh
No secret in react bundlepnpm --filter @buckspay/react exec vitest run no-secret-in-bundle
Expiration boundedpnpm --filter @buckspay/core exec vitest run expiration-bounded
Licenses within allow-listpnpm licenses
OZ Wasm hash pinned (real pinned value)pnpm --filter @buckspay/accounts exec vitest run oz-wasm-pin
Mainnet gatedpnpm --filter @buckspay/core exec vitest run network-gate
e2e green on testnet (classic + contract/passkey flows)BUCKSPAY_E2E=1 pnpm e2e
pnpm audit reviewed (transitive advisories accepted/resolved)pnpm audit --audit-level=high --prod
Run all at once: bash scripts/release-gate.sh.

Mainnet release blockers

Extends the checklist above with the mainnet-cutover items. Each maps 1:1 to a line in scripts/release-gate.sh.
BlockerVerification commandStatus
Secrets rotated (no tracked .env*, sponsor ≠ leaked G)bash scripts/check-no-committed-env.shguard
Secret-rotation runbook presenttest -f docs/security/secret-rotation.mddoc
Licenses within allow-list (copyleft confined to wallets-kit)node scripts/check-licenses.mjsguard
No unexpected copyleft in prod treepnpm --filter @buckspay/signers exec vitest run no-unexpected-copyleftguard
OZ wasm-hash pin reproduciblenode scripts/verify-wasm-hash.mjsguard
Cross-repo wasm-pin paritybash scripts/check-pin-parity.shguard
Mainnet cutover runbook presentbash scripts/check-cutover-runbook.shguard
Gated mainnet smokeBUCKSPAY_E2E_MAINNET=1 BUCKSPAY_E2E=1 pnpm e2egated (skips when unset)
This gate enforces “no copyleft outside the accepted wallets-kit tree”, not “zero copyleft” - the multi-wallet connectors are an accepted, confined risk (see the transitive-risks section above). Flipping to zero-copyleft requires the deferred Freighter-only vendoring.

Sign-off

The audit sign-off is filled by the auditor once bash scripts/release-gate.sh is green end-to-end. The scope hash ties a specific audit to a specific tree state - recompute with bash scripts/audit-scope-hash.sh; if it no longer matches, in-scope code changed after sign-off and the audit must be re-validated.
AuditorDateScope hashResult
(pending - engagement not yet run)963d5e9e36f38dcb16719da305372ae6af2ea0cb981ff96fbe8a506637f944d9(pending)