Security Patterns in Move
A defensive reference for building on Aptos Move.
Scope & stance. A builder-side reference for Aptos Move: the defensive patterns as you would write them now, which layer of the platform already covers each failure mode, and what is left to you. Every sample compiles and every pattern carries an adversarial test that tries the attack and fails, so a claim that a defence holds is a test result rather than an assertion.
Pages state which layer of the platform covers a failure mode: rejected at load by the bytecode verifier, enforced at execution by the VM, checked only by the compiler, or not covered at all. Those are different guarantees and the difference shows up in review. This is deliberately not:
- a Move tutorial; it assumes you can read Move,
- an audit checklist or a vulnerability catalogue,
- a cross-runtime comparison. Measured comparison between MoveVM and other runtimes is its own work and does not belong in a build-side reference,
- a multi-chain Move reference. Aptos Move only. Sui’s object model differs enough that its verdicts would differ too, and guessing at them here would be worse than omitting them.
A verdict is a statement about coverage, not about assurance. “The platform handles this” means one named check rejects one named thing; it does not mean a system built this way is well defended. Always audit, always.
Who this is for
Developers building on Aptos who want the why, and reviewers who want to know which platform guarantee they are actually leaning on. Several defences here are already provided by the platform, and the useful detail is how far each one reaches: a guarantee trusted past its scope is worse than one that was never assumed.
Each page names the failure mode, says which layer enforces it and which layer does not, and shows a
compiling sample backed by a test that tries the attack. Claims about platform behaviour cite the
aptos-core source they were read from, at a pinned commit, and the behaviour of the tests in
src/tests/ is the demonstration.
Where a defence lives
Each page says which of these covers its failure mode. They are not interchangeable:
| Layer | Meaning | What it costs you |
|---|---|---|
| Rejected at load | The bytecode verifier refuses the shape of the bug, so it cannot be published | Nothing at runtime; confirm the scope is what you think it is |
| Enforced at execution | The VM permits the code and aborts the misbehaviour | An abort is a liveness surface, and the scope is usually narrower than its reputation |
| Compiler only | The check runs at build time and constrains code your toolchain produced | Nothing constrains a module that arrived another way |
| Yours | The platform has no opinion | All of it |
A page may name two, where a platform check covers part of a failure mode and leaves the rest. The ability declarations page is one: the verifier enforces every consequence of an ability at load and never asks whether declaring it was right.
Patterns
| Pattern | Category | Prevents | Covered by |
|---|---|---|---|
| Callback Dispatch and Reentrancy | Safety & Access Control | A callback re-entering a module and reading state mid-update | Execution, with a scoped gap |
| Ability Declarations as an Access Decision | Abilities & Types | A convenience ability permitting duplication or silent discard of a value | Load, for the consequences; yours, for the declaration |
| Generic Type Confusion | Abilities & Types | A claim that records a quantity without recording what the quantity is in | Load, once the type says it; yours, to make the type say it |
| Value Substitution Through a Mutable Reference | Values & References | A validated value being replaced through &mut before the module reads it again |
Yours |
| Provenance of a Constructed Value | Values & References | A value built outside the module that performs the checks, and trusted as though it were not | Yours |
Planned
Scope is defined for each of the following; the write-ups are pending, because each needs the same source-level work the first page had before it is worth publishing.
Safety & Access Control Signer Authorization (&signer proves that someone signed, not that the
right someone did) · Object Ownership (any Object<T> can be handed to any function; possession of
the handle is not ownership) · Lifecycle Gating · Pausing (an immutable package makes this the only
lever you will have)
Capabilities Capability and Witness Handling (returning a ConstructorRef hands out authority
that survives the call) · One-Time Witness Misuse
Storage & Execution Unbounded Iteration (a structure any user can grow is a denial-of-service primitive; the verifier’s limits bound module loading, not loop iterations) · Rounding and Precision
Upgrade & Operations Upgrade Policy Choice (arbitrary, compatible, immutable, and what each
commits you to) · Publishing Key Custody · Randomness (an on-chain API with a compile-time
reachability rule, and an attribute that switches the rule off)
External Data Oracle Freshness and Source Diversity
Standards and platform references
Each pattern rests on a specific platform mechanism. REFERENCES.md maps them to what they govern from a security perspective, and to the behaviour that matters when implementing against them.
Running the samples
The samples are a single Move package. With the Aptos CLI:
cd src && aptos move compile --language-version 2.4
A note on the samples
The Move in src/ is a set of reference samples. They illustrate a mechanism in the
fewest lines possible: they are not audited, are not meant to be deployed as-is, and deliberately
omit hardening, events, access control, and edge cases a real deployment needs. Every sample carries
a REFERENCE SAMPLE header saying so.
Coverage is not assurance
Knowing that a platform check covers a failure mode tells you where to stop looking, not that the result is well defended. Checks enforce the rule they implement, against the threats their authors modelled, in the version deployed today; the interesting bugs are the ones nobody modelled, and those are found by audits and bounties rather than by reading a table.
Using any pattern from this repository is never a substitute for an independent security audit.
Always audit, always.
License
MIT, see LICENSE. A reference repository: code here is not audited and is never a substitute for an independent audit.