Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

Replicated empty notarization lets a previous-epoch Telock become the new epoch's chain tip

Đang mở
#663 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

Chưa có ai nhận issue này.

Đánh giá

Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức phù hợp với người mới
38/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
go

Hướng nghiên cứu

Start with processQuorumRound and QuorumRound.GetEpoch in simplex/epoch.go and common/msg.go, then trace the existing quorum verification and replicated response handling described in the issue. Check how the block, notarization, finalization, and empty notarization epochs are validated before any state is stored or persisted. Done means a mixed epoch quorum round is rejected; the issue’s test sketch expects the WAL to remain unchanged and Metadata().Prev to stay unchanged.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

medium security

Details

A validator of the new epoch can halt the whole chain for every validator, and a restart does not fix it. It needs the old epoch's notarization for its first Telock, and enough validator overlap for that old certificate to verify. The cause is processQuorumRound, which takes the epoch of a replicated round from its empty notarization and never checks the block's own epoch.

flowchart TD
  n1["attacker validator of the new epoch"]
  n2["processQuorumRound"]
  n3["honest validators' chain state"]
  n4["epoch comparison of block, notarization and empty notarization"]
  n5["ReplicationResponse handling in HandleMessage"]
  n1 -->|"sends mixed quorum round"| n5
  n5 -->|"skips the epoch filter"| n2
  n2 -->|"stores old Telock as chain tip"| n3
  n4 -->|"not applied"| n2
  classDef actor stroke:#2563eb,stroke-width:2px
  classDef vulnerable_code stroke:#dc2626,stroke-width:2px
  classDef existing_control stroke:#16a34a,stroke-width:2px
  classDef missing_control stroke:#dc2626,stroke-width:2px,stroke-dasharray:5 5
  classDef asset stroke:#9333ea,stroke-width:2px
  classDef component stroke:#6b7280,stroke-width:1px
  class n1 actor
  class n2 vulnerable_code
  class n3 asset
  class n4 missing_control
  class n5 component
  1. attacker validator builds a mixed ReplicationResponse quorum round. It combines the previous epoch's Telock block and its notarization with a genuine new-epoch empty notarization for the same round.
  2. attacker validator sends the response to the validators that are already in the new epoch. Replication responses skip the per-message epoch filter in HandleMessage, so no epoch check runs at this point. (simplex/epoch.go:186-190)
  3. processQuorumRound accepts the quorum round after one epoch check. QuorumRound.GetEpoch returns the empty notarization's epoch first, so the current epoch hides the old epoch of the block. (simplex/epoch.go:3628-3633)
  4. verifyQuorumRound verifies the old notarization against the current validator set. It passes when the signers are still validators with the same keys and form a quorum of the new set, and VerifyQCConsistentWithBlock only compares rounds, not epochs. (simplex/epoch.go:3576-3601)
  5. createNotarizedBlockVerificationTask stores the old-epoch Telock as the newest notarized block and restarts the round. It writes the block and notarization to e.rounds and the WAL, and Verify(OnlyVMVerifyOpt) returns at once for a Telock. (simplex/epoch.go:2376-2457)
  6. metadata() builds the next proposal on the injected Telock at seq k+2. The new epoch's chain is now built on the Telock instead of on the sealing block. (simplex/epoch.go:2749-2777)
  7. indexFinalizations waits forever for seq k+1 after the new block is finalized. CallbackStorage.Index skips Telocks, so seq k+1 is never committed. Blocks keep being finalized but none is committed. (simplex/epoch.go:1503-1544)

Evidence

  1. simplex/epoch.go:3628–3633
  2. common/msg.go:351–361
  3. common/msg.go:383–421
  4. simplex/epoch.go:3576–3601
  5. simplex/epoch.go:186–190
  6. simplex/epoch.go:2376–2457
  7. external.go:62–79
  8. simplex/epoch.go:2749–2777
  9. simplex/epoch.go:682–706
  10. msm/msm.go:1469–1489
  11. simplex/epoch.go:1503–1544
  12. adapters.go:59–75
  13. simplex/epoch.go:3492–3522

Impact

The chain halts for every validator, because no block can be committed once a block built on the Telock is finalized. A restart does not recover it, since the WAL filter keeps the new-epoch blocks built on the Telock. No conflicting block is committed and nothing is disclosed, so the harm to integrity is limited to corrupted consensus state.

Reproduction steps

  1. The attacker must be a validator of the new epoch. It must hold the old epoch's notarization, or the individual votes, for the old epoch's first Telock. Conditions outside its control: that Telock was notarized, and the old certificate verifies against the new validator set. The second condition needs validator overlap, which an incremental validator-set change gives. The attacker can re-aggregate the old votes to pick signers that fit. The new epoch's first round must also get an empty notarization, and the attacker can force this when it leads that round. As the empty notarization forms, it sends the mixed response to every validator. The next leader builds on the Telock, and the poisoned validators notarize and finalize that block. No user action is needed. A variant with a finalized Telock sets e.lastBlock to the Telock directly. Poisoned honest nodes also serve the mixed round to peers. Replies for seq k+1 carry no empty notarization and are dropped.

Recommended fix

processQuorumRound relies on QuorumRound.GetEpoch, which lets a current-epoch empty notarization vouch for a block, notarization or finalization of another epoch. VerifyQCConsistentWithBlock never compares the empty notarization's epoch with the block's. The old certificate then verifies against the current validators.

Fix criteria: Every part of a replicated quorum round (block header, notarization, finalization and empty notarization) carries the node's current epoch. Otherwise the whole quorum round is dropped before anything is stored, persisted, voted on or used by metadata(). The test sketch confirms it: an epoch-4 block plus an epoch-5 empty notarization delivered to an epoch-5 node leaves the WAL without its records and Metadata().Prev unchanged.

Status on main

Re-checked against main at 90995e0 on 2026-10-26; still present:

processQuorumRound (simplex/epoch.go:3618-3653) checks only QuorumRound.GetEpoch(), which returns the empty notarization's epoch first (common/msg.go:351-361). VerifyQCConsistentWithBlock (common/msg.go:383-421) compares round and digest/header but never compares the empty notarization's epoch with the block's epoch. verifyQuorumRound (epoch.go:3576-3601) verifies the old-epoch notarization QC against the current validator set (VerifyQC in util.go:53-76 does no epoch check). createNotarizedBlockVerificationTask (epoch.go:2376-2457) also has no block-epoch check. Rounds continue across epochs (setMetadataFromStorage sets e.round = lastBlock.Round+1, epoch.go:688-689), so Telock rounds can collide with new-epoch rounds. Exploitability needs validator overlap.


Severity: MEDIUM
Status: Open
Category: Capture-replay
CWE: CWE-294
Repository: ava-labs/Simplex
Branch: main
Date created: 2026-10-26
Claude Security finding: https://claude.ai/security/findings/find_01Txb4brf7Qje2X7Lr7cVe1E

Ngôn ngữ chính
Go
Star
22
Fork
4
Merge trung bình
1 ngày 17 giờ
Pull request đã merge (30 ngày)
32

Chuẩn bị môi trường

Dự án này không cung cấp dev container, Dockerfile hay hướng dẫn đóng góp, nên bạn cần tự thiết lập môi trường: hãy bắt đầu từ README và xem hướng dẫn đóng góp lần đầu của chúng tôi để biết các bước chung.

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của ava-labs/Simplex

Tất cả issue của ava-labs/Simplex

Issue tương tự

Thêm issue về Go

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.