On the EVM there is one attacker axis: msg.sender. Whoever sends the
transaction is the actor, and everything on chain is public - so being able to see
something and being able to act on it are the same privilege. If you can read the state,
you can use it.
Canton breaks that single privilege into two independent ones, and this is the whole game. Every transaction you submit names two sets of parties:
-
actAs- your authority. The right to act: to trigger a contract's actions and put a party on the hook for its obligations. -
readAs- your disclosure. The right to see: to read a contract's contents.
They don't imply each other. A party can see everything about a contract and have zero power over it. A party can have the power to act inside a transaction whose full contents are hidden from them. Privacy and authorization are separate concerns, so the attacker model is no longer one-dimensional.
The faithful attacker
The classic mistake is auditing "as the owner" - writing the test as if the attacker submits with the victim's identity. That hands the attacker the victim's authority and the victim's visibility, and every finding inflates. The faithful attacker uses only their own authority and only the disclosure they could actually get.
This matters because many Daml vulnerabilities aren't "crypto bugs" at all. They're authorization mistakes, visibility assumptions, broken business workflows, or invariants that hold for one execution path but not another. The question isn't just "can the attacker call this choice?" but also "can they even discover this contract?" and "what information are they actually allowed to reason over?"
On the EVM, seeing and acting are the same power, so there's one attacker to model. On Canton they're two separate powers, and the attacker rarely holds both. Audit the two axes separately - who can act, and who can see - or you'll inflate half your findings and miss the other half.
Secure your codebase - valvessecurity.com