Security

What could hurt you, and what stands in the way.

Three of the six risks below end in nothing standing in the way at all. They are here because a security page that only lists its defences is a page you cannot check.

Security overview

Four statuses, and three of them are no.

Network

devnet only

every figure on this site was read against devnet, and the app is locked to it

Mainnet writes

locked

no mainnet transaction has ever been built by this code, and opening that gate needs more than a green build

Independent audit

none

no firm, no report, no score. There is nothing to link to and this page does not pretend there is

Real Phantom wallet

not completed

every browser run was driven by a throwaway devnet keypair over the debug protocol: the signatures are genuine, the human is not

Served at verx.fun under a certificate for verx.fun that expires 2027-01-15, read 2026-10-17. Being reachable is not the same as being audited, and none of the three no's above changed when it went up.

Key security

The keys never leave the tab, because they are never written down.

Your ElGamal keypair and AES key are derived in the browser from one wallet signature. They live in memory, in one tab, and a reload asks for the signature again.

swept
localStorage, sessionStorage, cookies, indexedDB, caches
found
0 of 3 secrets, in any store
control
the same sweep did find verx.history, so it was looking
requests
no request the page made carried the ElGamal secret or the AE key, across 133 requests and 28,032 bytes of body; the only hosts contacted were the app itself and the devnet rpc

How the keys are derived

The signature is the key

Treat that one message the way you treat a seed phrase.

Signing solana-conf-bal/v1 is what produces your vault keys. Approving it on a site that is not this one hands that site the same keys, and no header here can stop that.

VERX will never ask for a seed phrase, a private key or an export of anything. There is no server to send one to. If a page calling itself VERX asks, it is not this page.

The headers on this very response
directivewhat it stops
connect-src 'self' https://api.devnet.solana.coman injected script posting your keys to a server of its own
script-src 'self' 'wasm-unsafe-eval'a CDN, an analytics tag or a font host running code here
frame-ancestors 'none'this page being framed invisibly and clicked through into signing
object-src 'none'a plugin object being embedded at all
form-action 'none'anything on the page posting a form somewhere else
base-uri 'self'a rewritten base tag pointing every relative url elsewhere

Also set: X-Content-Type-Options nosniff, X-Frame-Options DENY, Referrer-Policy no-referrer, Cross-Origin-Opener-Policy same-origin, Strict-Transport-Security for 180 days, and a Permissions-Policy denying camera, microphone, geolocation, payment and usb. A probe reads them back off the wire rather than out of the source.

Mainnet

The gate is shut, and these are the items.

Mainnet reads are allowed: that is how the compatibility audit was done. A mainnet WRITE is refused in the one place this app broadcasts anything, before a wallet is asked for anything, until every item below is true.

  1. met

    compatibility

    npm run audit-mainnet: Token-2022, the ZK ElGamal Proof program and SPL Record all run on mainnet, and an SDK encoded Deposit decodes there. 20 ok, 0 FAIL, 10 controls, 2026-10-17.

  2. not met

    production mint

    No Token-2022 mint with the confidential transfer extension exists on mainnet for this project. One must be created deliberately, with its authorities decided first: see MAINNET in lib/verx.ts.

  3. not met

    real wallet run

    A person has to drive connect, unlock, configure, shield, apply, send, withdraw and recovery with the real Phantom extension on devnet first. npm run phantom prints the checklist and reads the chain afterwards.

  4. not met

    independent audit

    No independent security review has been done, so no critical finding has been closed, because none has been opened.

  5. not met

    owner approval

    The owner has to set VERX_MAINNET_WRITE_APPROVED to the exact phrase "i-approve-mainnet-writes" in the server environment. Nothing in the repository can set it for them.

The programs a confidential transfer needs do run on mainnet, measured 2026-10-17: Token-2022, the ZK ElGamal Proof program and SPL Record all answered, and an instruction encoded by the SDK decoded there. Mainnet runs 4.3.0 and devnet runs 4.4.0-beta.0, so those matching answers are not a tautology. What does not exist is a mint: none has been created, and creating one is a set of decisions listed in lib/verx.ts.

Transaction safety

What happens when one of them goes wrong.

The first two nodes are what any product draws. The third is the one that was measured by abandoning real flows on purpose, at every boundary they have.

  1. 01

    Proof validation

    Every transaction is simulated against the cluster before your wallet is asked for anything, and each proof is verified by the ZK ElGamal Proof program inside the validator. A proof that does not hold is refused there, not here.

    simulated before signing · verified by the validator

  2. 02

    Confirmation

    A signature is not inclusion. The executor waits for each transaction to confirm, shows the signature the moment there is one, and the activity list marks a row confirmed only after the ledger has been asked about it.

    one approval per transaction · status read from the chain

  3. 03

    Recovery

    Every temporary account carries a closing authority from the moment it exists, and the planner refuses any plan where that is not true. An interrupted flow leaves only accounts your own wallet can close, and Home offers to close them and return the rent.

    0 transactions can strand lamports · 21 assertions, 4 controls

The old plan, the one that could strand an account nobody could close, is kept as the control: the context-account transfer plan, which strands one account. It must still be refused, and it is. Measured 2026-10-17 by npm run probe-cleanup.

Known limitations

Six risks, with the honest third column.

Open any of them for what does NOT stand in the way. Three of the six have nothing there at all, and those three are the ones worth your attention.

  1. 01

    A script that should not be on this page

    in the way: partly

    Nothing third party is loaded: no CDN, no analytics, no font host, no icon service. The fonts are self hosted at build time, and connect-src reaches only this origin and the RPC.

    What does not

    An RPC accepts arbitrary strings, so a determined injected script could still smuggle bytes out through it. Next needs unsafe-inline for styles and its own hydration script. This raises the cost of an injection; it does not make one harmless.

  2. 02

    A copy of this site on a domain that is not this one

    in the way: not at all

    Nothing. The keys come from a signature over eighteen fixed bytes, so any site that gets you to approve the same message derives the same keys.

    What does not

    No header, no CSP and no code on this page can defend a signature you gave to a different origin. Check the address bar before you approve, every time.

  3. 03

    A wallet extension that is not what it says it is

    in the way: not at all

    VERX never asks for a seed phrase and has no server to send one to. It asks a wallet provider to sign, and reads back what it returns.

    What does not

    A compromised wallet sees every message it is asked to sign, including the one that derives your vault. A page cannot audit the extension it is talking to.

  4. 04

    Being framed and clicked through

    in the way: fully

    frame-ancestors none and X-Frame-Options DENY, both set on every route, plus Cross-Origin-Opener-Policy same-origin so an explorer link cannot reach back through window.opener.

    What does not

    Nothing material. This one is a solved problem and the headers solve it.

  5. 05

    A flow interrupted halfway

    in the way: fully

    Every temporary account is given a closing authority in the same transaction that creates it, and the planner refuses to send a plan where that is not true. 0 transactions across both flows can strand lamports.

    What does not

    An interrupted flow can still leave a balance mid-move: some of it applied, some not. Nothing is lost, and the next run picks it up, but the screens will not read as a clean number until it does.

  6. 06

    Your own machine

    in the way: not at all

    The keys live in the memory of one tab, are never written to any store, and are gone on reload. Nothing persists for malware to read at rest.

    What does not

    Anything that can read the memory of your browser while the vault is unlocked can read the keys. That is true of every wallet and every web app, and it is true here.

  • VERX does not mix funds and has no shared pool.
  • It does not break the link between a wallet and its history.
  • It hides amounts. It does not hide who paid whom.
  • Nothing here has been audited, and the site does not claim otherwise.

The devnet figures were read at slot 511,942,023 on 2026-10-17, and the browser figures at slot 511,962,211 on 2026-10-17. The proofs are checked by ZkE1Gama1Proof11111111111111111111111111111, a program built into the validator. VERX deploys none of its own.

Read the limits before the features.

What an encrypted amount buys, and what it does not.