Setting up a simple policy restricting your wallet to only be able to take a known set of actions can save you even in the event of a complete infrastructure takeover.
Colfax Selby
|Mar 14, 2025
Looking at recent hacks, they are usually the result of a compromised wallet taking an action it doesn’t normally perform. In most cases, especially with wallets that hold a large amount of value, wallets transact in the same patterns - with a finite list of addresses or contracts, same set of assets, calling the same functions, or transferring a regular fixed amount. Or if that’s not the case, it is possible to rearchitect a system that way.
Your wallet has many layers of security to protect you – you need to enter a password to interact, you’re (generally) shown what the transaction does (or better yet, what the result of it is), and even in some cases your wallet lives on its own hardware device.
But whether you’ve gotten phished or your infrastructure gets compromised directly, hacks still happen. A safeguard you can use as a last line of defense is policies.
With Privy server wallets, you can set up simple or complex policies that restrict what your wallet can do. These policies are enforced against any incoming transaction request, and if the request does not adhere to the policy, even if the request comes from your servers, it will not go through. This is inherently baked into the implementation of server wallets and there is no way to bypass it, details on that below.
Some common examples of policies are:
Max transaction value
Allowlist transactions to a certain set of addresses / contracts
Restrict parameter values when calling a smart contract
Prevent the use of delegatecall
Stack multiple together
Privy’s architecture ensures that a wallet’s private key can only be reconstituted on behalf of the holders of the wallet’s authorization keys. Policies are an additional layer of defense, enforced before your private key is reassembled inside the secure execution environment. You can read more about our server wallet architecture here.
When talking about policies, it’s important to understand how they can be updated. Policies have owners. Owners are made up of a quorum of keys – an individual key, a subset of a group, or a whole set of keys are required to sign off on updates, depending on the configuration.
Transactions are also approved by a quorum - either a single key, or multiple, are required to send a transaction request.
With these tools, you can architect a wallet system that fits your needs, whether you’re just getting started or run a large, multi-national corporation.
A simple architecture fit for an early-stage idea
You’re working on a social, verified-image sharing app
You have a signing key that manages your policies. You set them up once, and keep this key offline since it’s not needed on a regular basis.
You have a different signing key that’s responsible for signing off on each transaction. This key sits in an environment variable.
A complex architecture fit for a large organization
You run a global exchange that handles $10B of annual volume across 50 currencies.
Your core transaction policies are managed by compliance team
Policy changes require a 5 of 7 quorum of signatures for updates
The OFAC denylist policy is managed by a separate sanctions team
Your wallets are provisioned and policies assigned to them on a restricted machine, and this happens very rarely
You have a small fleet of “omnibus” treasury wallets that hold a majority of your funds
Any transaction coming out of these wallets requires 3 signatures out of a preset group of 5 treasury managers at your company
These wallets can only send funds to a list of 10 “hot” wallets your company manages
Each outgoing transaction has a limit of $500k
Hot wallets
These are your day-to-day operations wallets
They each only require one signature to transact from a key that lives in an environment variable on your server
They can send to any address with a transaction limit of $10k
However, a set of 3 administrators can sign together to send up to $500k in a transaction
In either case, if your core infrastructure is compromised, the attacker can only send transactions from your wallets that adhere to the policies you’ve set up – they can only send funds to your allowlisted addresses, send transactions of a maximum value, or call smart contracts with the constrained parameters you’ve specified.
Policies must be easy and intuitive to set up. You are only as secure as your policy configuration and the safety of the keys that control them.
We’re working hard to make the safest way, the easiest way. Currently, we offer the ability to restrict the parameters on smart contract calls, and we’re building a higher level abstraction like 'usdc_transfer_limit' and things like transaction simulation, so you can enforce against the outcome of a transaction rather than the inputs. We’re also working on restricting total transaction volume, rather than individual transaction limits, so you can set up even more constraints.
You can get started with transaction policies here! We’re always excited to hear about what you’re building, and especially your experience with Privy, so join our developer slack and let us know what you think – your feedback will drive our roadmap.