From fc2f96a77add236032c4f0eb3f8dd262ff6d5579 Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Mon, 11 May 2026 14:57:02 +0200 Subject: [PATCH 1/6] fix(security): apply ICP brand voice to security guides - Replace all standalone "dapp"/"dapps" with "app"/"apps" across 9 files; preserve repo names (nns-dapp, encrypted-notes-dapp) in URLs and update their link labels (NNS app, encrypted notes example app) - Replace "smart contract(s)" with "canister(s)" in decentralization.md, including section heading and the blockchains admonition note - Remove em-dashes from Upstream comments in all 11 remaining files (identity-and-access-management.mdx was already fixed) - Remove informal phrasing in data-integrity-and-authenticity.md: "club composite_query" and "best of both worlds" - Fix garbled sentence in identity-and-access-management.mdx mobile II section --- docs/guides/security/canister-upgrades.md | 2 +- .../data-integrity-and-authenticity.md | 16 +++++----- docs/guides/security/data-storage.md | 6 ++-- docs/guides/security/decentralization.md | 32 +++++++++---------- docs/guides/security/dos-prevention.md | 6 ++-- docs/guides/security/formal-verification.md | 8 ++--- docs/guides/security/https-outcalls.md | 2 +- .../identity-and-access-management.mdx | 14 ++++---- docs/guides/security/inter-canister-calls.md | 2 +- docs/guides/security/miscellaneous.md | 4 +-- .../security/observability-and-monitoring.md | 2 +- docs/guides/security/overview.md | 8 ++--- 12 files changed, 51 insertions(+), 51 deletions(-) diff --git a/docs/guides/security/canister-upgrades.md b/docs/guides/security/canister-upgrades.md index 0af030d1..c490be15 100644 --- a/docs/guides/security/canister-upgrades.md +++ b/docs/guides/security/canister-upgrades.md @@ -49,4 +49,4 @@ Using the Rust CDK, the recurring timer is also lost on upgrade as explained in - See the Rust documentation on [set_timer_interval](https://docs.rs/ic-cdk/0.6.9/ic_cdk/timer/fn.set_timer_interval.html). - + diff --git a/docs/guides/security/data-integrity-and-authenticity.md b/docs/guides/security/data-integrity-and-authenticity.md index 1433e65b..4b8e1fec 100644 --- a/docs/guides/security/data-integrity-and-authenticity.md +++ b/docs/guides/security/data-integrity-and-authenticity.md @@ -9,16 +9,16 @@ sidebar: ### Security concern -ICP offers three modes of operation for canisters: `update`, `query`, and `composite_query`. For the sake of simplicity, we will club `composite_query` under queries for the rest of this section. +ICP offers three modes of operation for canisters: `update`, `query`, and `composite_query`. For simplicity, this guide treats `composite_query` as a query call for the rest of this section. Update calls are slow and expensive but provide integrity guarantees as their responses include a threshold signature signed by the subnet. -On the other hand, query calls are fast since a single replica formulates the response, but **there is no integrity guarantee, since the response can be manipulated by a single replica or boundary node.** For example, if the NNS dapp fetches proposal information from the governance canister via query calls and the responding node is malicious, it can mask an ill-intentioned proposal that causes irrevocable damage as innocuous by modifying the proposal payload in the response and mislead voters into voting yes. Another consequence of query calls is that users can't rely on [canister_inspect_message](../../references/ic-interface-spec/canister-interface.md#system-api-inspect-message) as a guard. **This makes query calls, in their raw form, unfit to serve data for security-critical applications.** +On the other hand, query calls are fast since a single replica formulates the response, but **there is no integrity guarantee, since the response can be manipulated by a single replica or boundary node.** For example, if the NNS app fetches proposal information from the governance canister via query calls and the responding node is malicious, it can mask an ill-intentioned proposal that causes irrevocable damage as innocuous by modifying the proposal payload in the response and mislead voters into voting yes. Another consequence of query calls is that users can't rely on [canister_inspect_message](../../references/ic-interface-spec/canister-interface.md#system-api-inspect-message) as a guard. **This makes query calls, in their raw form, unfit to serve data for security-critical applications.** ### Using certified variables for secure queries -In certain use cases, there is a third option whereby query results can return data that has been certified by the subnet in an earlier update call. This is the concept of certified data, and it requires changes to the update call to create the certification, the query call to return the certificate, and the frontend to verify the certificate. Using certified data provides the best of both worlds with query-like response times and update-like certified responses. +In certain use cases, there is a third option whereby query results can return data that has been certified by the subnet in an earlier update call. This is the concept of certified data, and it requires changes to the update call to create the certification, the query call to return the certificate, and the frontend to verify the certificate. Using certified data provides query-like response times with update-like certified responses. -Some examples of certified variables are asset certification in [Internet Identity](https://github.com/dfinity/internet-identity/blob/b29a6f68bbe5a49d048e12bc7a3263a9f43d080b/src/internet_identity/src/main.rs#L775-L808), [NNS dapp](https://github.com/dfinity/nns-dapp/blob/372c3562127d70c2fde059bc9c268e8ae858583e/rs/src/assets.rs#L121-L145), or the [canister signature implementation in Internet Identity](https://github.com/dfinity/ic-canister-sig-creation). +Some examples of certified variables are asset certification in [Internet Identity](https://github.com/dfinity/internet-identity/blob/b29a6f68bbe5a49d048e12bc7a3263a9f43d080b/src/internet_identity/src/main.rs#L775-L808), [NNS app](https://github.com/dfinity/nns-dapp/blob/372c3562127d70c2fde059bc9c268e8ae858583e/rs/src/assets.rs#L121-L145), or the [canister signature implementation in Internet Identity](https://github.com/dfinity/ic-canister-sig-creation). :::tip Certified variables are an advanced feature that require careful implementation of authenticated data structures and verification on the canister and client sides, respectively. **If the client doesn't require fast response times, call the query method as an update call (replicated query).** The response would be certified by the subnet, and a single malicious or boundary node can't modify the response. @@ -610,11 +610,11 @@ function bigEndian(n) { } ``` -## Use HTTP asset certification and avoid serving your dapp through `raw.icp0.io` +## Use HTTP asset certification and avoid serving your app through `raw.icp0.io` ### Security concern -Dapps on ICP can use [asset certification](https://learn.internetcomputer.org/hc/en-us/articles/34276431179412-Asset-Certification) to make sure the HTTP assets delivered to the browser are authentic (i.e., threshold-signed by the subnet). If an app does not do asset certification, it can only be served insecurely through `raw.icp0.io`, where no asset certification is checked. This is insecure since a single malicious node or boundary node can freely modify the assets delivered to the browser. +Apps on ICP can use [asset certification](https://learn.internetcomputer.org/hc/en-us/articles/34276431179412-Asset-Certification) to make sure the HTTP assets delivered to the browser are authentic (i.e., threshold-signed by the subnet). If an app does not do asset certification, it can only be served insecurely through `raw.icp0.io`, where no asset certification is checked. This is insecure since a single malicious node or boundary node can freely modify the assets delivered to the browser. If an app is served through `raw.icp0.io` in addition to `icp0.io`, an adversary may trick users (phishing) into using the insecure `raw.icp0.io`. @@ -622,8 +622,8 @@ If an app is served through `raw.icp0.io` in addition to `icp0.io`, an adversary - Only serve assets through `.icp0.io`, where the boundary nodes enforce response verification on the served assets. Do not serve through `.raw.icp0.io`. -- Serve assets using the asset canister, which creates asset certification automatically, or add the `ic-certificate` header including the asset certification as, e.g., done in the [NNS dapp](https://github.com/dfinity/nns-dapp) and [Internet Identity](https://github.com/dfinity/internet-identity). +- Serve assets using the asset canister, which creates asset certification automatically, or add the `ic-certificate` header including the asset certification as, e.g., done in the [NNS app](https://github.com/dfinity/nns-dapp) and [Internet Identity](https://github.com/dfinity/internet-identity). - Check in the canister's `http_request` method if the request came through raw. If so, return an error and do not serve any assets. - + diff --git a/docs/guides/security/data-storage.md b/docs/guides/security/data-storage.md index 960491fd..e2f7fa62 100644 --- a/docs/guides/security/data-storage.md +++ b/docs/guides/security/data-storage.md @@ -71,7 +71,7 @@ By default, canisters provide integrity but not confidentiality. Data stored on - Consider end-to-end encrypting any private or personal data (e.g., a user's personal or private information) on canisters. -- The example dapp [encrypted notes](https://github.com/dfinity/examples/tree/master/motoko/encrypted-notes-dapp) illustrates how end-to-end encryption can be done. +- The [encrypted notes](https://github.com/dfinity/examples/tree/master/motoko/encrypted-notes-dapp) example app illustrates how end-to-end encryption can be done. ## Create backups @@ -79,7 +79,7 @@ By default, canisters provide integrity but not confidentiality. Data stored on A canister could be rendered unusable and impossible to upgrade. For example, due to one of the following reasons: -- It has a faulty upgrade process due to some bug from the dapp developer. +- It has a faulty upgrade process due to some bug from the app developer. - The state becomes inconsistent or corrupt because of a bug in the code that persists data. @@ -91,4 +91,4 @@ A canister could be rendered unusable and impossible to upgrade. For example, du - See the "Backup and recovery" section in [how to audit an Internet Computer canister](https://www.joachim-breitner.de/blog/788-How_to_audit_an_Internet_Computer_canister). - + diff --git a/docs/guides/security/decentralization.md b/docs/guides/security/decentralization.md index 14bcdf52..36044030 100644 --- a/docs/guides/security/decentralization.md +++ b/docs/guides/security/decentralization.md @@ -1,11 +1,11 @@ --- title: "Decentralization" -description: "Security best practices for decentralizing dapp control using SNS, governance, and reducing centralized trust." +description: "Security best practices for distributed canister control using the SNS, governance mechanisms, and reducing centralized trust." sidebar: order: 10 --- -## Use a decentralized governance system like SNS to put dapps under decentralized control +## Use a decentralized governance system such as the SNS to control your canisters ### Security concerns @@ -15,45 +15,45 @@ Furthermore, the controller of canisters serving web content (such as e.g., the Dapps are commonly reachable over their own custom domain name instead of ic0.app. These domains are registered with a DNS registrar by one of the developers. The developer can choose to have this domain point at a completely different web application, even one not hosted on ICP. Users will trust this domain and the app it serves. This could allow such a developer to steal funds, leak data, etc. -A dapp might have privileged features that are only accessible to principals that are on an allow list. For example, minting new tokens, debugging functions, managing permissions, removing NFTs for digital rights violations, etc. This means that whoever controls that principal (such as the dapp developers) may have central control over these privileged features. +An app might have privileged features that are only accessible to principals that are on an allow list. For example, minting new tokens, debugging functions, managing permissions, removing NFTs for digital rights violations, etc. This means that whoever controls that principal (such as the app developers) may have central control over these privileged features. -For performance or privacy reasons, some components of a dapp may be hosted off-chain. These off-chain components often control principals used to interact with the onchain components and are usually controlled by a developer holding credentials to the off-chain cloud environment. On top of that, third party off-chain entities such as cloud providers can inspect and manipulate data in this environment if they choose. They could take ICP principal private keys out of this environment and call privileged operations on the canisters. Off-chain components can quickly lead to many additional centrally trusted parties. Depending on the value managed by a dapp, these parties could be tempted to act maliciously. +For performance or privacy reasons, some components of an app may be hosted off-chain. These off-chain components often control principals used to interact with the onchain components and are usually controlled by a developer holding credentials to the off-chain cloud environment. On top of that, third party off-chain entities such as cloud providers can inspect and manipulate data in this environment if they choose. They could take ICP principal private keys out of this environment and call privileged operations on the canisters. Off-chain components can quickly lead to many additional centrally trusted parties. Depending on the value managed by an app, these parties could be tempted to act maliciously. ### Recommendations -In the following list, we first provide recommendations for centralized dapp control and then move to recommendations for increasingly decentralized settings. From a security perspective, more decentralization is favorable. The following list could also be used as a basis for assessing a dapp's level of decentralization. This is just a set of recommendations and may be incomplete. +In the following list, we first provide recommendations for centralized canister control and then move to recommendations for increasingly decentralized settings. From a security perspective, more decentralization is favorable. The following list could also be used as a basis for assessing an app's level of decentralization. This is just a set of recommendations and may be incomplete. -1. **The dapp uses central, off-chain components:** The application makes use of centralized components such as those running in the cloud. The owners of these cloud services have full control over the application and assets managed by it. Your application should likely be further decentralized by avoiding central components. But while you have them, [securely manage your keys in the cloud](https://cloudsecurityalliance.org/research/topics/cloud-key-management/). -2. **The dapp is controlled by the developer team:** Your project is not under decentralized control, for example, because it is in an early development stage or does not (yet) hold significant funds. In that case, it is recommended to manage access to your canisters securely and ideally not let individuals control the application. To achieve that, consider the following: +1. **The app uses central, off-chain components:** The application makes use of centralized components such as those running in the cloud. The owners of these cloud services have full control over the application and assets managed by it. Your application should likely be further decentralized by avoiding central components. But while you have them, [securely manage your keys in the cloud](https://cloudsecurityalliance.org/research/topics/cloud-key-management/). +2. **The app is controlled by the developer team:** Your project is not under decentralized control, for example, because it is in an early development stage or does not (yet) hold significant funds. In that case, it is recommended to manage access to your canisters securely and ideally not let individuals control the application. To achieve that, consider the following: - Require approval by several individuals or parties to perform any canister controller operations. - Require approval by several individuals or parties for any security-sensitive changes at the application level that are restricted to privileged principals, such as admin operations including permissions management, minting new tokens, removing NFTs for digital rights violations, etc. - - A helpful tool to achieve either of the above two points is the [orbit station canister](https://github.com/dfinity/orbit) which allows you to configure intricate policies for canister control. [Orbit](https://orbit.global/) also serves as an enterprise wallet where token funds are governed using policies. Ideally, individuals also manage their key material using hardware security modules, such as [YubiHSM](https://www.yubico.com/ch/store/yubihsm-2-series/) and physically protect these through methods such as using safes at different geographical locations. Some of HSMs support threshold signature schemes, which can help to further secure the setup. To increase transparency about the changes made to a dapp, consider using a tool like [LaunchTrail](https://github.com/spinner-cash/launchtrail). -3. **Full decentralization using a DAO**: The dapp is controlled by a decentralized governance system such as ICP's [Service Nervous System (SNS)](https://learn.internetcomputer.org/hc/en-us/articles/34084394684564-SNS-Service-Nervous-System), so that any security-sensitive changes to the canisters are only executed if the SNS community approves them collectively through a proposal voting mechanism. If an SNS is used: + - A helpful tool to achieve either of the above two points is the [orbit station canister](https://github.com/dfinity/orbit) which allows you to configure intricate policies for canister control. [Orbit](https://orbit.global/) also serves as an enterprise wallet where token funds are governed using policies. Ideally, individuals also manage their key material using hardware security modules, such as [YubiHSM](https://www.yubico.com/ch/store/yubihsm-2-series/) and physically protect these through methods such as using safes at different geographical locations. Some of HSMs support threshold signature schemes, which can help to further secure the setup. To increase transparency about the changes made to an app, consider using a tool like [LaunchTrail](https://github.com/spinner-cash/launchtrail). +3. **Full decentralization using a DAO**: The app is controlled by a decentralized governance system such as ICP's [Service Nervous System (SNS)](https://learn.internetcomputer.org/hc/en-us/articles/34084394684564-SNS-Service-Nervous-System), so that any security-sensitive changes to the canisters are only executed if the SNS community approves them collectively through a proposal voting mechanism. If an SNS is used: - Make sure voting power is distributed over many independent entities such that there is not one single or a few entities that can decide by themselves how the [DAO evolves](https://learn.internetcomputer.org/hc/en-us/articles/34088279488660-Tokenomics#voting-power-and-decentralization). - - Ensure all components of the dapp are under SNS control, including the canisters serving the web frontends; see [SNS asset canisters](../governance/managing.md). + - Ensure all components of the app are under SNS control, including the canisters serving the web frontends; see [SNS asset canisters](../governance/managing.md). - Consider the [SNS preparation checklist](../governance/launching.md). Important points from a security perspective are tokenomics, disclosing dependencies to off-chain components, and performing security reviews. - Rather than self-deploying the SNS code or building your own DAO, consider using the official SNS on the SNS subnet, as this guarantees that the SNS is running an NNS-blessed version and maintained as part of ICP. - See also [verification and trust in a (launched) SNS](https://wiki.internetcomputer.org/wiki/Verification_and_trust_in_a_(launched)_SNS) and [SNS decentralization swap trust](https://wiki.internetcomputer.org/wiki/SNS_decentralization_swap_trust). -An alternative to DAO control (3. above) would be to create an immutable canister smart contract by removing the canister controller completely. This can be achieved by setting the controller to a [black hole canister](https://github.com/ninegua/ic-blackhole). However, note that this implies that the canister can **never** be upgraded, which may have severe implications in case a bug is found. The complexity of ICP dapps and the fact that complex frontends are hosted onchain means that black holed canisters are rarely the right solution. The option to use a decentralized governance system and thus being able to upgrade smart contracts is a big advantage of the ICP ecosystem compared to other blockchains. +An alternative to DAO control (3. above) would be to create an immutable canister by removing the canister controller completely. This can be achieved by setting the controller to a [black hole canister](https://github.com/ninegua/ic-blackhole). However, note that this implies that the canister can **never** be upgraded, which may have severe implications in case a bug is found. The complexity of ICP apps and the fact that complex frontends are hosted onchain means that black holed canisters are rarely the right solution. The option to use a decentralized governance system and thus being able to upgrade canisters is a big advantage of the ICP ecosystem compared to other chains. :::note -Contrary to some other blockchains, immutable smart contracts need cycles to run, and they can receive cycles. +Contrary to some other chains, immutable canisters need cycles to run, and they can receive cycles. ::: It is also possible to implement a DAO on ICP from scratch. If you decide to do this (e.g., along the lines of the [basic DAO example](https://github.com/dfinity/examples/tree/master/rust/basic_dao)), be aware that this is security critical and must be security reviewed carefully. Furthermore, users will need to verify that the DAO is controlled by itself. -## Verify the control and level of decentralization of smart contracts you depend on +## Verify the control and trust level of canisters you depend on ### Security concern -If a dapp depends on a third-party canister smart contract (e.g., by making inter-canister calls to it), it is important to verify that the callee satisfies an appropriate level of decentralization. For example: +If your app depends on a third-party canister (e.g., by making inter-canister calls to it), it is important to verify that the callee satisfies an appropriate level of decentralization. For example: - If funds or cycles are transferred to a third-party canister, one might require the canister to be controlled by a decentralized governance system, as otherwise these funds are centrally controlled. - If inter-canister calls are made to a centrally controlled and potentially malicious canister, that canister could execute a denial of service attack on the caller or even trigger functional bugs; see [be aware of the risks involved in calling untrustworthy canisters](./inter-canister-calls.md#be-aware-of-the-risks-involved-in-calling-untrustworthy-canisters). ### Recommendation -If you interact with a canister that you require to be decentralized, make sure it is controlled by the NNS, a service nervous system (SNS) or a decentralized governance system, and review under what conditions and by whom the smart contract can be changed. +If you interact with a canister that you require to be decentralized, make sure it is controlled by the NNS, a service nervous system (SNS) or a decentralized governance system, and review under what conditions and by whom the canister can be changed. ## Don't load JavaScript or other assets from untrusted domains @@ -73,4 +73,4 @@ Note that also loading other assets such as [CSS](https://xsleaks.dev/docs/attac - Use a [content security policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) to prevent scripts and other content from other origins from being loaded at all. See also [define security headers, including a content security policy (CSP)](./overview.md#web-security). - + diff --git a/docs/guides/security/dos-prevention.md b/docs/guides/security/dos-prevention.md index 5cc8a93d..83a23b27 100644 --- a/docs/guides/security/dos-prevention.md +++ b/docs/guides/security/dos-prevention.md @@ -9,7 +9,7 @@ sidebar: ### Security concern -A denial of service (DoS) attack aims to make a system unavailable by overwhelming it with requests or data. A Distributed Denial of Service (DDoS) attack is a more sophisticated version, where the attack originates from multiple sources, making it harder to block. An attacker will typically search for operations that are free to be executed by anyone but which are expensive for the application in terms of certain resources such as storage, memory usage, network bandwidth, computing resources, etc. In the case of canisters, such attacks can aim to deplete cycles, making the canister unable to process legitimate requests. The reverse gas model means that a dapp needs to implement strategies to deal with this. +A denial of service (DoS) attack aims to make a system unavailable by overwhelming it with requests or data. A Distributed Denial of Service (DDoS) attack is a more sophisticated version, where the attack originates from multiple sources, making it harder to block. An attacker will typically search for operations that are free to be executed by anyone but which are expensive for the application in terms of certain resources such as storage, memory usage, network bandwidth, computing resources, etc. In the case of canisters, such attacks can aim to deplete cycles, making the canister unable to process legitimate requests. The reverse gas model means that apps need to implement strategies to deal with this. ### Recommendation @@ -31,7 +31,7 @@ To mitigate the "noisy neighbor" issue, manage your canister's resource allocati * **Memory allocation**: Memory can be reserved per canister by setting `memory_allocation`, ensuring that your canister can always allocate memory up to the requested `memory_allocation` and preventing other canisters from using up the subnet's available memory. Note that memory availability is not guaranteed beyond the memory allocation and thus monitoring actual memory usage against this value is important to avoid availability issues. * **Compute reservation**: Similar to memory, computing power can also be reserved by setting `compute_allocation` to a value between 0 and 100, which denotes the percentage of one CPU core to be reserved for this canister. A value of 50 means that every 2 rounds, the canister will be scheduled to execute a message. This guarantees the minimal progress your canister can make, which protects against noisy neighbors. Both allocations are reserving resources for your canister on the subnet, which prevents the other canisters from using them. Hence, they come at a cost. Memory allocation is charged as if all that memory would be allocated. Compute allocation is currently charged at 10M cycles per percentage point. Learn more about managing memory and compute resources in the [cycles costs reference](../../references/cycles-costs.md). -* **Subnet and canister distribution**: Implement a smart canister deployment strategy by monitoring the load on subnets. You can choose to deploy new canisters on less busy subnets or adopt a multi-canister architecture that balances the load across subnets. Be mindful to minimize inter-subnet communication for canisters that frequently interact with each other. Additionally, avoid deploying to known high-traffic subnets where possible, though keep in mind that resource usage can change unexpectedly with new dapps. +* **Subnet and canister distribution**: Implement a smart canister deployment strategy by monitoring the load on subnets. You can choose to deploy new canisters on less busy subnets or adopt a multi-canister architecture that balances the load across subnets. Be mindful to minimize inter-subnet communication for canisters that frequently interact with each other. Additionally, avoid deploying to known high-traffic subnets where possible, though keep in mind that resource usage can change unexpectedly with new apps. :::note When the subnet grows above 750GiB, then the new reservation mechanism activates. Every time a canister allocates new storage bytes, the system sets aside some amount of cycles from the main balance of the canister. These reserved cycles will be used to cover future payments for the newly allocated bytes. The reserved cycles are not transferable, and the amount of reserved cycles depends on how full the subnet is. For example, it may cover days, months, or even years of payments for the newly allocated bytes. It is important to note that the reservation mechanism applies only to the newly allocated bytes and does not apply to the storage already in use by the canister. See more at [resource reservations](https://forum.dfinity.org/t/increasing-subnet-storage-capacity-and-introducing-resource-reservation-mechanism/23447). @@ -59,4 +59,4 @@ An attacker will target expensive calls to drain the cycles balance or available - Be aware of attacks targeting high cycles-consuming calls. - See the "Cycle balance drain attacks section" in [How to audit an ICP canister](https://www.joachim-breitner.de/blog/788-How_to_audit_an_Internet_Computer_canister). - + diff --git a/docs/guides/security/formal-verification.md b/docs/guides/security/formal-verification.md index 502fb990..f7db5039 100644 --- a/docs/guides/security/formal-verification.md +++ b/docs/guides/security/formal-verification.md @@ -21,14 +21,14 @@ The Temporal Logic of Actions (TLA+) is a language for specifying and verifying Importantly, after building the model of the code, model checking runs with virtually no further human input, making it highly cost-effective. To illustrate with some made-up numbers: if the industry standard practices (such as testing and security reviews) eliminate 80% of the bugs, and "heavyweight" formal verification eliminates 99.99%, with TLA+ you can eliminate 90% with a fraction of the effort of the heavyweight verification. -We have used TLA+ to create the following models that can be interesting for dapp developers: +We have used TLA+ to create the following models that can be interesting for canister developers: - NNS and SNS governance (focusing on interactions with the ledger canister). - ICP ledger (focusing on block archival). - ckBTC minter. - SNS swap canister. -- People parties dapp. +- People parties app. -To find out more on why and how you can apply TLA+ to your canisters and dapps, including an in-depth guide to modeling canisters, refer to our series of blog posts ([1](https://medium.com/dfinity/eliminating-smart-contract-bugs-with-tla-e986aeb6da24), [2](https://medium.com/dfinity/weeding-out-the-bugs-with-tla-models-3606045bf24e), [3](https://mynosefroze.com/blog/2023-08-09-tla_for_canisters)). You can also look at the [DFINITY-produced TLA+ models](https://github.com/dfinity/formal-models) for examples and techniques. +To find out more on why and how you can apply TLA+ to your canisters and apps, including an in-depth guide to modeling canisters, refer to our series of blog posts ([1](https://medium.com/dfinity/eliminating-smart-contract-bugs-with-tla-e986aeb6da24), [2](https://medium.com/dfinity/weeding-out-the-bugs-with-tla-models-3606045bf24e), [3](https://mynosefroze.com/blog/2023-08-09-tla_for_canisters)). You can also look at the [DFINITY-produced TLA+ models](https://github.com/dfinity/formal-models) for examples and techniques. - + diff --git a/docs/guides/security/https-outcalls.md b/docs/guides/security/https-outcalls.md index 22e244b6..57ae423d 100644 --- a/docs/guides/security/https-outcalls.md +++ b/docs/guides/security/https-outcalls.md @@ -94,4 +94,4 @@ Perform input validation when using user-submitted data in the HTTPS outcalls. See the [OWASP Input Validation Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html) for more information. - + diff --git a/docs/guides/security/identity-and-access-management.mdx b/docs/guides/security/identity-and-access-management.mdx index a8a7f2b1..6a16cd98 100644 --- a/docs/guides/security/identity-and-access-management.mdx +++ b/docs/guides/security/identity-and-access-management.mdx @@ -111,17 +111,17 @@ A [short presentation](https://www.youtube.com/watch?v=iRmpCkzC6iI&t=1863s) can ### Security concern -Internet Identity has a standardized way for web applications to request authentication of a user. This [client authentication protocol](../../references/internet-identity-spec.md#client-authentication-protocol) allows a client dapp frontend to obtain a delegation signed by the Internet Identity for a locally generated session key pair. Using this delegation in combination with the session key allows the dapp frontend to make authenticated calls towards the backend canister. Such calls need to be digitally signed by the session private key. The IC will verify the signature and verify if there is a delegation (or chain of delegations) from the II key to the session public key. +Internet Identity has a standardized way for web applications to request authentication of a user. This [client authentication protocol](../../references/internet-identity-spec.md#client-authentication-protocol) allows a client app frontend to obtain a delegation signed by the Internet Identity for a locally generated session key pair. Using this delegation in combination with the session key allows the app frontend to make authenticated calls towards the backend canister. Such calls need to be digitally signed by the session private key. The IC will verify the signature and verify if there is a delegation (or chain of delegations) from the II key to the session public key. The II client authentication protocol leverages the browser's `postMessage` API to communicate between the client origin and the II origin. This protocol allows II to authenticate the origin of the authorization request using the hostname. :::note -As part of the client authentication protocol, a dapp can specify an alternative origin by following the [alternative frontend origins](../../references/internet-identity-spec.md#alternative-frontend-origins) requirements. +As part of the client authentication protocol, an app can specify an alternative origin by following the [alternative frontend origins](../../references/internet-identity-spec.md#alternative-frontend-origins) requirements. ::: -Upon successful authentication, II will return a delegation for the principal derived from the users' II for the specific frontend origin. This serves two purposes. First, a client dapp can't use this delegation on other dapps to impersonate the user. Second, multiple client dapps can't correlate user behavior across dapps, thereby reducing privacy. A dapp with a different frontend origin won't be able to request authentication for your dapp, which provides protection against certain phishing attacks. +Upon successful authentication, II will return a delegation for the principal derived from the users' II for the specific frontend origin. This serves two purposes. First, a client app can't use this delegation on other apps to impersonate the user. Second, multiple client apps can't correlate user behavior across apps, thereby reducing privacy. An app with a different frontend origin won't be able to request authentication for your app, which provides protection against certain phishing attacks. -When integrating a mobile application with II, the implementation is not straightforward since a mobile app can't call the `postMessage` API. It is tempting to create a simple "proxy" web frontend served by the dapp as shown in the sequence diagram below. The mobile application can load this proxy to complete the normal II authorization flow. Upon completion, this proxy web app provides the delegation back to the mobile app. +When integrating a mobile application with II, the implementation is not straightforward since a mobile app can't call the `postMessage` API. It is tempting to create a simple "proxy" web frontend served by the app as shown in the sequence diagram below. The mobile application can load this proxy to complete the normal II authorization flow. Upon completion, this proxy web app provides the delegation back to the mobile app. **Naive implementation sequence diagram:** ```mermaid @@ -164,7 +164,7 @@ sequenceDiagram However, without any precautions, this proxy would happily accept malicious requests to authenticate the user and might return the delegation back to an attacker. -Such an attack would start by phishing the user by means of a malicious mobile or web application. The user is asked to authenticate through II. However, instead of using II directly, the attacker abuses the open proxy to authenticate the user for the dapp, under which the vulnerable proxy is running. The attacker would generate a session key and ask the proxy to use the session public key in the II authentication protocol. Through this method, II issues a signed delegation for the user's II derived for the frontend origin of the proxy. This delegation could leak to the attacker, who can use it to impersonate the user. For example, if the attacker can trick the proxy to redirect to the malicious application (e.g., by registering Android deep links or iOS custom schemes), it could directly obtain the delegation. Furthermore, the delegation could leak through an insecure communication channel between the proxy and the mobile app or through observation of the IC state. +Such an attack would start by phishing the user by means of a malicious mobile or web application. The user is asked to authenticate through II. However, instead of using II directly, the attacker abuses the open proxy to authenticate the user for the app under which the vulnerable proxy is running. The attacker would generate a session key and ask the proxy to use the session public key in the II authentication protocol. Through this method, II issues a signed delegation for the user's II derived for the frontend origin of the proxy. This delegation could leak to the attacker, who can use it to impersonate the user. For example, if the attacker can trick the proxy to redirect to the malicious application (e.g., by registering Android deep links or iOS custom schemes), it could directly obtain the delegation. Furthermore, the delegation could leak through an insecure communication channel between the proxy and the mobile app or through observation of the IC state. The attack requires four conditions: 1. An attacker can provide a session key to be used in the II client authentication protocol. @@ -172,7 +172,7 @@ The attack requires four conditions: 3. The user completes the II authentication protocol. 4. The attacker can obtain the delegation, which is signed by the II canister. -Conditions 1, 2, and 3 can be satisfied by convincing the user to initiate an authentication flow with a session public key that is chosen by the attacker by loading the proxy from an attacker-controlled mobile or web application. Concretely, an attacker would execute a phishing attack where a victim is directed to the proxy from an unsuspicious application. For example, the victim is convinced that the attacker is issuing an airdrop. The victim has to download a corresponding malicious mobile app that requires II authentication. This malicious mobile app would load the proxy (step 3) similarly to how the legitimate mobile app would. The malicious app would ask the proxy to authenticate the user for an Condition 2 is met for any dapp that exposes such an open II authentication proxy on their domain. session key. The victim might not realize they are completing an authorization flow for a different dapp origin. +Conditions 1, 2, and 3 can be satisfied by convincing the user to initiate an authentication flow with a session public key that is chosen by the attacker by loading the proxy from an attacker-controlled mobile or web application. Concretely, an attacker would execute a phishing attack where a victim is directed to the proxy from an unsuspicious application. For example, the victim is convinced that the attacker is issuing an airdrop. The victim has to download a corresponding malicious mobile app that requires II authentication. This malicious mobile app would load the proxy (step 3) similarly to how the legitimate mobile app would. The malicious app would ask the proxy to authenticate the user for an attacker-chosen session key. Condition 2 is met for any app that exposes such an open II authentication proxy on their domain. The victim might not realize they are completing an authorization flow for a different app origin. Condition 4 can be satisfied by controlling a replica or boundary node that can observe the delegation in step 7. Alternatively, the delegation could leak in step 9 by using an HTTP GET parameter in a URI pointing to the IC. In such cases, if the mobile app that should receive the URI isn't installed, the browser loads the web app by making a request to the URI. Boundary and replica nodes would again receive the delegation as part of the URI. Condition 4 can also be met if the mobile app issues a request to the IC in step 11 without verifying the delegation obtained in step 9. @@ -236,7 +236,7 @@ MA -->> U: <> and [Android](https://developer.android.com/training/app-links/verify-android-applinks) documentation for details. * Return the delegation chain to the mobile app using a [URI fragment](https://www.w3.org/DesignIssues/Fragment.html) (everything following the # in the URI). The browser will load the URI if the mobile app linked to the app/universal link isn't installed on the mobile device. The benefit of URI fragments is that they are not included in the request to the server if the browser were to resolve the URI. A URL parameter or path would be included in such a request, and therefore it would leak the delegation chain to the proxy app backend (most likely the IC boundary and replica nodes). A URI fragment is still available to the mobile app for extraction. * Verify the delegation chain in the mobile application before using it in an IC message. The mobile application likely uses an agent that does not verify whether the session key generated in step 2 corresponds to the delegation found in the delegation chain returned in step 11. Using such an agent to make a signed update call would simply create a message with the provided delegation chain and sign it with a mismatching key. Obviously, the IC would reject such a message as the signature does not correspond to the delegation chain, but the delegation chain would already have leaked to the boundary and potentially replica nodes where an attacker could steal it. -* Optionally, the proxy frontend could explicitly warn the user that it is about to sign in with II for your dapp. It could include the dapp's name and logo. This might alarm the user who is being phished since the pretense used by the attacker would likely not match with the purpose of your dapp. For example, the attacker claims the authentication is required as part of an airdrop while you are running an unrelated decentralized exchange. When the proxy dapp is opened, the user would see your dapp's logo and abort the sign-in. +* Optionally, the proxy frontend could explicitly warn the user that it is about to sign in with II for your app. It could include the app's name and logo. This might alarm the user who is being phished since the pretense used by the attacker would likely not match with the purpose of your app. For example, the attacker claims the authentication is required as part of an airdrop while you are running an unrelated decentralized exchange. When the proxy app is opened, the user would see your app's logo and abort the sign-in. For more information, view an [example implementation in the form of a Unity app](https://github.com/dfinity/examples/tree/main/native-apps/unity_ii_deeplink). The following pieces of that codebase are most important: diff --git a/docs/guides/security/inter-canister-calls.md b/docs/guides/security/inter-canister-calls.md index 5863fce3..5bbfe9c9 100644 --- a/docs/guides/security/inter-canister-calls.md +++ b/docs/guides/security/inter-canister-calls.md @@ -339,4 +339,4 @@ Loops in the call graph (e.g., canister A calling B, B calling C, C calling A) m - For more information, see [current limitations of the Internet Computer](https://wiki.internetcomputer.org/wiki/Current_limitations_of_the_Internet_Computer), section "Loops in call graphs." - + diff --git a/docs/guides/security/miscellaneous.md b/docs/guides/security/miscellaneous.md index 792e7375..c0875bc0 100644 --- a/docs/guides/security/miscellaneous.md +++ b/docs/guides/security/miscellaneous.md @@ -154,7 +154,7 @@ fn random_bytes(size: u32) -> RandomBytesResult { #### Caveats: - The `setup_randomness` must **always** be initialized in both the `init` and `post_upgrade` hook as `init` [is not invoked during a canister upgrade](../../references/ic-interface-spec/canister-interface.md#system-api-upgrades). - The `init` and `post_upgrade` methods don't allow async calls, and thus a timer is immediately scheduled to seed the randomness. -- Once the seed is initialized, the outcome of all future `random_bytes` is predictable to anyone having the seed (node providers), as the PRNG is deterministic. This breaks the unpredictable property of secure randomness. Hence, to balance security vs. performance, we recommend frequently reseeding the PRNG on a timer. The example above already does this with a duration of **1 hour**. However, based on the sensitivity of their dapp, developers can choose an appropriate reseeding interval by setting `SEEDING_INTERVAL`. +- Once the seed is initialized, the outcome of all future `random_bytes` is predictable to anyone having the seed (node providers), as the PRNG is deterministic. This breaks the unpredictable property of secure randomness. Hence, to balance security vs. performance, we recommend frequently reseeding the PRNG on a timer. The example above already does this with a duration of **1 hour**. However, based on the sensitivity of their app, developers can choose an appropriate reseeding interval by setting `SEEDING_INTERVAL`. - The `random_bytes` must **always** be an `update` method, so the PRNG can preserve the state and offer unique randomness on every request. ## Verify that your canister doesn't export malicious endpoints @@ -277,4 +277,4 @@ Floats in Rust may behave unexpectedly. There can be undesirable loss of precisi Use [`rust_decimal::Decimal`](https://docs.rs/rust_decimal/latest/rust_decimal/) or [`num_rational::Ratio`](https://docs.rs/num-rational/latest/num_rational/). Decimal uses a fixed-point representation with base 10 denominators, and Ratio represents rational numbers. Both implement `checked_div` to handle division by zero, which is not available for floats. Numbers in common use, like 0.1 and 0.2, can be represented more intuitively with Decimal and can be represented exactly with Ratio. Rounding oddities like `0.1 + 0.2 != 0.3`, which happen with floats in Rust, do not arise with Decimal (see https://0.30000000000000004.com/ ). With Ratio, the desired precision can be made explicit. With either Decimal or Ratio, although one still has to manage precision, the above makes arithmetic easier to reason about. - + diff --git a/docs/guides/security/observability-and-monitoring.md b/docs/guides/security/observability-and-monitoring.md index 79477d58..d15e5cb0 100644 --- a/docs/guides/security/observability-and-monitoring.md +++ b/docs/guides/security/observability-and-monitoring.md @@ -19,4 +19,4 @@ Without monitoring, it can be hard to detect attacks or vulnerabilities that are - See [effective Rust canisters](https://mmapped.blog/posts/01-effective-rust-canisters.html) for general patterns on canister observability. - + diff --git a/docs/guides/security/overview.md b/docs/guides/security/overview.md index 1fbf3d31..1b568060 100644 --- a/docs/guides/security/overview.md +++ b/docs/guides/security/overview.md @@ -7,7 +7,7 @@ sidebar: This section provides security best practices for developing canisters and web apps served by canisters on ICP. These best practices are mostly inspired by issues found in security reviews. -The goal of these best practices is to enable developers to identify and address potential issues early during the development of new dapps, and not only in the end when (if at all) a security review is done. Ideally, this will make the development of secure dapps more efficient. +The goal of these best practices is to enable developers to identify and address potential issues early during the development of new apps, and not only in the end when (if at all) a security review is done. Ideally, this will make the development of secure apps more efficient. Some excellent canister best practices linked here are from [effective Rust canisters](https://mmapped.blog/posts/01-effective-rust-canisters.html) and [how to audit an ICP canister](https://www.joachim-breitner.de/blog/788-How_to_audit_an_Internet_Computer_canister). The relevant sections are linked in the individual best practices. @@ -17,11 +17,11 @@ The target audience for these documents is any developer working on ICP canister ## Disclaimers and limitations -The collection of best practices may grow over time. While it is useful to improve the security of dapps on ICP, such a list will never be complete and will never cover all potential security concerns. For example, there will always be attack vectors very specific to a dapp's use cases that cannot be covered by general best practices. Thus, following the best practices can complement, but not replace, security reviews. Especially for security-critical dapps, it is recommended to perform security reviews or audits. Furthermore, please note that the best practices are currently not ordered according to risk or priority. +The collection of best practices may grow over time. While it is useful to improve the security of apps on ICP, such a list will never be complete and will never cover all potential security concerns. For example, there will always be attack vectors very specific to an app's use cases that cannot be covered by general best practices. Thus, following the best practices can complement, but not replace, security reviews. Especially for security-critical apps, it is recommended to perform security reviews or audits. Furthermore, please note that the best practices are currently not ordered according to risk or priority. ## Further reading -Below are resources covering security best practices for technologies commonly used in ICP dapps. These are equally important as the ICP-specific guidelines and should be studied carefully. +Below are resources covering security best practices for technologies commonly used in ICP apps. These are equally important as the ICP-specific guidelines and should be studied carefully. ### General * [How to audit an Internet Computer canister](https://www.joachim-breitner.de/blog/788-How_to_audit_an_Internet_Computer_canister) by Joachim Breitner @@ -51,4 +51,4 @@ Below are resources covering security best practices for technologies commonly u * In [effective Rust canisters](https://mmapped.blog/posts/01-effective-rust-canisters.html): [test upgrades](https://mmapped.blog/posts/01-effective-rust-canisters.html#test-upgrades), [make code target-independent](https://mmapped.blog/posts/01-effective-rust-canisters.html#target-independent) * Consider [PocketIC](../testing/pocket-ic.md) for canister testing - + From 07800dd978b6b1b661e3acc77e34e90278983c48 Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Mon, 11 May 2026 15:27:30 +0200 Subject: [PATCH 2/6] fix(security): replace DAO with community governance in decentralization.md Aligns with wording convention established in PR #208 (SNS framework page), which avoids "DAO" in prose and uses "community-governed" constructions instead. - "Full decentralization using a DAO" heading -> "Full community governance" - "DAO evolves" link text -> "community governance evolves" - "building your own DAO" -> "building your own governance system" - "alternative to DAO control" -> "alternative to community governance" - "implement a DAO from scratch" -> "implement a custom governance canister" - "basic DAO example" link text -> "basic governance example" - "the DAO is controlled by itself" -> "the governance canister is controlled by itself" --- docs/guides/security/decentralization.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/guides/security/decentralization.md b/docs/guides/security/decentralization.md index 36044030..0ce22d1a 100644 --- a/docs/guides/security/decentralization.md +++ b/docs/guides/security/decentralization.md @@ -28,20 +28,20 @@ In the following list, we first provide recommendations for centralized canister - Require approval by several individuals or parties to perform any canister controller operations. - Require approval by several individuals or parties for any security-sensitive changes at the application level that are restricted to privileged principals, such as admin operations including permissions management, minting new tokens, removing NFTs for digital rights violations, etc. - A helpful tool to achieve either of the above two points is the [orbit station canister](https://github.com/dfinity/orbit) which allows you to configure intricate policies for canister control. [Orbit](https://orbit.global/) also serves as an enterprise wallet where token funds are governed using policies. Ideally, individuals also manage their key material using hardware security modules, such as [YubiHSM](https://www.yubico.com/ch/store/yubihsm-2-series/) and physically protect these through methods such as using safes at different geographical locations. Some of HSMs support threshold signature schemes, which can help to further secure the setup. To increase transparency about the changes made to an app, consider using a tool like [LaunchTrail](https://github.com/spinner-cash/launchtrail). -3. **Full decentralization using a DAO**: The app is controlled by a decentralized governance system such as ICP's [Service Nervous System (SNS)](https://learn.internetcomputer.org/hc/en-us/articles/34084394684564-SNS-Service-Nervous-System), so that any security-sensitive changes to the canisters are only executed if the SNS community approves them collectively through a proposal voting mechanism. If an SNS is used: - - Make sure voting power is distributed over many independent entities such that there is not one single or a few entities that can decide by themselves how the [DAO evolves](https://learn.internetcomputer.org/hc/en-us/articles/34088279488660-Tokenomics#voting-power-and-decentralization). +3. **Full community governance**: The app is controlled by a decentralized governance system such as ICP's [Service Nervous System (SNS)](https://learn.internetcomputer.org/hc/en-us/articles/34084394684564-SNS-Service-Nervous-System), so that any security-sensitive changes to the canisters are only executed if the SNS community approves them collectively through a proposal voting mechanism. If an SNS is used: + - Make sure voting power is distributed over many independent entities such that there is not one single or a few entities that can decide by themselves how the [community governance evolves](https://learn.internetcomputer.org/hc/en-us/articles/34088279488660-Tokenomics#voting-power-and-decentralization). - Ensure all components of the app are under SNS control, including the canisters serving the web frontends; see [SNS asset canisters](../governance/managing.md). - Consider the [SNS preparation checklist](../governance/launching.md). Important points from a security perspective are tokenomics, disclosing dependencies to off-chain components, and performing security reviews. - - Rather than self-deploying the SNS code or building your own DAO, consider using the official SNS on the SNS subnet, as this guarantees that the SNS is running an NNS-blessed version and maintained as part of ICP. + - Rather than self-deploying the SNS code or building your own governance system, consider using the official SNS on the SNS subnet, as this guarantees that the SNS is running an NNS-blessed version and maintained as part of ICP. - See also [verification and trust in a (launched) SNS](https://wiki.internetcomputer.org/wiki/Verification_and_trust_in_a_(launched)_SNS) and [SNS decentralization swap trust](https://wiki.internetcomputer.org/wiki/SNS_decentralization_swap_trust). -An alternative to DAO control (3. above) would be to create an immutable canister by removing the canister controller completely. This can be achieved by setting the controller to a [black hole canister](https://github.com/ninegua/ic-blackhole). However, note that this implies that the canister can **never** be upgraded, which may have severe implications in case a bug is found. The complexity of ICP apps and the fact that complex frontends are hosted onchain means that black holed canisters are rarely the right solution. The option to use a decentralized governance system and thus being able to upgrade canisters is a big advantage of the ICP ecosystem compared to other chains. +An alternative to community governance (3. above) would be to create an immutable canister by removing the canister controller completely. This can be achieved by setting the controller to a [black hole canister](https://github.com/ninegua/ic-blackhole). However, note that this implies that the canister can **never** be upgraded, which may have severe implications in case a bug is found. The complexity of ICP apps and the fact that complex frontends are hosted onchain means that black holed canisters are rarely the right solution. The option to use a decentralized governance system and thus being able to upgrade canisters is a big advantage of the ICP ecosystem compared to other chains. :::note Contrary to some other chains, immutable canisters need cycles to run, and they can receive cycles. ::: -It is also possible to implement a DAO on ICP from scratch. If you decide to do this (e.g., along the lines of the [basic DAO example](https://github.com/dfinity/examples/tree/master/rust/basic_dao)), be aware that this is security critical and must be security reviewed carefully. Furthermore, users will need to verify that the DAO is controlled by itself. +It is also possible to implement a custom governance canister on ICP from scratch. If you decide to do this (e.g., along the lines of the [basic governance example](https://github.com/dfinity/examples/tree/master/rust/basic_dao)), be aware that this is security critical and must be security reviewed carefully. Furthermore, users will need to verify that the governance canister is controlled by itself. ## Verify the control and trust level of canisters you depend on From 1d1eeea71106861ae4329ad937f4ad9bd0cdf22d Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Mon, 11 May 2026 15:28:02 +0200 Subject: [PATCH 3/6] fix(security): replace "decentralized governance system" with "governance framework" --- docs/guides/security/decentralization.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/guides/security/decentralization.md b/docs/guides/security/decentralization.md index 0ce22d1a..10e6c669 100644 --- a/docs/guides/security/decentralization.md +++ b/docs/guides/security/decentralization.md @@ -5,7 +5,7 @@ sidebar: order: 10 --- -## Use a decentralized governance system such as the SNS to control your canisters +## Use a governance framework such as the SNS to control your canisters ### Security concerns @@ -28,14 +28,14 @@ In the following list, we first provide recommendations for centralized canister - Require approval by several individuals or parties to perform any canister controller operations. - Require approval by several individuals or parties for any security-sensitive changes at the application level that are restricted to privileged principals, such as admin operations including permissions management, minting new tokens, removing NFTs for digital rights violations, etc. - A helpful tool to achieve either of the above two points is the [orbit station canister](https://github.com/dfinity/orbit) which allows you to configure intricate policies for canister control. [Orbit](https://orbit.global/) also serves as an enterprise wallet where token funds are governed using policies. Ideally, individuals also manage their key material using hardware security modules, such as [YubiHSM](https://www.yubico.com/ch/store/yubihsm-2-series/) and physically protect these through methods such as using safes at different geographical locations. Some of HSMs support threshold signature schemes, which can help to further secure the setup. To increase transparency about the changes made to an app, consider using a tool like [LaunchTrail](https://github.com/spinner-cash/launchtrail). -3. **Full community governance**: The app is controlled by a decentralized governance system such as ICP's [Service Nervous System (SNS)](https://learn.internetcomputer.org/hc/en-us/articles/34084394684564-SNS-Service-Nervous-System), so that any security-sensitive changes to the canisters are only executed if the SNS community approves them collectively through a proposal voting mechanism. If an SNS is used: +3. **Full community governance**: The app is controlled by a governance framework such as ICP's [Service Nervous System (SNS)](https://learn.internetcomputer.org/hc/en-us/articles/34084394684564-SNS-Service-Nervous-System), so that any security-sensitive changes to the canisters are only executed if the SNS community approves them collectively through a proposal voting mechanism. If an SNS is used: - Make sure voting power is distributed over many independent entities such that there is not one single or a few entities that can decide by themselves how the [community governance evolves](https://learn.internetcomputer.org/hc/en-us/articles/34088279488660-Tokenomics#voting-power-and-decentralization). - Ensure all components of the app are under SNS control, including the canisters serving the web frontends; see [SNS asset canisters](../governance/managing.md). - Consider the [SNS preparation checklist](../governance/launching.md). Important points from a security perspective are tokenomics, disclosing dependencies to off-chain components, and performing security reviews. - Rather than self-deploying the SNS code or building your own governance system, consider using the official SNS on the SNS subnet, as this guarantees that the SNS is running an NNS-blessed version and maintained as part of ICP. - See also [verification and trust in a (launched) SNS](https://wiki.internetcomputer.org/wiki/Verification_and_trust_in_a_(launched)_SNS) and [SNS decentralization swap trust](https://wiki.internetcomputer.org/wiki/SNS_decentralization_swap_trust). -An alternative to community governance (3. above) would be to create an immutable canister by removing the canister controller completely. This can be achieved by setting the controller to a [black hole canister](https://github.com/ninegua/ic-blackhole). However, note that this implies that the canister can **never** be upgraded, which may have severe implications in case a bug is found. The complexity of ICP apps and the fact that complex frontends are hosted onchain means that black holed canisters are rarely the right solution. The option to use a decentralized governance system and thus being able to upgrade canisters is a big advantage of the ICP ecosystem compared to other chains. +An alternative to community governance (3. above) would be to create an immutable canister by removing the canister controller completely. This can be achieved by setting the controller to a [black hole canister](https://github.com/ninegua/ic-blackhole). However, note that this implies that the canister can **never** be upgraded, which may have severe implications in case a bug is found. The complexity of ICP apps and the fact that complex frontends are hosted onchain means that black holed canisters are rarely the right solution. The option to use a governance framework and thus being able to upgrade canisters is a big advantage of the ICP ecosystem compared to other chains. :::note Contrary to some other chains, immutable canisters need cycles to run, and they can receive cycles. @@ -48,12 +48,12 @@ It is also possible to implement a custom governance canister on ICP from scratc ### Security concern If your app depends on a third-party canister (e.g., by making inter-canister calls to it), it is important to verify that the callee satisfies an appropriate level of decentralization. For example: -- If funds or cycles are transferred to a third-party canister, one might require the canister to be controlled by a decentralized governance system, as otherwise these funds are centrally controlled. +- If funds or cycles are transferred to a third-party canister, one might require the canister to be controlled by a governance framework, as otherwise these funds are centrally controlled. - If inter-canister calls are made to a centrally controlled and potentially malicious canister, that canister could execute a denial of service attack on the caller or even trigger functional bugs; see [be aware of the risks involved in calling untrustworthy canisters](./inter-canister-calls.md#be-aware-of-the-risks-involved-in-calling-untrustworthy-canisters). ### Recommendation -If you interact with a canister that you require to be decentralized, make sure it is controlled by the NNS, a service nervous system (SNS) or a decentralized governance system, and review under what conditions and by whom the canister can be changed. +If you interact with a canister that you require to be decentralized, make sure it is controlled by the NNS, a service nervous system (SNS) or a governance framework, and review under what conditions and by whom the canister can be changed. ## Don't load JavaScript or other assets from untrusted domains From c076ef59dfba054c31e57588b458a8ba87b85d31 Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Mon, 11 May 2026 15:29:23 +0200 Subject: [PATCH 4/6] fix(security): correct composite_query description to "query methods" not "query call" --- docs/guides/security/data-integrity-and-authenticity.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/security/data-integrity-and-authenticity.md b/docs/guides/security/data-integrity-and-authenticity.md index 4b8e1fec..dbf3b64b 100644 --- a/docs/guides/security/data-integrity-and-authenticity.md +++ b/docs/guides/security/data-integrity-and-authenticity.md @@ -9,7 +9,7 @@ sidebar: ### Security concern -ICP offers three modes of operation for canisters: `update`, `query`, and `composite_query`. For simplicity, this guide treats `composite_query` as a query call for the rest of this section. +ICP offers three modes of operation for canisters: `update`, `query`, and `composite_query`. For simplicity, this guide treats `composite_query` methods as query methods for the rest of this section. Update calls are slow and expensive but provide integrity guarantees as their responses include a threshold signature signed by the subnet. From 5fc447e01fd26f0ef8701cfec5ac4e3722ce7f7d Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Mon, 11 May 2026 15:32:21 +0200 Subject: [PATCH 5/6] fix(security): off-chain -> offchain, avoid onchain where possible --- docs/guides/security/decentralization.md | 8 ++++---- docs/guides/security/observability-and-monitoring.md | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/guides/security/decentralization.md b/docs/guides/security/decentralization.md index 10e6c669..90d2cfd5 100644 --- a/docs/guides/security/decentralization.md +++ b/docs/guides/security/decentralization.md @@ -17,13 +17,13 @@ Dapps are commonly reachable over their own custom domain name instead of ic0.ap An app might have privileged features that are only accessible to principals that are on an allow list. For example, minting new tokens, debugging functions, managing permissions, removing NFTs for digital rights violations, etc. This means that whoever controls that principal (such as the app developers) may have central control over these privileged features. -For performance or privacy reasons, some components of an app may be hosted off-chain. These off-chain components often control principals used to interact with the onchain components and are usually controlled by a developer holding credentials to the off-chain cloud environment. On top of that, third party off-chain entities such as cloud providers can inspect and manipulate data in this environment if they choose. They could take ICP principal private keys out of this environment and call privileged operations on the canisters. Off-chain components can quickly lead to many additional centrally trusted parties. Depending on the value managed by an app, these parties could be tempted to act maliciously. +For performance or privacy reasons, some components of an app may be hosted offchain. These offchain components often control principals used to interact with the canisters and are usually controlled by a developer holding credentials to the offchain cloud environment. On top of that, third party offchain entities such as cloud providers can inspect and manipulate data in this environment if they choose. They could take ICP principal private keys out of this environment and call privileged operations on the canisters. Offchain components can quickly lead to many additional centrally trusted parties. Depending on the value managed by an app, these parties could be tempted to act maliciously. ### Recommendations In the following list, we first provide recommendations for centralized canister control and then move to recommendations for increasingly decentralized settings. From a security perspective, more decentralization is favorable. The following list could also be used as a basis for assessing an app's level of decentralization. This is just a set of recommendations and may be incomplete. -1. **The app uses central, off-chain components:** The application makes use of centralized components such as those running in the cloud. The owners of these cloud services have full control over the application and assets managed by it. Your application should likely be further decentralized by avoiding central components. But while you have them, [securely manage your keys in the cloud](https://cloudsecurityalliance.org/research/topics/cloud-key-management/). +1. **The app uses central, offchain components:** The application makes use of centralized components such as those running in the cloud. The owners of these cloud services have full control over the application and assets managed by it. Your application should likely be further decentralized by avoiding central components. But while you have them, [securely manage your keys in the cloud](https://cloudsecurityalliance.org/research/topics/cloud-key-management/). 2. **The app is controlled by the developer team:** Your project is not under decentralized control, for example, because it is in an early development stage or does not (yet) hold significant funds. In that case, it is recommended to manage access to your canisters securely and ideally not let individuals control the application. To achieve that, consider the following: - Require approval by several individuals or parties to perform any canister controller operations. - Require approval by several individuals or parties for any security-sensitive changes at the application level that are restricted to privileged principals, such as admin operations including permissions management, minting new tokens, removing NFTs for digital rights violations, etc. @@ -31,11 +31,11 @@ In the following list, we first provide recommendations for centralized canister 3. **Full community governance**: The app is controlled by a governance framework such as ICP's [Service Nervous System (SNS)](https://learn.internetcomputer.org/hc/en-us/articles/34084394684564-SNS-Service-Nervous-System), so that any security-sensitive changes to the canisters are only executed if the SNS community approves them collectively through a proposal voting mechanism. If an SNS is used: - Make sure voting power is distributed over many independent entities such that there is not one single or a few entities that can decide by themselves how the [community governance evolves](https://learn.internetcomputer.org/hc/en-us/articles/34088279488660-Tokenomics#voting-power-and-decentralization). - Ensure all components of the app are under SNS control, including the canisters serving the web frontends; see [SNS asset canisters](../governance/managing.md). - - Consider the [SNS preparation checklist](../governance/launching.md). Important points from a security perspective are tokenomics, disclosing dependencies to off-chain components, and performing security reviews. + - Consider the [SNS preparation checklist](../governance/launching.md). Important points from a security perspective are tokenomics, disclosing dependencies to offchain components, and performing security reviews. - Rather than self-deploying the SNS code or building your own governance system, consider using the official SNS on the SNS subnet, as this guarantees that the SNS is running an NNS-blessed version and maintained as part of ICP. - See also [verification and trust in a (launched) SNS](https://wiki.internetcomputer.org/wiki/Verification_and_trust_in_a_(launched)_SNS) and [SNS decentralization swap trust](https://wiki.internetcomputer.org/wiki/SNS_decentralization_swap_trust). -An alternative to community governance (3. above) would be to create an immutable canister by removing the canister controller completely. This can be achieved by setting the controller to a [black hole canister](https://github.com/ninegua/ic-blackhole). However, note that this implies that the canister can **never** be upgraded, which may have severe implications in case a bug is found. The complexity of ICP apps and the fact that complex frontends are hosted onchain means that black holed canisters are rarely the right solution. The option to use a governance framework and thus being able to upgrade canisters is a big advantage of the ICP ecosystem compared to other chains. +An alternative to community governance (3. above) would be to create an immutable canister by removing the canister controller completely. This can be achieved by setting the controller to a [black hole canister](https://github.com/ninegua/ic-blackhole). However, note that this implies that the canister can **never** be upgraded, which may have severe implications in case a bug is found. The complexity of ICP apps and the fact that complex frontends are hosted as canisters means that black holed canisters are rarely the right solution. The option to use a governance framework and thus being able to upgrade canisters is a big advantage of the ICP ecosystem compared to other chains. :::note Contrary to some other chains, immutable canisters need cycles to run, and they can receive cycles. diff --git a/docs/guides/security/observability-and-monitoring.md b/docs/guides/security/observability-and-monitoring.md index d15e5cb0..11af5747 100644 --- a/docs/guides/security/observability-and-monitoring.md +++ b/docs/guides/security/observability-and-monitoring.md @@ -15,7 +15,7 @@ Without monitoring, it can be hard to detect attacks or vulnerabilities that are - Monitor your canister's cycles balance regularly, set up alerts for sudden changes in cycles consumption, and add an endpoint to expose health indicators. See the [DoS prevention best practices](./dos-prevention.md) for more context on cycles monitoring. -- Consider emitting logs for security-relevant events (e.g., access control failures, unexpected state transitions). Since logs are stored on-chain, they provide a tamper-resistant audit trail. +- Consider emitting logs for security-relevant events (e.g., access control failures, unexpected state transitions). Since logs are stored in the canister, they provide a tamper-resistant audit trail. - See [effective Rust canisters](https://mmapped.blog/posts/01-effective-rust-canisters.html) for general patterns on canister observability. From 88e73d622b2e56a1c54233bf579e24885124f4ac Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Mon, 11 May 2026 15:37:02 +0200 Subject: [PATCH 6/6] fix(security): remove onchain/offchain labels; tamper-resistant -> tamperproof Per updated brand voice rules: - offchain components -> external components/infrastructure (decentralization.md) - tamper-resistant -> tamperproof (observability-and-monitoring.md) --- docs/guides/security/decentralization.md | 6 +++--- docs/guides/security/observability-and-monitoring.md | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/guides/security/decentralization.md b/docs/guides/security/decentralization.md index 90d2cfd5..307550fb 100644 --- a/docs/guides/security/decentralization.md +++ b/docs/guides/security/decentralization.md @@ -17,13 +17,13 @@ Dapps are commonly reachable over their own custom domain name instead of ic0.ap An app might have privileged features that are only accessible to principals that are on an allow list. For example, minting new tokens, debugging functions, managing permissions, removing NFTs for digital rights violations, etc. This means that whoever controls that principal (such as the app developers) may have central control over these privileged features. -For performance or privacy reasons, some components of an app may be hosted offchain. These offchain components often control principals used to interact with the canisters and are usually controlled by a developer holding credentials to the offchain cloud environment. On top of that, third party offchain entities such as cloud providers can inspect and manipulate data in this environment if they choose. They could take ICP principal private keys out of this environment and call privileged operations on the canisters. Offchain components can quickly lead to many additional centrally trusted parties. Depending on the value managed by an app, these parties could be tempted to act maliciously. +For performance or privacy reasons, some components of an app may be hosted on external infrastructure. These external components often control principals used to interact with the canisters and are usually controlled by a developer holding credentials to the cloud environment. On top of that, third parties such as cloud providers can inspect and manipulate data in this environment if they choose. They could take ICP principal private keys out of this environment and call privileged operations on the canisters. External components can quickly lead to many additional centrally trusted parties. Depending on the value managed by an app, these parties could be tempted to act maliciously. ### Recommendations In the following list, we first provide recommendations for centralized canister control and then move to recommendations for increasingly decentralized settings. From a security perspective, more decentralization is favorable. The following list could also be used as a basis for assessing an app's level of decentralization. This is just a set of recommendations and may be incomplete. -1. **The app uses central, offchain components:** The application makes use of centralized components such as those running in the cloud. The owners of these cloud services have full control over the application and assets managed by it. Your application should likely be further decentralized by avoiding central components. But while you have them, [securely manage your keys in the cloud](https://cloudsecurityalliance.org/research/topics/cloud-key-management/). +1. **The app uses central, external components:** The application makes use of centralized components such as those running in the cloud. The owners of these cloud services have full control over the application and assets managed by it. Your application should likely be further decentralized by avoiding central components. But while you have them, [securely manage your keys in the cloud](https://cloudsecurityalliance.org/research/topics/cloud-key-management/). 2. **The app is controlled by the developer team:** Your project is not under decentralized control, for example, because it is in an early development stage or does not (yet) hold significant funds. In that case, it is recommended to manage access to your canisters securely and ideally not let individuals control the application. To achieve that, consider the following: - Require approval by several individuals or parties to perform any canister controller operations. - Require approval by several individuals or parties for any security-sensitive changes at the application level that are restricted to privileged principals, such as admin operations including permissions management, minting new tokens, removing NFTs for digital rights violations, etc. @@ -31,7 +31,7 @@ In the following list, we first provide recommendations for centralized canister 3. **Full community governance**: The app is controlled by a governance framework such as ICP's [Service Nervous System (SNS)](https://learn.internetcomputer.org/hc/en-us/articles/34084394684564-SNS-Service-Nervous-System), so that any security-sensitive changes to the canisters are only executed if the SNS community approves them collectively through a proposal voting mechanism. If an SNS is used: - Make sure voting power is distributed over many independent entities such that there is not one single or a few entities that can decide by themselves how the [community governance evolves](https://learn.internetcomputer.org/hc/en-us/articles/34088279488660-Tokenomics#voting-power-and-decentralization). - Ensure all components of the app are under SNS control, including the canisters serving the web frontends; see [SNS asset canisters](../governance/managing.md). - - Consider the [SNS preparation checklist](../governance/launching.md). Important points from a security perspective are tokenomics, disclosing dependencies to offchain components, and performing security reviews. + - Consider the [SNS preparation checklist](../governance/launching.md). Important points from a security perspective are tokenomics, disclosing dependencies to external components, and performing security reviews. - Rather than self-deploying the SNS code or building your own governance system, consider using the official SNS on the SNS subnet, as this guarantees that the SNS is running an NNS-blessed version and maintained as part of ICP. - See also [verification and trust in a (launched) SNS](https://wiki.internetcomputer.org/wiki/Verification_and_trust_in_a_(launched)_SNS) and [SNS decentralization swap trust](https://wiki.internetcomputer.org/wiki/SNS_decentralization_swap_trust). diff --git a/docs/guides/security/observability-and-monitoring.md b/docs/guides/security/observability-and-monitoring.md index 11af5747..c67b684a 100644 --- a/docs/guides/security/observability-and-monitoring.md +++ b/docs/guides/security/observability-and-monitoring.md @@ -15,7 +15,7 @@ Without monitoring, it can be hard to detect attacks or vulnerabilities that are - Monitor your canister's cycles balance regularly, set up alerts for sudden changes in cycles consumption, and add an endpoint to expose health indicators. See the [DoS prevention best practices](./dos-prevention.md) for more context on cycles monitoring. -- Consider emitting logs for security-relevant events (e.g., access control failures, unexpected state transitions). Since logs are stored in the canister, they provide a tamper-resistant audit trail. +- Consider emitting logs for security-relevant events (e.g., access control failures, unexpected state transitions). Since logs are stored in the canister, they provide a tamperproof audit trail. - See [effective Rust canisters](https://mmapped.blog/posts/01-effective-rust-canisters.html) for general patterns on canister observability.