ZIP-0 moves value between chains. Treat every key as production, because the code that handles testnet funds is the code that will handle real ones.
Do not open a public issue for a security problem. Contact a repository maintainer directly.
If the finding concerns a deployed contract, include the network, the contract address, and a concrete reproduction.
- Never commit a private key. Not as a default, not as a fallback, not "just for testing".
- No literal-key fallbacks in code. If an environment variable is missing, the program must fail loudly. A committed fallback in a public repository is a published key, and it will be used silently the moment someone forgets to set the variable.
- Never reuse a key across environments. The deployer key, the relayer key, and any test payer key must be distinct, and mainnet keys must never have existed on a developer laptop that also runs testnet scripts.
- Assume any leaked key is permanently compromised. Rewriting Git history does not un-leak a key: forks, clones, caches, and mirrors keep their copy. The only remedy is rotation.
- Fund deployer keys with the minimum needed. A mainnet deployment of
ZIP0PaymentVaultcosts roughly 1.25–1.75 HSK. Do not hold more than the task requires.
.gitignore covers .env, .env.*, *.pem, and wallets, but the last line of defence is you.
Check git diff --staged before every commit.
ZIP0PaymentVault is not trust-minimized in its current form.
Any address holding RELAYER_ROLE can call releasePayment() for any unused paymentId, to any
recipient, for any amount up to the vault balance. There is no on-chain proof of the corresponding
credit on the source chain.
This means a compromised relayer key is equivalent to full control of vault float. Guard it accordingly, and keep vault liquidity proportionate to what the deployment actually needs.
A payer can call claimRefund() on any deposit still INITIATED once REFUND_TIMEOUT (24 h) has
passed. The relayer prevents this for deposits it settles by calling acknowledgePayment()
before crediting the destination chain.
So relayer downtime is not only an availability problem. If the relayer is down for longer than
REFUND_TIMEOUT, deposits it never acknowledged become refundable to the payer, and a relayer that
comes back and settles one of them without acknowledging first would pay it twice. The relayer
always acknowledges before crediting, and a failed acknowledgement stops the settlement. Monitor
relayer uptime against REFUND_TIMEOUT, and never settle a deposit by any path that skips
acknowledgePayment().
Making settlement trust-minimized is the purpose of the planned CCTP rail. See
docs/project-status.md.
DEFAULT_ADMIN_ROLE can grant and revoke RELAYER_ROLE and TREASURY_ROLE. If a relayer key is
suspected of exposure:
- Generate a new key offline.
- Grant
RELAYER_ROLEto the new address. - Revoke
RELAYER_ROLEfrom the old address. - Move vault float if the exposure window was long.
Revocation is what actually stops an attacker. Granting a replacement without revoking the old address changes nothing.
Consider assigning TREASURY_ROLE to a Safe multisig rather than an EOA — HashKey Chain provides
one at https://multisig.hashkeychain.net.
This policy covers the contracts in packages/contracts-evm and the relayer in
packages/cctp-bridge. This is hackathon-stage software and has not been audited. Do not deploy
it with funds you are unwilling to lose.
elliptic <= 6.6.1(CVE-2025-14505 / GHSA-848j-6mx2-7j84):- Status: Low severity. Deep transitive dependency pulled by
@circle-fin/adapter-viem-v2through@ethersproject/signing-key. - Upstream Mitigation: As of September 2026, version 6.6.1 is the latest release published by upstream
indutny/ellipticwith no patched version available yet (first_patched_version: null). ZIP-0 relies primarily on native Viem cryptographic primitives and RPC nodes for transaction signing rather than legacy elliptic curves directly.
- Status: Low severity. Deep transitive dependency pulled by