canister-security
Canister Security
What This Is
Security patterns for IC canisters in Motoko and Rust. The async messaging model creates TOCTOU (time-of-check-time-of-use) vulnerabilities where state changes between await calls. canister_inspect_message is NOT a reliable security boundary. Anyone on the internet can burn your cycles by sending update calls. This skill provides copy-paste correct patterns for access control, reentrancy prevention, async safety, and callback trap handling.
Prerequisites
- For Motoko:
mopspackage manager,core = "2.0.0"in mops.toml - For Rust:
ic-cdk = "0.19",candid = "0.10"
Security Pitfalls
-
Relying on
canister_inspect_messagefor access control. This hook runs on a single replica without full consensus. If that replica is malicious, it can simply skip the check and execute the update call without any message inspection. It is also never called for inter-canister calls, query calls, or management canister calls. Always duplicate access checks inside every update method. Useinspect_messageonly as a cycle-saving optimization, never as a security boundary. -
Forgetting to reject the anonymous principal. Every endpoint that requires authentication must check that the caller is not the anonymous principal (
2vxsx-fae). In Motoko usePrincipal.isAnonymous(caller), in Rust comparemsg_caller() != Principal::anonymous(). Without this, unauthenticated callers can invoke protected methods — and if the canister uses the caller principal as an identity key (e.g., for balances), the anonymous principal becomes a shared identity anyone can use. -
Reading state before an async call and assuming it's unchanged after (TOCTOU). When your canister
awaits an inter-canister call, other messages can interleave and mutate state. This is one of the most critical sources of DeFi exploits on IC. Use per-caller locking (CallerGuard pattern) to prevent concurrent operations. For financial operations, also consider the saga pattern (deduct beforeawait, compensate on failure) — but implementing it correctly is complex due to edge cases like callback traps and call timeouts where the outcome is ambiguous.
More from dfinity/icskills
icp-cli
Guides use of the icp command-line tool for building and deploying Internet Computer applications. Covers project configuration (icp.yaml), recipes, environments, canister lifecycle, and identity management. Use when building, deploying, or managing any IC project. Use when the user mentions icp, dfx, canister deployment, local network, or project setup. Do NOT use for canister-level programming patterns like access control, inter-canister calls, or stable memory — use domain-specific skills instead.
134internet-identity
Integrate Internet Identity authentication. Covers passkey and OpenID login flows, delegation handling, and principal-per-app isolation. Use when adding login, sign-in, auth, passkeys, or Internet Identity to a frontend or canister. Do NOT use for wallet integration or ICRC signer flows — use wallet-integration instead.
126asset-canister
Deploy frontend assets to the IC. Covers certified assets, SPA routing with .ic-assets.json5, content encoding, and programmatic uploads. Use when hosting a frontend, deploying static files, or setting up SPA routing on IC. Do NOT use for canister-level code patterns or custom domain setup — use custom-domains instead.
126stable-memory
Persist canister state across upgrades. Covers StableBTreeMap and MemoryManager in Rust, persistent actor in Motoko, and upgrade hook patterns. Use when dealing with canister upgrades, data persistence, data lost after upgrade, stable storage, StableBTreeMap, pre_upgrade traps, or heap vs stable memory. Do NOT use for inter-canister calls or access control — use multi-canister or canister-security instead.
121https-outcalls
Make HTTPS requests from canisters to external web APIs. Covers transform functions for consensus, cycle cost management, response size limits, and idempotency patterns. Use when a canister needs to call an external API, fetch data from the web, or make HTTP requests. Do NOT use for EVM/Ethereum calls — use evm-rpc instead.
121certified-variables
Serve cryptographically verified responses from query calls using Merkle trees and subnet BLS signatures. Covers certified data API, RbTree/CertTree construction, witness generation, and frontend certificate validation. Use when query responses need verification, certified data, or response authenticity proofs.
116