GREXIE VAULT / DOCUMENTATION

Architecture and custody

Vault is a public MIT project with one Go binary and an embedded PWA. There are three roles: the hosted account/ciphertext service, a user-controlled signing device, and a requesting CLI. The same binary can run each role; a public deployment must not run users' signers.

Encryption and passkeys

The browser generates a random vault key plus separate owner approval and encryption keys. WebAuthn PRF output, bound to the account and credential, wraps this root. The root encrypts identity records before upload. MongoDB receives a second AES-256-GCM layer using a deployment-local 32-byte file. Grexie's storage key cannot open the browser encryption layer. Names, private keys, owner material and pinned devices are inside the browser-encrypted vault. Paired devices receive a signed public identity catalog encrypted to each device separately.

MongoDB application documents use authenticated scope/id/version/expiry metadata, CAS updates and TTL deletion. Opaque HMAC index values, record versions and expiry times remain visible. Database operation logs, backups and transport are an operator responsibility. Secrets live in protected local files or deployment secret mounts and are absent from source/images.

A secure HttpOnly SameSite cookie identifies an encrypted 30-day server session. A cookie-authenticated endpoint returns a random session wrapping secret; the browser uses it to encrypt its root into localStorage. The root and local ciphertext are never uploaded by that endpoint. Logout invalidates the server session/wrapping secret, removes the local cache, clears sensitive forms and pending drafts, terminates the browser worker and invalidates stale operations. Each approval still requires a fresh purpose-bound, single-use WebAuthn verification ticket.

Delivered browser JavaScript is trusted. Malicious same-origin code, a compromised browser, OS account, or root on a signing device can defeat this design. It does not claim protection from a malicious update served by the hosting origin. Self-hosting and source inspection are part of the trust model.

Pairing and approval

A device generates independent P-256 signing/encryption keys locally. Its public descriptor includes a role: requesting client or signing agent. A one-time out-of-band pairing code carries a secret; the owner's browser verifies it and MACs an encrypted pairing reply. The device pins the owner's public approval/encryption keys. The browser pins device public keys and role. The pairing UI identifies signing agents as machines trusted to hold approved private keys.

Requests contain identity name/type, reason, operation, session and duration and are signed by the paired client. Operation/type validation runs in both server and browser. Crypto requests must target a pinned signing agent; the requester cannot supply its receiver. The signing daemon creates a fresh ephemeral receiver secret, signs the receiver, and holds that secret only in memory.

The browser reviews signed request bytes and encrypts an owner-signed approval to that receiver. A separate owner-signed authorization binds the request hash, receiver hash, agent public key and deadline for the requesting client. Private key material travels only as ciphertext from the browser to the signing device. The hosted service cannot substitute receiver or approval keys to open it.

Agent RPC uses a requester-signed payload encrypted to the ephemeral receiver. Replies are agent-signed and encrypted to a fresh caller reply key. Signatures bind nonce, request, exact payload and deadline. The daemon checks the cloud state before each operation, rejects replay, and drops the in-memory lease on expiry, device/session revocation or lost cloud contact. Both participants must still be active. The public service has no signing API that accepts plaintext private keys.

SSH and age

Only the requesting machine creates a 0600 Unix SSH-agent socket in an owner-only directory. The signing daemon creates no SSH socket. Requests cross HTTPS as encrypted authenticated operations; SSH-agent list/sign are allowed and add/remove/lock extensions are refused. RSA uses SHA-256/512, not SHA-1. Requester processes sharing the same OS privileges can use that request's socket; a Unix path is not per-process isolation.

SSH wrappers create a temporary config with the approved public key and IdentitiesOnly yes. They remove additive private identity fallbacks and keychain/agent-loading/forwarding/control settings from the copied configuration, while keeping original files unchanged. Remote signing failure therefore does not load a local private key. Revocation stops new signatures but does not terminate an already established SSH connection.

Age encryption is local and public-key-only. Decryption sends only a bounded age header, not the document, to the signing device. The file key is returned encrypted to the requester. One-shot approval is bound to that exact header and cannot unwrap another document. A client that already has plaintext or a file key can retain it; revocation is not erasure of copies.

Ethereum and Bitcoin

Signing happens on the designated device and is bound to the exact reviewed transaction/PSBT bytes. The CLI receives a signature or signed transaction, not the private key. Native ETH, chain, sender, nonce, fees, method calls and warnings come from local decoders. JSON duplicate/case-variant transaction fields are rejected so browser and Go cannot review different calldata. Verified ABI fetching occurs directly in the browser; selector names are not proof of code behavior or a simulation result.

Only EIP-155 protected legacy, EIP-2930 and EIP-1559 transactions are supported. Bitcoin supports ordinary P2PKH, P2WPKH and key-path P2TR with full output commitment. The CLI returns base64 PSBT. Script-path policies and unconstrained SIGHASH modes are refused. UTXO availability/confirmations are not verified by a node.

Foundry uses a capability-protected, loopback-only JSON-RPC adapter. Chain/address and signed transaction contents are verified. Only explicit caller-side --broadcast submits through the chosen RPC; hosted service and signer never broadcast.

Threshold CMP/FROST protocol primitives are included with adversarial tests. Shared-owner application enrollment/recovery/signing remains unreleased. The pinned upstream release fixes the OT advisory; the precise stale scanner exception is documented in the security review. No independent cryptographic audit has been performed. Strict n-of-n has no death/loss override: every owner's share and required authentication material need an independently protected succession plan.

Credentials, autofill and imports

Provider wrappers intentionally release a credential to one child process and preserve args/streams/status. This is a credential-release approval, not a sandbox or provider-side capability reduction. The child, descendants or same-privilege processes can copy it. API passthrough similarly trusts the user-controlled device and restricts destination/method/path in the local profile. Docker's ephemeral helper keeps the registry password in memory; temporary files contain only helper metadata.

Browser import reads one explicitly approved origin/account using normal OS controls or an official CSV. Chrome's authorized decryption key may be cached in service memory until restart; macOS can still request more authorization. No access-control or keychain-unlock bypass exists. Safari's modern Passwords database may require an official export.

Autofill binds an origin and document token, checks visible field roles again, and returns only counts. The selected website receives the values. It does not submit a form, although site code may react to input. Card number/name/expiry may be encrypted in cloud; CVV stays device-local and is excluded from export. A merchant/amount label is not an issuer-enforced payment limit.

Backups and operational limits

Password backups use fixed bounded Argon2id parameters (64 MiB, three passes) and AES-256-GCM. Decryption, validation and conflict preview happen locally. Wrong passwords/corruption fail before merging. Exports omit cookies, live leases, device tokens and local CVVs. Public account or operator assistance cannot reconstruct lost user encryption material.

Run one cloud replica with per-device rate limits, serialized active-request admission, bounded push workers and generic notification text. HTTP/TLS ingress, host security, MongoDB authentication, backup retention and monitoring remain operator responsibilities. Read the review's findings and test evidence; passing tests are not a professional security audit.

Web3 wallet and Hyperliquid

The Chrome MV3 extension is an additional requesting interface, not another custodian. An isolated content script relays provider requests to its worker. Chrome authenticates the caller to a fixed native-messaging host; the worker obtains the top-level origin from Chrome's sender metadata. The Go host reads the paired client's owner-signed public catalogue, persists local chain metadata and sends encrypted requests through the existing broker to the pinned signing device. It opens no localhost port.

Website connection and chain-control approvals use wallet-connect. Their owner-signed results carry an origin/device-bound identity permission, chain set and timestamps; the public catalogue carries the same grant. Local state contains network preferences, last-use timestamps and revocation tombstones, not keys. PWA revocation republishes the catalogue and revokes pending requests for the affected origin. Chrome polls the signed state and emits account changes.

Each wallet-sign request commits the origin, identity ID/name/address, method, chain, exact normalized payload, submit flag and transaction RPC URL. The browser worker and Go signer independently validate this binding. The agent releases one signature and clears that one-shot approval. Message signatures use an exact EIP-191 or EIP-712 digest. Transactions use the existing Ethereum normalizer and signed-byte verifier. Only the local bridge may submit an eth_sendTransaction, after exact sign-and-submit approval and another grant/chain check. The cloud and signing daemon never broadcast.

The hyperliquid CLI shares this remote-signing path but uses its own typed action schema and network binding. It returns a verified signed exchange envelope. Public balance, position and order queries use only the official info endpoint and need no approval. Hyperliquid browser terms use the generic EIP-712 wallet path; creating an external trading API key remains a distinct authority grant.

See Chrome wallet and Hyperliquid for protocol compatibility, installation, failure behavior and tests.

Read on GitHub โ†— ยท AI agent instructions โ†—