Security Best Practices
Guidelines for authoring secure policies and managing permissions.
Matador policies act as the "programmable firewall" for your smart accounts. While the interpreter is robust, the security of your system ultimately depends on the logic of the policies you write.
Core Design Principles
Principle of Least Privilege
Grant only the exact permissions needed for a specific task.
- Bad: Whitelisting an entire protocol router address.
- Good: Restricting access to a specific
routeraddress AND a specific function selector (e.g.,swap).
Fail Closed
Design your policies so that any ambiguity results in a revert. Matador enforces this by default: if an opcode is unknown or a check fails, the transaction is blocked.
Logic Grouping
Prefer all (AND) blocks over any (OR) blocks. Use any only when explicitly defining alternative valid paths (e.g., "Allow Swap OR Allow Revoke").
Common Pitfalls
1. Calldata Manipulation
When inspecting calldata, a malicious actor might try to manipulate unchecked arguments.
Vulnerability Example
Checking amountOutMinimum but ignoring recipient in a swap could allow an attacker to swap your tokens but send the proceeds to their own wallet.
Mitigation: Always verify critical parameters like recipient, tokenIn, and tokenOut.
// Secure Swap Policy
when: {
all {
Uniswap.exactInputSingle,
context.args.params.recipient == context.caller, // Enforce self-custody
context.args.params.tokenIn == parameters.allowedToken
}
}2. Rate Limit Key Collision
The ratelimit opcode uses a 32-byte key to track state.
- Risk: Reusing the string
"daily-limit"across multiple policies will cause them to share the same counter. - Fix: Use unique, descriptive keys or hash the policy ID into the key.
// Unique key per policy/action
ratelimit(1 days, 1000 ether, "policy-123-daily-spend")3. Reentrancy & External Calls
CUSTOM_CHECK and STATE_VARIABLE_CHECK perform calls to external contracts.
Mitigation:
- Treat external data as untrusted.
- Use
enforceViewwhere possible to prevent state changes during validation. - Only whitelist trusted oracles and validators.
Operational Security
Compiler Verification
Always verify that the bytecode you are signing matches your source code.
- Source Control: Store
.matadorfiles in git. - CI Verification: Run
matador-policy-cli compilein CI and compare the output hash with the on-chain bytecode. - Human Review: Use the
instructionsfield in the compiler output to sanity-check the generated opcodes.
Monitoring
Set up alerts for PermissionViolation events.
- Spikes: A sudden spike in violations often indicates a broken bot or an active exploit attempt.
- Root Cause: Decode the
opcodein the error to identify exactly which check failed.
Audit Checklist
Before deploying a policy to mainnet, ensure you can answer "Yes" to these questions:
- Does the policy restrict the
targetaddress? - Does the policy restrict the function
selector? - Are all critical calldata arguments (recipient, amount) validated?
- Are numeric limits (allowance, slippage) set to safe bounds?
- Is the rate-limit key unique to this use case?
- Has the policy been tested against both valid and invalid transactions in Foundry?