You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/content/ccip/concepts/architecture/onchain/aptos/components.mdx
+6Lines changed: 6 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -175,3 +175,9 @@ The `ccip::receiver_registry` is a module where developers can register their cu
175
175
## RMN (Risk Management Network) Remote
176
176
177
177
The `ccip::rmn_remote` module is a critical security component deployed on every CCIP-enabled chain. Various CCIP modules (like `OnRamp`, `OffRamp`, `Token Pools`) query this component to verify the status of other chains in the network. It maintains an onchain list of "cursed" (i.e., blocklisted) chains. If a source or destination chain is cursed, CCIP transactions involving that chain are halted.
178
+
179
+
<Asidetype="note">
180
+
Based on user demand, CCIP's architecture is evolving to provide enhanced support for modular security and
181
+
configurable compliance capabilities. As part of this transition, the Risk Management Network is being adapted to
182
+
align with this broader, more flexible architecture.
Copy file name to clipboardExpand all lines: src/content/ccip/concepts/architecture/onchain/evm/components.mdx
+6Lines changed: 6 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -180,3 +180,9 @@ The RMN Contract is deployed on every chain where CCIP is integrated. Its key fu
180
180
1.**Cursing Mechanism**
181
181
-**Curse Initiation**: When the CCIP Owner manually initiates a curse, the `curse()` function is invoked to mark the appropriate subjects as cursed.
182
182
-**Curse Detection**: Onchain components (such as the Router, OnRamp, OffRamp, and TokenPool) call the `isCursed()` function on the RMNRemote contract to detect global curses or curses targeting a remote chain.
183
+
184
+
<Asidetype="note">
185
+
Based on user demand, CCIP's architecture is evolving to provide enhanced support for modular security and
186
+
configurable compliance capabilities. As part of this transition, the Risk Management Network is being adapted to
187
+
align with this broader, more flexible architecture.
Copy file name to clipboardExpand all lines: src/content/ccip/concepts/architecture/onchain/svm/components.mdx
+4-6Lines changed: 4 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -201,10 +201,8 @@ The Risk Management Network (RMN) adds an additional security layer to CCIP by m
201
201
- Once cursed, any CCIP transaction that performs the verification check for that chain selector (or the global curse) will revert, preventing cross-chain message processing.
202
202
- The owner calls `uncurse` to lift the curse when the threat is resolved, restoring normal CCIP operations.
203
203
204
-
<Asidetype="caution"title="Phased Deployments">
205
-
Certain blockchains may be integrated with CCIP in a phased approach, with the Committing and Executing DONs deployed
206
-
first and the Risk Management Network added in a later update. In cases of a phased deployment, merkle roots in
207
-
relevant Commit Stores are always considered blessed until the Risk Management Network has been deployed for that
208
-
blockchain. Please see the [CCIP Directory](/ccip/directory) for which integrations utilize a phased approach. Please
209
-
review [CCIP Service Responsibility](/ccip/service-responsibility) for more information.
204
+
<Asidetype="note">
205
+
Based on user demand, CCIP's architecture is evolving to provide enhanced support for modular security and
206
+
configurable compliance capabilities. As part of this transition, the Risk Management Network is being adapted to
207
+
align with this broader, more flexible architecture.
Copy file name to clipboardExpand all lines: src/content/ccip/llms-full.txt
+16-6Lines changed: 16 additions & 6 deletions
Original file line number
Diff line number
Diff line change
@@ -1527,6 +1527,12 @@ The RMN Contract is deployed on every chain where CCIP is integrated. Its key fu
1527
1527
- **Curse Initiation**: When the CCIP Owner manually initiates a curse, the `curse()` function is invoked to mark the appropriate subjects as cursed.
1528
1528
- **Curse Detection**: Onchain components (such as the Router, OnRamp, OffRamp, and TokenPool) call the `isCursed()` function on the RMNRemote contract to detect global curses or curses targeting a remote chain.
1529
1529
1530
+
<Aside type="note">
1531
+
Based on user demand, CCIP's architecture is evolving to provide enhanced support for modular security and
1532
+
configurable compliance capabilities. As part of this transition, the Risk Management Network is being adapted to
1533
+
align with this broader, more flexible architecture.
1534
+
</Aside>
1535
+
1530
1536
---
1531
1537
1532
1538
# Onchain Architecture - Upgradability (EVM)
@@ -1915,12 +1921,10 @@ The Risk Management Network (RMN) adds an additional security layer to CCIP by m
1915
1921
- Once cursed, any CCIP transaction that performs the verification check for that chain selector (or the global curse) will revert, preventing cross-chain message processing.
1916
1922
- The owner calls `uncurse` to lift the curse when the threat is resolved, restoring normal CCIP operations.
1917
1923
1918
-
<Aside type="caution" title="Phased Deployments">
1919
-
Certain blockchains may be integrated with CCIP in a phased approach, with the Committing and Executing DONs deployed
1920
-
first and the Risk Management Network added in a later update. In cases of a phased deployment, merkle roots in
1921
-
relevant Commit Stores are always considered blessed until the Risk Management Network has been deployed for that
1922
-
blockchain. Please see the [CCIP Directory](/ccip/directory) for which integrations utilize a phased approach. Please
1923
-
review [CCIP Service Responsibility](/ccip/service-responsibility) for more information.
1924
+
<Aside type="note">
1925
+
Based on user demand, CCIP's architecture is evolving to provide enhanced support for modular security and
1926
+
configurable compliance capabilities. As part of this transition, the Risk Management Network is being adapted to
1927
+
align with this broader, more flexible architecture.
1924
1928
</Aside>
1925
1929
1926
1930
---
@@ -2249,6 +2253,12 @@ The `ccip::receiver_registry` is a module where developers can register their cu
2249
2253
2250
2254
The `ccip::rmn_remote` module is a critical security component deployed on every CCIP-enabled chain. Various CCIP modules (like `OnRamp`, `OffRamp`, `Token Pools`) query this component to verify the status of other chains in the network. It maintains an onchain list of "cursed" (i.e., blocklisted) chains. If a source or destination chain is cursed, CCIP transactions involving that chain are halted.
2251
2255
2256
+
<Aside type="note">
2257
+
Based on user demand, CCIP's architecture is evolving to provide enhanced support for modular security and
2258
+
configurable compliance capabilities. As part of this transition, the Risk Management Network is being adapted to
2259
+
align with this broader, more flexible architecture.
Copy file name to clipboardExpand all lines: src/content/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts.mdx
+165-4Lines changed: 165 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -525,13 +525,170 @@ The deployment and configuration process involves these steps:
525
525
While the `setForwarderAddress()` function allows updating to `address(0)`, this disables the critical security check and allows **anyone** to call your `onReport()` function with arbitrary data. The function emits a `SecurityWarning` event if you attempt this. Only use `address(0)` for testing if you fully understand the implications.
526
526
</Aside>
527
527
528
-
### Replay protection
528
+
### Replay attacks
529
529
530
-
The `KeystoneForwarder` contract includes built-in replay protection that prevents successful reports from being executed multiple times. By requiring the forwarder address at construction time, `ReceiverTemplate` ensures your consumer benefits from this protection automatically.
530
+
CRE reports carry DON signatures that any compatible `KeystoneForwarder` will accept. This creates two distinct replay vectors that workflow authors must explicitly protect against by embedding protective metadata in their report payloads and verifying it in their consumer contracts.
531
+
532
+
#### Cross-chain replay
533
+
534
+
**The risk**: While publishing a single signed report to multiple chains simultaneously enables patterns like [Proof of Reserve (PoR)](/data-feeds/smartdata#proof-of-reserve-feeds) or feed-style publish-once-post-many, it also means **anyone holding a valid report can replay it on any chain that recognizes the DON's signing keys**.
535
+
536
+
The forwarder validates cryptographic signatures but those signatures do not commit to a specific chain—without additional protection in your consumer contract, a replayed report can land on an unintended chain.
**The mitigation**: Embed the target chain selector in the report payload. The consumer contract decodes this value and rejects reports not intended for the current chain. Chain selectors are `uint64` identifiers used throughout the CRE platform to identify blockchain networks — see [Chain Selectors](/cre/reference/sdk/evm-client-ts#chain-selectors) for the full list of constants and the `ChainSelectorFromName` helper.
544
+
545
+
**Workflow (embed chain selector in the report payload):**
546
+
547
+
```go
548
+
// Define your report struct with a ChainSelector field.
549
+
// ChainSelector is a uint64 — the same type used when instantiating evm.Client.
550
+
typePaymentReportstruct {
551
+
Recipient common.Address
552
+
Amount *big.Int
553
+
ChainSelectoruint64// Target chain — used by the consumer to reject cross-chain replays
**The risk**: While allowing failed deliveries to be retried without requiring a new signed report enables permissionless recovery from transient failures, it also means the forwarder does not mark reverted transmissions as used.
607
+
608
+
**A malicious actor can exploit this window**: after your workflow has already reacted to a failure (for example, scheduled a corrective action), an attacker can replay the original signed report once conditions recover, causing double-execution.
609
+
610
+
<ClickToZoomsrc="/images/cre/same-chain-replay-on-failure.png"alt="Same-chain replay on failure diagram" />
1. A cron workflow attempts to pay a wallet $100 USDC. The consumer contract **reverts** (insufficient funds).
615
+
1. CRE returns a reverted transaction hash. The workflow records the failure and plans to correct the balance on the next run.
616
+
1. Funds are replenished — by the owner, another workflow, or a user deposit.
617
+
1. An attacker (or a bot) replays the original signed report. The consumer now has funds and the payment **executes again** — the recipient is paid twice.
618
+
</Aside>
619
+
620
+
**The mitigation**: Embed the scheduled execution timestamp in the report payload. The consumer contract stores the last accepted timestamp and rejects any report with a timestamp equal to or earlier than the stored value. Once a later execution has been accepted, earlier failed reports can never land.
621
+
622
+
{/* prettier-ignore */}
623
+
<Asidetype="note"title="Use the trigger's scheduled time, not wall-clock time">
624
+
The timestamp must be deterministic across all DON nodes so they agree during consensus. Use the cron trigger's scheduled execution slot time rather than `time.Now()`. Refer to the [cron trigger reference](/cre/reference/sdk/triggers/cron-trigger-go) for the exact field name on the trigger payload.
625
+
</Aside>
626
+
627
+
**Workflow (embed scheduled execution timestamp in the report payload):**
628
+
629
+
```go
630
+
// Use the trigger's scheduled slot time — deterministic across all DON nodes.
631
+
// Refer to the cron trigger reference for the exact field name on cron.Payload.
632
+
scheduledAt:= trigger.ScheduledAt.Unix()
633
+
634
+
// Define your report struct with a ScheduledAt field
635
+
typePaymentReportstruct {
636
+
Recipient common.Address
637
+
Amount *big.Int
638
+
ScheduledAt *big.Int// Monotonic execution timestamp — used to reject stale replays
<Asidetype="note"title="Failed reports can be retried">
534
-
If a report fails (reverts), the forwarder's replay protection allows it to be retried. This is safe because reverts undo all state changes, ensuring no duplicate effects occur in your contract.
690
+
<Asidetype="tip"title="Combining both protections">
691
+
For maximum safety, embed both `chainSelector` and `scheduledAt` in a single report struct. This protects against cross-chain and same-chain replay simultaneously with one encoding step.
535
692
</Aside>
536
693
537
694
### Additional validation layers
@@ -562,6 +719,10 @@ The forwarder address provides baseline security, but you can add additional val
562
719
-**Single workflow**: Use `setExpectedWorkflowId()` to restrict to one specific workflow (highest security)
563
720
-**Multiple workflows from same owner**: Use `setExpectedAuthor()` to restrict to workflows you own
564
721
-**Multiple workflows from different owners**: Implement custom validation logic in your `onReport()` override
722
+
1.**Protect against replay attacks** - For any workflow that performs state-changing actions (payments, minting, position updates):
723
+
- Embed the **target chain selector** in the report payload and verify it in `_processReport` to prevent cross-chain replay
724
+
- Embed a **monotonic execution timestamp** from the cron trigger and reject reports with a timestamp ≤ the last accepted value to prevent same-chain replay on failure
725
+
- See [Replay attacks](#replay-attacks) for complete code examples
565
726
1.**Keep your owner key secure** - The owner can update all permission settings
566
727
1.**Test permission configurations** - Verify your security settings work as expected before production deployment
567
728
1.**Workflow name validation** - Can be used with `setExpectedWorkflowName()` but requires `setExpectedAuthor()` to also be configured for security
Copy file name to clipboardExpand all lines: src/content/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values.mdx
+11Lines changed: 11 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -126,6 +126,17 @@ This report is designed to be passed directly to either:
126
126
-`evm.Client.WriteReport()` for onchain delivery
127
127
-`http.Client` for offchain delivery
128
128
129
+
{/* prettier-ignore */}
130
+
<Asidetype="caution"title="Protect against replay attacks before submitting">
131
+
If your workflow performs state-changing actions (payments, minting, position updates), embed protective metadata in the payload you pass to `runtime.GenerateReport()`:
132
+
133
+
-**Chain selector**: Include the target chain selector so the consumer contract can reject reports replayed on a different chain.
134
+
-**Execution timestamp**: Include the cron trigger's scheduled slot time so the consumer can reject stale reports that were previously reverted and are being replayed by an attacker.
135
+
136
+
See [Replay attacks](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts#replay-attacks) in the Building Consumer Contracts guide for full code examples.
137
+
138
+
</Aside>
139
+
129
140
### 4. Submit the report
130
141
131
142
Now that you have a generated report, choose where to send it:
Copy file name to clipboardExpand all lines: src/content/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-structs.mdx
+11Lines changed: 11 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -122,6 +122,17 @@ This report is designed to be passed directly to either:
122
122
-`evm.Client.WriteReport()` for onchain delivery
123
123
-`http.Client` for offchain delivery
124
124
125
+
{/* prettier-ignore */}
126
+
<Asidetype="caution"title="Protect against replay attacks before submitting">
127
+
If your workflow performs state-changing actions (payments, minting, position updates), add protective fields to your struct before encoding:
128
+
129
+
-**Chain selector**: Include the target chain selector so the consumer contract can reject reports replayed on a different chain.
130
+
-**Execution timestamp**: Include the cron trigger's scheduled slot time so the consumer can reject stale reports that were previously reverted and are being replayed by an attacker.
131
+
132
+
See [Replay attacks](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts#replay-attacks) in the Building Consumer Contracts guide for full code examples.
133
+
134
+
</Aside>
135
+
125
136
The report can now be [submitted onchain](/cre/guides/workflow/using-evm-client/onchain-write/submitting-reports-onchain) or [sent via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http).
0 commit comments