Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

Honest builders never raise timestamp to parent's, so a leader's future timestamp voids honest proposals

Aperta
#654 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 1 giorno

@yacovm ci sta già lavorando.

Dal 27/10/2026.

  • #669 di @yacovm — aperta

Valutazione

Difficoltà
4/5
Tempo stimato
3-5 giorni
Idoneità per principianti
43/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
go

Direzione di ricerca

Read the builders and timestamp validation in msm/msm.go, starting with buildBlockOrTransitionEpoch and verifyTimestamp; then check the other builder paths at the cited locations for normal, collecting-approvals, Telock, and new-epoch blocks. Reproduce the stated case with a parent timestamped T+9s and verify the built block against its actual parent. Done means every honest builder's block passes VerifyBlock in that case.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

high security

Details

One Byzantine validator can stop honest leaders from getting blocks accepted, so the chain advances mostly through the attacker's own blocks. It needs only its normal turn as round leader. Honest builders stamp blocks with their own clock and never raise it to the parent's timestamp, so a future-dated parent makes their blocks fail verifyTimestamp.

flowchart TD
  n1["Byzantine validator acting as leader"]
  n2["honest builders in msm/msm.go (stamp raw sm.GetTime)"]
  n3["verifyTimestamp"]
  n4["honest leaders' proposals and chain progress"]
  n5["clamp of timestamp to parent's"]
  n1 -->|"future-dated block accepted"| n3
  n2 -->|"child stamped below parent"| n3
  n3 -->|"rejects honest blocks, rounds skipped"| n4
  n5 -->|"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 existing_control
  class n4 asset
  class n5 missing_control
  1. Byzantine validator proposes a block stamped up to about 10 seconds ahead of real time on its turn as leader. The verifier accepts any timestamp up to TimeSkewLimit ahead, and production wiring sets no TimeSkewLimit, so the default maxSkew = 10s applies. (instance.go:570-591)
  2. verifyTimestamp accepts the future-dated block, which is then notarized. It rejects a timestamp below the parent's but allows one up to now + timeSkewLimit. (msm/msm.go:526-540)
  3. the next honest leader's builder stamps its child block with the raw local clock. buildBlockOrTransitionEpoch uses sm.GetTime() and never raises it to the parent's timestamp, so the child is stamped earlier than its parent. (msm/msm.go:617-632)
  4. the honest leader's BuildBlock proposes the block without verifying it. The leader's own node does not run VerifyBlock on what it builds, so only other nodes catch the bad timestamp. (adapters.go:263-277)
  5. honest verifiers reject the block with errTimestampDecreasing. verifyNonZeroBlock runs verifyTimestamp first on every non-zero proposal, against the real parent. (msm/msm.go:498-504)
  6. honest nodes empty-vote at once, so the round is skipped. triggerEmptyBlockNotarization is called on the verification failure, and the parent stays the attacker's block. (simplex/epoch.go:2227-2242)
  7. Byzantine validator builds another future-dated child on its next turn. LeaderForRound is round-robin over round numbers, so the attacker leads again after a fixed number of rounds, skipped ones included. (simplex/epoch.go:3827-3830)

Evidence

  1. msm/msm.go:617–632
  2. msm/msm.go:1076–1077
  3. msm/msm.go:1477–1482
  4. msm/msm.go:526–540
  5. msm/msm.go:498–504
  6. external.go:62–81
  7. adapters.go:263–277
  8. simplex/epoch.go:2227–2242
  9. simplex/epoch.go:3827–3830
  10. instance.go:570–591

Impact

Honest leaders' proposals are rejected for up to TimeSkewLimit (10s) after each attacker turn. If the attacker's turns recur inside that window, honest leaders never land a block. The chain then advances only through attacker-built blocks, at a fraction of its normal rate, and the attacker picks every included transaction. No data is disclosed or changed, and every finalized block is valid.

Reproduction steps

  1. The attacker is a single Byzantine validator, which the report treats as the primary threat actor. It needs only its own round-robin turn as leader. Only a validator's signed leader proposal is processed. Whether the attack repeats without end depends on how soon the attacker's turns recur. That depends on validator-set size and network delay. With small validator sets a failed round ends after one network delay, so the attacker's turns can recur inside the 10 second window. Each turn is bounded by TimeSkewLimit.

Recommended fix

The builders at msm/msm.go:588, :617, :1076 and :1478 stamp blocks with the raw local clock. The verifier requires timestamps that never decrease but accepts a parent up to TimeSkewLimit in the future. Honest builders therefore make blocks that honest verifiers reject.

Fix criteria: Every block an honest node builds passes verifyTimestamp against its actual parent, the block named by metadata.Prev, for example by using a timestamp at least the parent's. That parent is not the sealing block that buildBlockEpochSealed passes on. Test: with a verifier and an honest builder at time T, a block the honest builder builds on a parent stamped T+9s is accepted by VerifyBlock. Check this for normal, collecting-approvals, Telock and new-epoch blocks.

Status on main

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

Every builder still stamps blocks with sm.GetTime() directly and never clamps to the parent's timestamp: msm/msm.go:588, 617, 1076 and 1478, via wrapBlock at msm/msm.go:1422. verifyTimestamp (msm/msm.go:526-541) rejects any block whose timestamp is below its parent's (531-533), but accepts timestamps up to now+TimeSkewLimit. The default limit is 10s (msm/msm.go:24, 232-233), and production wiring uses GetTime: time.Now (instance.go:571). No issue or PR tracks this.


Severity: HIGH
Status: Open
Category: Improper input validation
CWE: CWE-20
Repository: ava-labs/Simplex
Branch: main
Date created: 2026-10-26
Claude Security finding: https://claude.ai/security/findings/find_01PE8Rjj8nHkYYyQHYY372eT

Lingua principale
Go
Stelle
22
Fork
4
Merge medio
1g 16h
PR unite (30g)
35

Preparare l'ambiente

Questo progetto non fornisce container di sviluppo, Dockerfile né guida per i contributori, quindi l'ambiente è a tuo carico: parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di ava-labs/Simplex

Tutte le issue di ava-labs/Simplex

Issue simili

Altre issue su Go

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.