Security audits
Independent review is the standard.
AI is the standing review layer.
Asylia has not completed an external human audit yet. Until that bar is cleared, every Bitcoin-critical change is reviewed with a recurring AI-assisted process across GPT, Claude, and Gemini, then kept open for human inspection.
v0.3 · 2026-05-04 · May 4, 2026
01 · Status
Independent review is the standard. AI is the standing review layer.
That is a security fact, not a footnote.
Asylia is early, and the honest state is simple: no external human security firm has completed a report on the product. We will not use the word audited as a shortcut until that work exists, is reviewed, and can be linked publicly.
The current control is a standing AI-assisted review program focused on the narrow Bitcoin surface: descriptors, script construction, PSBT assembly, hardware signing adapters, signature checks, and broadcast behavior. AI review does not certify the system. It raises questions, finds edge cases, and forces repeatable evidence before code ships.
AI review
Recurring
Run against material security changes and release candidates.
Model quorum
3 families
GPT, Claude, and Gemini are used as separate review lenses.
02 · Reports
Public audit history.
Public-safe audit records tied to release branches, model versions, scope, findings, and residual risk.
Sorted newest first from content/audits.
gpt-5-5-release-security-audit-2026-05-12 · May 12, 2026
Security Audit: Wallet access, PSBT policy, and signer authentication
Security audit by GPT-5.5 covering wallet access sessions, signer authentication, PSBT policies, Supabase RLS/RPC boundaries, hardware signer adapters, and release gates.
- Target
- main
- Commit range
- main...release/test
- Models
- GPT-5.5
- Findings
- C0 / H0 / M0 / L1 / I4
Scope
- Wallet access sessions and signer authentication
- PSBT spending policy validation and proposal transaction lifecycle enforcement
- Ledger and Trezor hardware signer authentication and signing adapters
- Supabase RLS, service-role-only RPCs, and branch database security tests
- CI/release gates, production configuration checks, and audit publication artifacts
Read the public report on this page
Security Audit: Wallet access, PSBT policy, and signer authentication
Date: May 12, 2026 Audit ID: gpt-5-5-release-security-audit-2026-05-12 Model: GPT-5.5
As part of our commitment to transparent security, we conducted an automated security audit on the latest release candidate.
Audit Scope
This review focused on:
- Wallet access sessions and signer authentication
- PSBT spending policy validation and proposal transaction lifecycle enforcement
- Ledger and Trezor hardware signer authentication and signing adapters
- Supabase RLS, service-role-only RPCs, and branch database security tests
- CI/release gates, production configuration checks, and audit publication artifacts
Results
The audit found zero critical, high, or medium severity issues.
We identified one low-severity residual risk related to the expanded service-role Edge Function boundary. The reviewed implementation mitigates this with authentication, session binding, single-use challenge checks, vault access checks, hardened PSBT policy validation, and service-role-only RPC grants.
There are no unresolved critical/high or blocking findings. The release has been marked as passed with notes.
gemini-3-1-pro-release-audit-2026-05-10 · May 10, 2026
Security Audit: Wallet-centric access, PSBT policy, and Ledger integration
Security audit by Gemini 3.1 Pro covering wallet access profiles, PSBT policies, Ledger hardware authentication, and Supabase RPC proposal enforcements.
- Target
- main
- Commit range
- main...release/test
- Models
- Gemini 3.1 Pro
- Findings
- C0 / H0 / M0 / L1 / I2
Scope
- Wallet-centric access profiles and billing
- PSBT spending policy validation helpers
- Ledger hardware signer authentication
- Proposal transaction state enforcement in Supabase
Read the public report on this page
Security Audit: Wallet-centric access, PSBT policy, and Ledger integration
Date: May 10, 2026 Audit ID: gemini-3-1-pro-release-audit-2026-05-10 Model: Gemini 3.1 Pro
As part of our commitment to transparent security, we have conducted an automated security audit on the latest release candidate.
Audit Scope
This review focused on:
- Wallet-centric access profiles and billing
- PSBT spending policy validation helpers
- Ledger hardware signer authentication
- Proposal transaction state enforcement in Supabase
Results
The audit found zero critical, high, or medium severity issues.
We identified two informational items related to memory safety and authentication challenge signing, and one low-severity item related to platform fee calculations being performed client-side, which are appropriately validated server-side.
There are no unresolved critical/high or blocking findings. The release has been marked as passed.
gemini-3-1-pro-release-test-2026-05-05 · May 5, 2026
Security Audit: UI & Dust Handling
Security audit by Gemini 3.1 Pro covering UI updates, marketing copy, coin selection dust handling, and network fee buffers.
- Target
- main
- Commit range
- main...release/test
- Models
- Gemini 3.1 Pro
- Findings
- C0 / H0 / M0 / L1 / I2
Scope
- E2E test RLS session caching
- Bitcoin network fee buffer addition
- Coin selection dust absorption
- Marketing copy and localization updates
- UI design system updates
Read the public report on this page
Security Audit: UI & Dust Handling
Date: May 5, 2026 Audit ID: gemini-3-1-pro-release-test-2026-05-05 Model: Gemini 3.1 Pro
As part of our commitment to transparent security, we have conducted an automated security audit on the latest release candidate.
Audit Scope
This review focused on:
- Bitcoin network fee buffer addition
- Coin selection dust absorption
- Marketing copy and localization updates
- E2E test RLS session caching
Results
The audit found zero critical, high, or medium severity issues.
We identified two informational items related to UX improvements for transaction fees (dust absorption and fee buffers) and one low-severity item related to non-production E2E testing infrastructure.
There are no unresolved critical/high or blocking findings. The release has been marked as passed.
claude-opus-4-7-security-audit-2026-05-04 · May 4, 2026
Independent second-model audit: wallet spend, proposal, and hardware-wallet hardening
Independent second-model security audit by Claude Opus 4.7 covering the same release/test promotion candidate as the Gemini 3.1 Pro audit recorded earlier the same day. Concurs with zero critical/high/medium/low findings; adds one informational note about the row-scoped UPDATE policy on V1_VaultProposals. No release blocker.
- Target
- main
- Commit range
- main...release/test
- Models
- Claude Opus 4.7, Gemini 3.1 Pro (referenced)
- Findings
- C0 / H0 / M0 / L0 / I3
Scope
- Supabase migrations: wallet spend locks, proposal scope hardening, server-validated PSBT updates, direct-insert revoke, broadcast RPC and lifecycle trigger
- Supabase Edge Functions: proposal-psbt, btc-broadcast, csp-report, ops-health, ops-monitoring-synthetic, btc-network-fees, btc-fiat-rates, btc-chain-fallback
- Shared Edge auth: constant-time bearer secret comparison and header-secret fallback
- Wallet SPA services: sessions IPv6 masking, proposals service-side validation, logger redaction, spendPlanner P2WSH fee math
- Bitcoin core: PSBT outpoint parsing strictness and P2WSH-multisig coin selection vbytes
- Hardware-wallet @asylia/hw-trezor: log redaction with safe-key allowlist and build-flag-gated unsafe-diagnostic path, ECDSA post-flight signature verification
- Wallet Content Security Policy and Permissions-Policy on Vercel and the SPA _headers file
- CI release controls: post-deploy synthetic smoke workflow and wallet production gate guards
- Audit tooling: enforce model slug in audit file names
Read the public report on this page
Independent Second-Model Audit: Wallet Spend, Proposal, And Hardware-Wallet Hardening
Audit ID: claude-opus-4-7-security-audit-2026-05-04
Date: 2026-05-04
Target: main
Source branch: release/test
Commit range: main...release/test
Status: passed with notes
Summary
This audit is an independent second-model security review of the same
release/test candidate that the Gemini 3.1 Pro audit covered earlier the
same day (security-audit-2026-05-04). It is intentionally redundant with
that pass: a release candidate that hardens the wallet spend pipeline,
proposal lifecycle, hardware-wallet logging, Edge Function auth comparison,
CSP, and coin-selection fee math is exactly the kind of change set where
multi-model concurrence is worth recording.
Claude Opus 4.7 re-read the security-relevant diff (git diff main...release/test) end to end with focus on:
- the new
create_vault_spend_proposal/set_vault_proposal_psbt/mark_vault_proposal_broadcastedSECURITY DEFINERRPC trio and the matchingv1_vault_proposals_enforce_insert_pathandv1_vault_proposals_enforce_lifecycletriggers, - the
proposal-psbtEdge Function content validator (input multiset match againstV1_VaultProposalInputslocks, output multiset match against the stored recipient + change + platform-fee summary, fee recompute, BIP-32-derivation-anchored signature counting, end-to-end finalisation when threshold is met), - the
btc-broadcastEdge Function stored-PSBT binding (re-finalisespsbt_base64, requires the suppliedrawTxHexandexpectedTxidto match byte-for-byte, validatesalreadyBroadcastedBy.txidagainst the same canonical txid, rate-limits server-side broadcasts viaconsume_btc_broadcast_quota, marks broadcast only through the service-role RPC), - the shared-secret comparison helpers (
requireBearerSecret,requireBearerOrHeaderSecret) on the constant-time path, - the wallet CSP on
apps/wallet/public/_headersanddeploy/vercel/wallet.json(the broadhttps://*.asylia.ioconnect-srcsource is removed;_headersandwallet.jsonare kept in sync by theverify:production-configgate), - the
@asylia/hw-trezoradapter (safe-key allowlist redaction inlog.ts, build-flag-gatedunsafeDiagnosticpath with atsupbuild that hard-disables the flag in production-like builds, ECDSA post-flight signature verification with a sweep-and-pivot fallback and hard refusal when no cosigner pubkey verifies), - coin-selection vbyte parameters in
@asylia/btc-coreand the walletspendPlanner(DEFAULT_FIXED_VBYTES = 85,DEFAULT_PER_INPUT_VBYTES = 110,DEFAULT_CHANGE_OUTPUT_VBYTES = 43, all paths round fees up viaMath.ceil), - IPv6 session IP masking on
apps/wallet/src/services/sessions.ts(compressed::addresses keep at most two leading segments), - the post-deploy synthetic smoke workflow
(
.github/workflows/post-deploy-smoke.yml,apps/wallet/e2e/post-deploy-smoke.spec.ts,apps/wallet/playwright.post-deploy.config.ts), - the wallet production-gates workflow guard and
verify-release-auditenforcement of the model-slug-in-filename convention.
The conclusion concurs with the parent audit: zero critical, high,
medium, or low findings, two info-level notes, no release blocker. This
report adds one further informational observation about the row-level
update policy on V1_VaultProposals that does not affect funds safety
but is worth recording for future migrations.
This release does not change BIP-48 derivation roots, the descriptor
format (wsh(sortedmulti(...))), the BIP-67 ordering rules, the network
constant (mainnet only), or the threat model around seed phrases,
hardware-wallet secrets, service-role keys, or private operational
tokens.
Release Target And Commit Range
- Target branch:
main - Source branch:
release/test - Commit range:
main...release/test - Notable commits reviewed (same set as the parent audit):
180f2fca9fix(supabase): harden proposal validation and insert controls09f7f0accfix(hw-trezor): keep signing diagnostics redacted by default8e948360ffix(btc-core): align P2WSH fee estimates with wallet spends62d057806fix(wallet): harden session IP maskingf55e4b57echore(deploy): tighten wallet CSP on Vercel06e176fbbtest(logger): add tests to ensure sensitive fingerprint values are redacted73668b7e0test(supabase): cover edge function handlers6f21c193bci(wallet): add post-deploy smoke workflow40b3b31b6ci(wallet): require UI coverage in production gates5d50c4b5bdocs(audit): add security audit report for May 4, 2026 by Gemini 3.1 Pro
Scope
- Supabase migrations:
20260429202000_wallet_spend_locks.sql20260430130000_vault_proposals_scope_hardening.sql20260502195000_btc_broadcast_stored_psbt_binding.sql20260502201000_proposal_broadcast_rpc_cache_and_trigger.sql20260503083000_server_validated_proposal_psbt_updates.sql20260503174813_restrict_direct_vault_proposal_inserts.sql
- Supabase Edge Functions:
proposal-psbt,btc-broadcast,csp-report,ops-health,ops-monitoring-synthetic,btc-network-fees,btc-fiat-rates,btc-chain-fallback,_shared/auth.ts. - Wallet SPA:
apps/wallet/src/services/sessions.tsapps/wallet/src/services/proposals.tsapps/wallet/src/services/spendPlanner.tsapps/wallet/src/services/logger.ts
- Bitcoin core:
packages/btc-core/src/psbt/build.tspackages/btc-core/src/psbt/coin-select.ts
- Hardware-wallet adapter:
packages/hw-trezor/src/log.tspackages/hw-trezor/src/sign.tspackages/hw-trezor/src/init.tspackages/hw-trezor/tsup.config.tsandsrc/build-flags.d.ts
- Deploy / CSP:
apps/wallet/public/_headersdeploy/vercel/wallet.json
- CI / release controls:
.github/workflows/post-deploy-smoke.yml.github/workflows/wallet-production-gates.ymlapps/wallet/e2e/post-deploy-smoke.spec.tsapps/wallet/playwright.post-deploy.config.tstools/verify-supabase-security.mjstools/verify-production-config.mjstools/verify-release-audit.mjs
Threat Model
The audit considered the same attacker classes as the parent audit:
- direct PostgREST writes that forge proposal rows, lifecycle status, or broadcast metadata,
- a malicious or compromised SPA submitting a PSBT whose inputs/outputs/fee do not match the stored proposal summary or the active input locks,
- a SPA-supplied
alreadyBroadcastedByreport that lies about the network txid in order to bind the wrong txid to a real proposal, - timing side channels on shared-secret bearer auth (
OPS_HEALTH_TOKENand the public ops-monitoring header), - hardware-wallet device interaction leaking xpubs, fingerprints, descriptors, or full PSBTs to the browser console or operational logs,
- a Trezor signing path that produces a partial signature that does not verify against any cosigner pubkey on the input,
- coin-selection fee math that underestimates the on-chain footprint and produces a transaction below the network minimum relay fee,
- session listing leaking full IP addresses to the SPA UI,
- CSP weakening that allows arbitrary
*.asylia.iofirst-party connect targets, - broken release-audit gating that allows an unreviewed change to reach
main.
Model Review
| Provider | Family | Model/version | Role | Status |
|---|---|---|---|---|
| Anthropic | Claude | Claude Opus 4.7 (claude-opus-4-7) | Independent second-model security audit (code review, RLS review, CSP review, Edge Function review, hardware-wallet adapter review, fee/coin-selection review, CI/release controls review) | Completed |
| Gemini | Gemini 3.1 Pro (google-geminy-3-1-pro) | Primary security-first release audit (recorded separately as security-audit-2026-05-04) | Referenced |
Claude Opus 4.7 ran:
- a manual diff read of the full
git diff main...release/test(105 files, ~7 500 insertions, ~500 deletions), - direct execution of the static gates
verify:supabase-security,verify:production-config,verify:wallet-production-gates, andverify:release-audit, - inspection of the Supabase migration semantics, with attention to the
ordering of the
v1_vault_proposals_enforce_lifecycletrigger across20260502201000_proposal_broadcast_rpc_cache_and_trigger.sqland20260503083000_server_validated_proposal_psbt_updates.sql(the later migration replaces the function with a strict superset of the previously enforced rules; no lifecycle invariant is dropped), - inspection of the transaction-local config flag pattern
(
asylia.allow_vault_proposal_insert,asylia.allow_proposal_psbt_update,asylia.allow_proposal_ready_update,asylia.allow_broadcast_proposal_update) — every flag is set withset_config(..., true)and the trigger reads withcurrent_setting(name, true)(missing_ok = true).
Findings
| Severity | Count | Notes |
|---|---|---|
| Critical | 0 | No funds-moving, key-handling, RLS, descriptor, PSBT-builder, or transaction-broadcast invariant is weakened by this change set. |
| High | 0 | No production secret, RLS boundary, or hardware-wallet trust path is exposed; service-role privilege remains scoped to narrow SECURITY DEFINER functions. |
| Medium | 0 | No mandatory production gate is removed; new lifecycle and content-binding checks add belt-and-braces over RLS. |
| Low | 0 | Coin-selection vbyte parameters now match Asylia's native-SegWit P2WSH multisig footprint; fee estimates round upward rather than underpaying network minimum. |
| Info | 3 | See below. |
Info-1: Service-role broadcast and PSBT-update RPCs rely on transaction-local config flags (concurs with parent audit)
- Affected surface:
mark_vault_proposal_broadcasted(...),set_vault_proposal_psbt(...),create_vault_spend_proposal(...). - Observation: the
v1_vault_proposals_enforce_lifecycleandv1_vault_proposals_enforce_insert_pathtriggers honourcurrent_setting('asylia.allow_*_update', true)flags set withset_config(..., true)(transaction-local). Theis_local = truethird argument keeps the bypass scoped to the active transaction, so a leaked flag cannot persist across sessions or pollute connection-pooled clients. The bypass remains a service-role-only path; theverify-supabase-securitygate enforces therevoke ... from public, anon, authenticated; grant execute ... to service_rolepattern on everySECURITY DEFINERfunction added after the baseline timestamp. - Impact: None on its own. Recorded so future migrations that add
another lifecycle-altering RPC keep the same
is_local = truediscipline. - Remediation: No action required.
Info-2: Wallet logger covers the dominant sensitive surfaces but is not exhaustive (concurs with parent audit)
- Affected surface:
apps/wallet/src/services/logger.ts. - Observation: the redaction key pattern covers
psbt|xpub|zpub|ypub|descriptor|previousTxHex|rawTxHex|policyHmac|witnessScript|scriptPubKey|privateKey|seed|mnemonic, the address/fingerprint/utxo families are shortened, andUint8Array,ArrayBuffer, and unknown shapes are reduced to redaction placeholders. Adjacent identifiers likeredeemScript,derivationPath,nodeXpub, orsignatureare not in the explicit pattern. In practice, the active call sites either route those values through one of the listed keys (PSBT/xpub/witnessScript) or through thehw-trezoradapter's strictersummariseSensitiveObjectpath. - Impact: None observed.
- Remediation: consider extending
SENSITIVE_KEY_PATTERNin the wallet logger to additionally coverredeemScript,derivationPath,signature, andnodeXpubfor defence-in-depth. Opportunistic improvement, not a release blocker.
Info-3: V1_VaultProposals UPDATE policy is row-scoped, not column-scoped
- Affected surface:
supabase/migrations/20260419140000_vault_proposals.sqlpolicyv1_vault_proposals_update_own. - Observation: the existing UPDATE policy on
V1_VaultProposalsscopes byuser_id = auth.uid()and the correspondingV1_Vaultsownership check, but it is not column-restricted. An authenticated user could therefore write a syntactically valid hex string intobroadcasted_tx_idand a timestamp intobroadcasted_aton their own not-yet-broadcasted row without invoking the canonical broadcast path. Attempting to actually transitionstatustobroadcastedstill fails because the lifecycle trigger requires theasylia.allow_broadcast_proposal_updateflag, which is only set inside the service-role-onlymark_vault_proposal_broadcasted(...)function. The trigger also re-validates txid format and timestamp presence on the broadcasted-status transition itself, and the service-role RPC always re-writes both fields with its own validated parameters underlower(p_txid). Thev1_vault_proposals_enforce_lifecycletrigger additionally freezes both fields oncestatus = 'broadcasted'. - Impact: None on funds safety. A user could only stamp cosmetic values on their own draft/awaiting/ready row; the row remains pre-broadcast, the SPA's broadcast UI does not key off these fields before the lifecycle trigger has approved the transition, and any later legitimate broadcast overwrites them through the service-role RPC.
- Remediation: future hardening could either (a) add a column-level
revoke update (broadcasted_tx_id, broadcasted_at) ... from authenticated; grant update (broadcasted_tx_id, broadcasted_at) ... to service_rolepair, or (b) extendv1_vault_proposals_enforce_lifecycleto require thatbroadcasted_tx_idandbroadcasted_atonly change when status is transitioning to'broadcasted'(i.e. forbid setting them on draft/awaiting/ready rows). Either option is a hygiene improvement; not a release blocker.
Fixes And Accepted Risk
The fixes recorded in security-audit-2026-05-04 are confirmed by this
second-model pass:
- Direct browser inserts on
V1_VaultProposalsare revoked; creation runs exclusively throughcreate_vault_spend_proposal()with atomic active input locks and parent-vault ownership re-check. - Browser clients can no longer set
psbt_base64,ready_to_broadcast, orbroadcasteddirectly. Theproposal-psbtEdge Function re-parses every PSBT, matches inputs againstV1_VaultProposalInputslocks, validates the output multiset (recipient + change + platform fee), recomputes the fee, and derives whether the vault threshold is met before calling the service-roleset_vault_proposal_psbt(...)RPC. Threshold-met PSBTs additionally finalise end-to-end in the Edge layer to confirm the partial signature set is internally consistent. - The
btc-broadcastEdge Function:- validates that
expectedTxidis canonical hex and matchesTransaction.fromHex(rawTxHex).getId(), - re-finalises the stored
psbt_base64and requires the produced hex and txid to match the supplied payload byte-for-byte, - validates and matches an
alreadyBroadcastedBy.txidclaim against the same canonical txid before any DB write, - rate-limits server-side broadcasts via
consume_btc_broadcast_quota, - records broadcast metadata only through the service-role
mark_vault_proposal_broadcasted(...)RPC, which re-checks vault ownership, txid format, and lifecycle status independently of the Edge layer.
- validates that
- Hardware-wallet logging:
- sensitive object fields (manifest, response, payload, raw, txid,
address, descriptor, xpub*, policy, hmac, etc.) are reduced to a
{ redacted: true }summary that exposes only stable enum-like fields (code,phase,status,transportType,transportVersion,type,success), - numbers, booleans, and bigints are kept only for an explicit
safe-context key allowlist (
pathComponentCount,inputIndex,outputIndex,psbtLengthChars, etc.), - the per-cosigner detail block (fingerprints, derivation paths, xpub
previews) is moved behind
log.unsafeDiagnostic(...)which is gated by the__ASYLIA_HW_TREZOR_UNSAFE_DIAGNOSTICS__build flag. Thetsup.config.tsbuild sets this flag tofalsewhenNODE_ENV === 'production'orVERCEL_ENV === 'production', so production bundles compile the diagnostic out entirely.
- sensitive object fields (manifest, response, payload, raw, txid,
address, descriptor, xpub*, policy, hmac, etc.) are reduced to a
- The Trezor signing post-flight verifier remains in place: every fresh signature is ECDSA-verified against the requested cosigner's pubkey, with a full sweep of the input's BIP-32 derivation block on mismatch and a hard refusal when no cosigner pubkey verifies the signature.
requireBearerSecretandrequireBearerOrHeaderSecretcompare auth values with a constant-time byte loop instead of===. The loop iterates overexpectedBytes.length, folds the length difference into the runningdifferenceaccumulator, and uses?? 0for any trailing positions inactual, so the elapsed time is bounded by the configured secret length and does not leak the supplied input length.- The wallet CSP
connect-srcno longer includes the broadhttps://*.asylia.iosource. The remaining list is enumerated providers (Supabase, mempool.space, blockstream, mempool.emzy.de, mempool.bisq.services, mempool.bitcoin-21.org, blockchain.info, BlockCypher, Coinbase, CoinGecko, Kraken, Better Stack, Trezor Connect, local Trezor Bridge ports). Thescript-srcremains'self'only — no'unsafe-inline', no'unsafe-eval'. - The
_headersfile used by the wallet build is kept in sync withdeploy/vercel/wallet.json; theverify:production-configgate fails the build if the two diverge, and the post-deploy smoke spec re-verifies them against the deployed origin. - Coin-selection defaults are corrected from a P2WPKH-shaped 64/31
vbyte pair to the actual P2WSH-multisig 85/43 footprint, and
SEND_FIXED_VBYTESin the spend planner is aligned to 85. The dust-fold and no-change fallback branches both round fees upward viaMath.ceil, so the fee figure presented to the operator is always at or above the network minimum the resulting transaction will require. extractPsbtInputsin@asylia/btc-corenow throws on a malformed outpoint instead of silently skipping, so a corrupt PSBT cannot reach later layers with implicit input drops.proposal-psbtandbtc-broadcastreject requests withContent-Length > 2_000_000before parsing the body, andcsp-reportkeeps its64_000byte cap andMAX_REPORTS_PER_REQUEST = 10policy.- The post-deploy synthetic smoke workflow runs against staging on
every deployment and against production after
release/testpromotes; it asserts HTTP 200, the full set of expected security headers, the CSP directive shape, the status API JSON contract (noservice_role, no PEM private keys, no Bearer tokens, nopostgres://URLs), and ops-health authentication.
Residual Risk
- Hardware-wallet handling outside Asylia's adapter (Trezor Suite,
Trezor Connect popup, the Trezor Bridge processes on
127.0.0.1) is not under Asylia's control. The CSP and Permissions-Policy retain only the necessary Trezor origins and theusb=(self "https://connect.trezor.io")allowance. - The
set_vault_proposal_psbtandmark_vault_proposal_broadcastedRPCs bypass the lifecycle and PSBT-immutability triggers when called byservice_role. This is by design and is the intended trust boundary; a service-role key compromise remains catastrophic regardless of these RPCs and is mitigated by the broader Supabase secret-handling posture rather than in this audit's scope. - The
V1_VaultProposalsUPDATE policy is row-scoped rather than column-scoped (Info-3 above). No funds-safety impact today; a future migration could tighten this to a column-restricted grant for extra defence-in-depth. - Public chain-data providers can rate-limit in correlated ways. The
btc-broadcastpaid Blockstream fallback is gated byconsume_btc_broadcast_quota, but availability of any one provider is not guaranteed; the wallet UI surfaces upstream errors and offers retry.
Public Publication Notes
This report is public-safe. It contains release-control, RLS, Edge Function, CSP, hardware-wallet adapter, and coin-selection details only. It does not disclose secrets, private user data, descriptors from real users, xpub sets, PSBT base64 from real users, UTXO arrays, OTP mailbox credentials, the paid Blockstream client credentials, or the operational ops-health bearer token.
security-audit-2026-05-04 · May 4, 2026
Wallet spend, proposal, and hardware-wallet hardening
Asylia hardened the wallet spend pipeline end to end before promoting release/test to main: server-validated PSBT updates, broadcast rebinding to the stored proposal PSBT, redacted hardware-wallet diagnostics, constant-time shared-secret comparison, tighter wallet CSP, and P2WSH-aligned coin-selection fee math.
- Target
- main
- Commit range
- main...release/test
- Models
- Gemini 3.1 Pro
- Findings
- C0 / H0 / M0 / L0 / I2
Scope
- Supabase migrations: wallet spend locks, proposal scope hardening, server-validated PSBT updates, direct-insert revoke
- Supabase Edge Functions: proposal-psbt, btc-broadcast, csp-report, ops-health, ops-monitoring-synthetic
- Shared Edge auth: constant-time bearer secret comparison
- Wallet SPA services: sessions IP masking, proposals service-side validation, logger redaction, spendPlanner P2WSH fee math
- Bitcoin core: PSBT outpoint parsing strictness and P2WSH-multisig coin selection vbytes
- Hardware-wallet @asylia/hw-trezor: log redaction with safe-key allowlist and build-flag-gated unsafe-diagnostic path
- Wallet Content Security Policy and Permissions-Policy on Vercel and the SPA _headers file
- CI release controls: post-deploy synthetic smoke workflow and wallet production gate guards
- Audit tooling: enforce model slug in audit file names
Read the public report on this page
Release Security Audit: Wallet Spend, Proposal, And Hardware-Wallet Hardening
Audit ID: security-audit-2026-05-04
Date: 2026-05-04
Target: main
Source branch: release/test
Commit range: main...release/test
Status: passed with notes
Summary
This audit covers the release/test candidate prepared for promotion to
main. The change set hardens the entire wallet spend pipeline end to end:
- proposal creation moves through a single
SECURITY DEFINERRPC and direct PostgREST inserts onV1_VaultProposalsare revoked, - proposal PSBT updates and lifecycle advancement to
ready_to_broadcast/broadcastedare gated by service-role-only RPCs guarded by transaction-local config flags, with full content validation in the Edge layer, - the
btc-broadcastEdge Function re-finalises the stored proposal PSBT and requires the supplied raw transaction hex and txid to match it byte-for-byte before any database state advances, - hardware-wallet (Trezor) logging is rebuilt around an explicit safe-key
allowlist, every potentially sensitive diagnostic context is moved behind a
build-flag-gated
unsafeDiagnosticpath that compiles to a no-op in production, - shared-secret comparisons in Edge auth helpers are migrated to constant-time byte equality,
- the wallet CSP is tightened (the broad
https://*.asylia.ioconnect-src source is removed), - coin-selection vbyte parameters and
spendPlannerdefaults are aligned with the actual native-SegWit P2WSH multisig footprint so fee math no longer underestimates the on-chain transaction size, - IPv6 session IP masking handles compressed
::addresses correctly, - a post-deploy synthetic smoke workflow is added that verifies release headers, CSP, status JSON, ops-health authentication, and protected wallet routes against the live deployment, and
- audit tooling enforces model slug in audit file names.
This release does not change BIP-48 derivation roots, the descriptor format
(wsh(sortedmulti(...))), the BIP-67 ordering rules, the network constant
(mainnet only), or the threat model around seed phrases, hardware wallet
secrets, service-role keys, or private operational tokens.
Release Target And Commit Range
- Target branch:
main - Source branch:
release/test - Commit range:
main...release/test - Notable commits reviewed:
180f2fca9fix(supabase): harden proposal validation and insert controls09f7f0accfix(hw-trezor): keep signing diagnostics redacted by default8e948360ffix(btc-core): align P2WSH fee estimates with wallet spends62d057806fix(wallet): harden session IP maskingf55e4b57echore(deploy): tighten wallet CSP on Vercel06e176fbbtest(logger): add tests to ensure sensitive fingerprint values are redacted73668b7e0test(supabase): cover edge function handlers6f21c193bci(wallet): add post-deploy smoke workflow40b3b31b6ci(wallet): require UI coverage in production gates
Scope
- Supabase migrations:
20260429202000_wallet_spend_locks.sql20260430130000_vault_proposals_scope_hardening.sql20260502195000_btc_broadcast_stored_psbt_binding.sql20260502201000_proposal_broadcast_rpc_cache_and_trigger.sql20260503083000_server_validated_proposal_psbt_updates.sql20260503174813_restrict_direct_vault_proposal_inserts.sql
- Supabase Edge Functions:
proposal-psbt,btc-broadcast,csp-report,ops-health,ops-monitoring-synthetic,btc-network-fees,btc-fiat-rates,btc-chain-fallback,_shared/auth.ts. - Wallet SPA:
apps/wallet/src/services/sessions.tsapps/wallet/src/services/proposals.tsapps/wallet/src/services/spendPlanner.tsapps/wallet/src/services/logger.ts
- Bitcoin core:
packages/btc-core/src/psbt/build.tspackages/btc-core/src/psbt/coin-select.ts
- Hardware wallet adapter:
packages/hw-trezor/src/log.tspackages/hw-trezor/src/sign.tspackages/hw-trezor/src/init.tspackages/hw-trezor/tsup.config.tsandsrc/build-flags.d.ts
- Deploy / CSP:
apps/wallet/public/_headersdeploy/vercel/wallet.json
- CI / release controls:
.github/workflows/post-deploy-smoke.yml.github/workflows/wallet-production-gates.ymlapps/wallet/e2e/post-deploy-smoke.spec.tsapps/wallet/playwright.post-deploy.config.tstools/verify-supabase-security.mjstools/verify-production-config.mjstools/verify-release-audit.mjs
Threat Model
The audit considered:
- direct PostgREST writes to
V1_VaultProposalsthat forge lifecycle status, broadcast metadata, or PSBT payloads, - a malicious or compromised SPA submitting a PSBT whose inputs/outputs/fee do not match the stored proposal summary or the active input locks,
- a SPA-supplied
alreadyBroadcastedByreport that lies about the network txid in order to bind the wrong txid to a real proposal, - timing side-channels on shared-secret bearer auth (
OPS_HEALTH_TOKENand the public ops-monitoring header), - hardware-wallet device interaction leaking xpubs, fingerprints, descriptors, or full PSBTs to the browser console or operational logs,
- a Trezor signing path that produces a partial signature that does not verify against any cosigner pubkey on the input,
- coin-selection fee math that underestimates the on-chain footprint and produces a transaction below the network minimum relay fee,
- session listing leaking full IP addresses to the SPA UI,
- CSP weakening that allows arbitrary
*.asylia.iofirst-party connect targets, - broken release-audit gating that allows an unreviewed change to reach
main.
Model Review
| Provider | Family | Model/version | Role | Status |
|---|---|---|---|---|
| Gemini | Gemini 3.1 Pro (google-geminy-3-1-pro) | Security-first release audit (code review, RLS review, CSP review, Edge Function review, hardware-wallet adapter review, fee/coin-selection review, CI/release controls review) | Completed |
The review combined static reading of the diffs (git diff main...release/test),
direct execution of the static gates verify:supabase-security,
verify:production-config, and verify:wallet-production-gates, and inspection
of the Supabase migration semantics including transaction-local config flags
(asylia.allow_vault_proposal_insert, asylia.allow_proposal_psbt_update,
asylia.allow_proposal_ready_update, asylia.allow_broadcast_proposal_update).
Findings
| Severity | Count | Notes |
|---|---|---|
| Critical | 0 | No funds-moving, key-handling, RLS, descriptor, PSBT-builder, or transaction-broadcast invariant is weakened by this change set. |
| High | 0 | No production secret, RLS boundary, or hardware-wallet trust path is exposed; service-role privilege remains scoped to narrow SECURITY DEFINER functions. |
| Medium | 0 | No mandatory production gate is removed; new lifecycle and content-binding checks add belt-and-braces over RLS. |
| Low | 0 | Coin-selection vbyte parameters now match Asylia's native-SegWit P2WSH multisig footprint; fee estimates round upward rather than underpaying network minimum. |
| Info | 2 | See below. |
Info-1: Service-role broadcast and PSBT-update RPCs rely on transaction-local config flags
- Affected surface:
mark_vault_proposal_broadcasted(...),set_vault_proposal_psbt(...),create_vault_spend_proposal(...). - Observation: the
v1_vault_proposals_enforce_lifecycleandv1_vault_proposals_enforce_insert_pathtriggers honourcurrent_setting('asylia.allow_*_update', true)flags set withset_config(..., true)(transaction-local). Settingis_local = truekeeps the bypass scoped to the active transaction, so a leaked flag cannot persist across sessions or pollute connection-pooled clients. The bypass is still a service-role-only path; this is consistent with Asylia's documented threat model whereservice_roleis treated as a trusted boundary and any leak of the service-role key is catastrophic regardless. - Impact: None on its own. Recorded so a future migration that introduces
another lifecycle-altering RPC keeps the same
is_local = truediscipline and the samerevoke all on function ... from public, anon, authenticated; grant execute ... to service_rolepattern. - Remediation: No action required. The pattern is documented, the static
verify-supabase-securitygate enforces the revoke convention on everySECURITY DEFINERfunction added after the baseline timestamp.
Info-2: Wallet logger covers the dominant sensitive surfaces but is not exhaustive
- Affected surface:
apps/wallet/src/services/logger.ts. - Observation: the redaction key pattern covers
psbt|xpub|zpub|ypub|descriptor|previousTxHex|rawTxHex|policyHmac|witnessScript|scriptPubKey|privateKey|seed|mnemonic, the address/fingerprint/utxo families are shortened, andUint8Array,ArrayBuffer, and unknown shapes are reduced to redaction placeholders. Adjacent identifiers likeredeemScript,derivationPath,nodeXpub, orsignatureare not in the explicit pattern. In practice, the wallet code paths that handle those values either route them through the listed keys (PSBT/xpub/witnessScript) or through thehw-trezoradapter which has its own strictersummariseSensitiveObjectpath. - Impact: None observed — manual review confirmed the active call sites
do not log raw
redeemScript,derivationPath, or unredactedsignaturevalues. Recorded as a hygiene note so future call sites stay consistent. - Remediation: consider extending
SENSITIVE_KEY_PATTERNin the wallet logger to additionally coverredeemScript,derivationPath,signature, andnodeXpubfor defence-in-depth. This is an opportunistic improvement, not a release blocker.
Fixes And Accepted Risk
- Direct browser inserts on
V1_VaultProposalsare revoked; creation runs exclusively throughcreate_vault_spend_proposal()with atomic active input locks and parent-vault ownership re-check. - Browser clients can no longer set
psbt_base64,ready_to_broadcast, orbroadcasteddirectly. Theproposal-psbtEdge Function re-parses every PSBT, matches inputs againstV1_VaultProposalInputslocks, validates the output multiset (recipient + change + platform fee), recomputes the fee, and derives whether the vault threshold is met before calling the service-roleset_vault_proposal_psbt(...)RPC. Threshold-met PSBTs additionally finalise end-to-end in the Edge layer to confirm the partial signature set is internally consistent. - The
btc-broadcastEdge Function:- validates that
expectedTxidis canonical hex and matchesTransaction.fromHex(rawTxHex).getId(), - re-finalises the stored
psbt_base64and requires the produced hex and txid to match the supplied payload byte-for-byte, - validates and matches an
alreadyBroadcastedBy.txidclaim against the same canonical txid, - rate-limits server-side broadcasts via
consume_btc_broadcast_quota, - records broadcast metadata only through the service-role
mark_vault_proposal_broadcasted(...)RPC, which re-checks vault ownership, txid format, and lifecycle status independently of the Edge layer.
- validates that
- Hardware-wallet logging:
- sensitive object fields (manifest, response, payload, raw, txid, address,
descriptor, xpub*, policy, hmac, etc.) are reduced to a
{ redacted: true }summary that exposes only stable enum-like fields (code,phase,status,transportType,transportVersion,type,success), - numbers/booleans/bigints are kept only for an explicit safe-context key
allowlist (
pathComponentCount,inputIndex,outputIndex,psbtLengthChars, etc.), - the per-cosigner detail block (fingerprints, derivation paths, xpub
previews) is moved behind
log.unsafeDiagnostic(...)which is gated by the__ASYLIA_HW_TREZOR_UNSAFE_DIAGNOSTICS__build flag. Thetsup.config.tsbuild sets this flag tofalsewhenNODE_ENV === 'production'orVERCEL_ENV === 'production', so production bundles compile the diagnostic out entirely.
- sensitive object fields (manifest, response, payload, raw, txid, address,
descriptor, xpub*, policy, hmac, etc.) are reduced to a
- The Trezor signing post-flight verifier remains in place: every fresh signature is ECDSA-verified against the requested cosigner's pubkey, with a full sweep of the input's BIP-32 derivation block on mismatch and a hard refusal when no cosigner pubkey verifies the signature.
requireBearerSecretandrequireBearerOrHeaderSecretnow compare auth values with a constant-time byte loop instead of===, removing a subtle timing side channel on the OTP-bypass and ops-monitoring shared secrets.- The wallet CSP
connect-srcno longer includes the broadhttps://*.asylia.iosource. The remaining list is enumerated providers (Supabase, mempool.space, blockstream, mempool.emzy.de, mempool.bisq.services, mempool.bitcoin-21.org, blockchain.info, BlockCypher, Coinbase, CoinGecko, Kraken, Better Stack, Trezor Connect, local Trezor Bridge ports). Thescript-srcremains'self'only — no'unsafe-inline', no'unsafe-eval'. - The
_headersfile used by the wallet build is kept in sync withdeploy/vercel/wallet.json; theverify:production-configgate fails the build if the two diverge, and the post-deploy smoke spec re-verifies them against the deployed origin. - Coin-selection defaults are corrected from a P2WPKH-shaped 64/31 vbyte pair
to the actual P2WSH-multisig 85/43 footprint, and
SEND_FIXED_VBYTESin the spend planner is aligned to 85. The dust-fold and no-change fallback branches both round fees upward viaMath.ceil, so the fee figure presented to the operator is always at or above the network minimum the resulting transaction will require. extractPsbtInputsin@asylia/btc-corenow throws on a malformed outpoint instead of silently skipping, so a corrupt PSBT cannot reach later layers with implicit input drops.proposal-psbtandbtc-broadcastreject requests withContent-Length > 2_000_000before parsing the body, andcsp-reportkeeps its64_000byte cap andMAX_REPORTS_PER_REQUEST = 10policy.- The post-deploy synthetic smoke workflow runs against staging on every
deployment and against production after
release/testpromotes; it asserts HTTP 200, the full set of expected security headers, the CSP directive shape, the status API JSON contract (noservice_role, no PEM private keys, no Bearer tokens, nopostgres://URLs), and ops-health authentication.
Residual Risk
- Hardware-wallet handling outside Asylia's adapter (Trezor Suite, Trezor
Connect popup, the Trezor Bridge processes on
127.0.0.1) is not under Asylia's control. The CSP and Permissions-Policy retain only the necessary Trezor origins and theusb=(self "https://connect.trezor.io")allowance. - The
set_vault_proposal_psbtandmark_vault_proposal_broadcastedRPCs bypass the lifecycle and PSBT-immutability triggers when called byservice_role. This is by design and is the intended trust boundary; a service-role key compromise remains catastrophic regardless of these RPCs and is mitigated by the broader Supabase secret-handling posture rather than in this audit's scope. - Public chain-data providers can rate-limit in correlated ways. The
btc-broadcastpaid Blockstream fallback is gated byconsume_btc_broadcast_quota, but availability of any one provider is not guaranteed; the wallet UI surfaces upstream errors and offers retry.
Public Publication Notes
This report is public-safe. It contains release-control, RLS, Edge Function, CSP, hardware-wallet adapter, and coin-selection details only. It does not disclose secrets, private user data, descriptors from real users, xpub sets, PSBT base64 from real users, UTXO arrays, OTP mailbox credentials, the paid Blockstream client credentials, or the operational ops-health bearer token.
ci-gates-stabilization-2026-05-03 · May 3, 2026
CI gates stabilization
Asylia stabilized the wallet production CI gates after the release/test promotion reached main.
- Target
- main
- Commit range
- main...release/test
- Models
- GPT-5.5
- Findings
- C0 / H0 / M0 / L0 / I1
Scope
- Wallet production GitHub Actions flow for push and pull-request events
- Release-audit target detection for branch push events
- Authenticated OTP E2E scheduling across pull-request, manual, and push runs
- Static wallet production workflow guard coverage for the OTP push-skip invariant
Read the public report on this page
This report covers release operations and CI controls only. It does not include wallet signing, descriptor, PSBT, hardware-wallet, chain-data, or Supabase RLS changes.
release-test-security-audit-2026-05-02 · May 2, 2026
Release test security audit
Asylia reviewed the release/test promotion candidate with a wider wallet, Supabase, package, release, and publication audit. Follow-up hardening centralises BIP-48 enforcement, removes hardware-wallet vendor payloads from console logs, and records broadcast state server-side.
- Target
- main
- Commit range
- main...release/test
- Models
- GPT-5.5, Cursor Composer (exact internal model/version not exposed)
- Findings
- C0 / H2 / M8 / L10 / I9
Scope
- Current release/test diff against main
- Bitcoin descriptor, PSBT, hardware-wallet, and chain-data packages
- Wallet auth, vault, proposal, signing, broadcast, logging, and telemetry boundaries
- Supabase migrations, RLS policies, Edge Functions, CORS, and operational logging helpers
- GitHub Actions, release audit tooling, production config verification, Vercel build paths, and public OSS export controls
Read the public report on this page
This report covers a documentation-only release/test promotion candidate plus
a wider security review of the current wallet posture. The follow-up hardening
closes the tracked high-severity derivation and logging gaps before promotion.
release-checks-vercel-hotfix-2026-05-02 · May 2, 2026
Release checks and Vercel build hotfix
Asylia stabilized the production release checks and Vercel deployment path after the release flow reached main.
- Target
- main
- Commit range
- main...release/test
- Models
- GPT-5.5
- Findings
- C0 / H0 / M0 / L0 / I1
Scope
- Public bitcoin-toolkit sync token permissions and workflow preservation
- Wallet production gate handling for live authenticated browser flows
- Vercel workspace dependency build ordering
- Vercel build helper scripts
Read the public report on this page
This report covers release operations and deployment controls only. It does not include wallet signing, descriptor, PSBT, hardware-wallet, chain-data, or Supabase RLS changes.
release-audit-flow-2026-05-02 · May 2, 2026
Release, deploy, and audit flow
Asylia introduced a production release flow that requires green CI and a public-safe release security audit record before code reaches main.
- Target
- main
- Commit range
- main...chore/release-audit-flow
- Models
- GPT-5.5
- Findings
- C0 / H0 / M0 / L0 / I1
Scope
- GitHub Actions production gates
- release/test branch mapping
- release audit manifest schema
- marketing security audit publication path
Read the public report on this page
This report covers release process controls only. It does not include wallet signing, descriptor, PSBT, hardware-wallet, chain-data, or Supabase RLS changes.
03 · Method
Three independent model passes.
The goal is adversarial coverage, not a single model verdict.
Each review round gives the same bounded scope to the current top model from GPT, Claude, and Gemini. Findings are compared for overlap and disagreement. Repeated findings become engineering work; single-model findings are investigated, reproduced, or dismissed with notes. The process is strongest when the models disagree, because disagreement exposes assumptions that a normal checklist can miss.
- 01
Scope freeze
Define the exact package, route, adapter, or transaction path under review.
- 02
Model review
Run GPT, Claude, and Gemini independently with the same threat model and code context.
- 03
Triage
Group findings by severity, reproducibility, affected funds surface, and user impact.
- 04
Remediation
Patch confirmed issues, add tests where the failure mode is stable, and record residual risk.
04 · Coverage
The current AI review bench.
Model families are listed by role, not treated as certification authorities.
| Model family | Review role | Current focus | Report status | Cadence |
|---|---|---|---|---|
| GPT | Systems reviewer | Cross-file invariants, data-flow assumptions, and missing negative tests. | Public reports in history | Every audit round |
| Claude | Adversarial reviewer | Threat-model gaps, ambiguous wallet policy handling, and failure-mode reasoning. | Public reports in history | Every audit round |
| Gemini | Breadth reviewer | Large-context comparison across adapters, docs, changelog, and product claims. | Public reports in history | Every audit round |
GPT
Systems reviewer
Cross-file invariants, data-flow assumptions, and missing negative tests.
Public reports in history
Claude
Adversarial reviewer
Threat-model gaps, ambiguous wallet policy handling, and failure-mode reasoning.
Public reports in history
Gemini
Breadth reviewer
Large-context comparison across adapters, docs, changelog, and product claims.
Public reports in history
05 · Scope
The first audit boundary is Bitcoin-critical.
Product chrome can wait. Funds-facing primitives cannot.
The intended first external audit scope is the code that can affect wallet correctness, signing intent, recovery, or broadcast safety.
- btc-core: descriptor parsing, address derivation, PSBT assembly, finalization, and signature checks.
- blockchain-data-btc: chain reads, UTXO interpretation, fee inputs, and broadcast boundaries.
- hw-trezor and hw-ledger: public-root export, policy registration, device signing, and returned signature handling.
- shared-types: domain contracts that keep wallet policy, signer metadata, and transaction state consistent across apps.
06 · Limits
AI review is not a substitute for human accountability.
It is useful precisely because its limits are explicit.
AI-assisted review can widen coverage quickly, but it cannot replace a qualified human audit, live exploit validation, vendor firmware review, or formal assurance. Findings are treated as leads until they are reproduced against the code, covered by tests, or closed with a concrete rationale.
- No AI model can certify that funds are safe.
- No model output is accepted without engineering review.
- No unresolved critical finding is hidden behind marketing language.
07 · Publication
Reports are published when they are public-safe.
Security claims should be inspectable by readers, not implied by tone.
AI-assisted release reports are published here in reverse chronological order when they can be shared without exposing secrets or operational material. When an external human audit is commissioned and completed, this page will link the report, scope, commit range, confirmed findings, remediation work, and any accepted residual risk.
Want to review the surface yourself?
Start with the narrow policy and the MIT-licensed packages. The smaller the wallet surface stays, the easier it is for outside reviewers to challenge it.