Skip to content

fix: enforce and verify canonical vault permissions - #134

Merged
mellowcroc merged 9 commits into
mainfrom
fix/f-2026-19297-canonical-permissions
Sep 15, 2026
Merged

mellowcroc merged 9 commits into
mainfrom
fix/f-2026-19297-canonical-permissions

Conversation

@mellowcroc

@mellowcroc mellowcroc commented Sep 11, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes F-2026-19297 by preventing the supported deployment flow from retaining hidden signature authority and refusing MinaGuard lookalikes whose on-chain account permissions differ from the canonical policy, even when they carry the official verification key.

  • define the canonical o1js permission vector alongside a browser-safe serialized representation, with a regression test enforcing equivalence
  • let the signed deployment update install a vector identical to the canonical policy except that setPermissions temporarily requires a proof
  • have proof-authorized setup() and reserveForParent() overwrite and permanently seal the complete canonical vector in the same atomic transaction
  • assert that successful root and child creation serialize separate signed deployment and proved initialization updates
  • remove the legacy split deploy/setup worker APIs so the supported UI cannot broadcast the temporary deployment alone
  • validate every stored permission field, including access and the setVerificationKey transaction-version guard
  • fail closed when the expected verification-key trust anchor is absent
  • require live permission verification during full discovery, manual subscription, and deferred auto-subscription
  • persist permissionsVerified, hide unverified vaults from every backend read/action route, and ignore unverified child state during proposal-status derivation
  • have the browser independently query Mina and recheck permissions at final action boundaries
  • authenticate proposed SubVault accounts before lifecycle approval or execution, including the dedicated SubVault creation wizard
  • require a matching explicit verification-key trust anchor in every backend/frontend build: the pinned MinaGuard VK in production, Trail, and preview, and the o1js dummy VK in proofless Lightnet E2E
  • document in MinaGuard.deploy() and the audit guides that VK equality alone must never be used to recognize or fund a vault
  • regenerate and pin the testnet and mainnet verification-key hashes for the revised circuit

Security boundary

The supported root and child creation paths now include two account updates atomically: the vault-signed deployment update leaves setPermissions open to proof, and the MinaGuard-proof-authorized initialization update writes GUARD_PERMISSIONS, including setPermissions: impossible(). A creator weakening send is overwritten; a creator closing setPermissions early makes the entire transaction fail.

The on-chain and client changes complement rather than replace the mandatory detection control. A creator can bypass the supported flow and deploy a lookalike directly, so the backend and online UI still reject every stored permission vector other than GUARD_PERMISSIONS.

Verification-key equality still does not authenticate deployment provenance. A proof-authorized factory and registry would remain the stronger L1 design for cryptographically authenticating canonical deployment provenance.

UI screenshots

The image assets are isolated from this PR on the pr-134-ui-screenshots branch. The embeds below use its immutable commit.

Unsafe Vault blocks transaction actions

Unsafe Vault warning with all transaction actions disabled

Unsafe proposed SubVault blocks approval and execution

Unsafe proposed SubVault permission warning with online actions blocked

Unsafe proposed SubVault blocks offline bundle creation and broadcast

Offline signing tab showing bundle creation and broadcast blocked

Tests

  • contracts: 150 passed, 1 skipped (local host required --timeout 20000; isolated CI retains the repository default)
  • permission-lock regressions cover both RootVault setup() and SubVault reserveForParent():
    • creator-weakened send is overwritten with the canonical vector
    • creator-set setPermissions: impossible() rejects the complete atomic creation
    • serialized call forests contain distinct signed-deploy and proved-initialization updates
    • successful root and child creation store GUARD_PERMISSIONS field by field
  • backend: 157 passed
  • deterministic UI Playwright: 36 passed
  • proofless Lightnet browser/on-chain E2E: 16 passed using PROOF_LEVEL=none, dummy proofs, and the matching dummy VK; it does not test browser circuit compilation
  • real testnet/mainnet circuit compilation and pinned-VK verification remain independently enforced by check-vk-hash
  • offline CLI: 30 passed
  • contracts, backend, and UI production builds pass
  • production, Trail, and preview Compose configurations validate with the pinned network VK; proofless Lightnet E2E validates with its matching dummy VK
  • PostgreSQL and SQLite Prisma schemas are in sync
  • testnet and mainnet VK hashes were independently compiled and pinned

Finding: F-2026-19297

@mellowcroc mellowcroc changed the title fix: reject vaults with non-canonical permissions fix: enforce and verify canonical vault permissions Sep 14, 2026
@mellowcroc
mellowcroc requested a review from graikos September 14, 2026 12:29
@mellowcroc
mellowcroc merged commit 47d93a2 into main Sep 15, 2026
6 checks passed
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.

2 participants