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

Builder ignores parent's P-chain height, so a leader's maximal height stalls honest proposals

Aperta
#656 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.

  • #670 di @yacovm — aperta

Valutazione

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

Direzione di ricerca

Read msm/build_decision.go at the P-chain height sampling point, then compare it with verifyPChainHeight in msm/msm.go and the parent-height handling in the collecting-approvals and Telock paths. Run TestByzantinePChainHeightStallsHonestBuilders; done means an honest child built on a parent at the current P-chain height passes sm3.VerifyBlock while the proposing height lags.

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

Descrizione

medium security

Details

One malicious validator can stop honest leaders' blocks from being accepted while the P-chain proposal window lags the P-chain tip. Their rounds end empty, and the blacklist can end up blaming them. The attacker must be a validator of the current epoch and wait for its turn as leader. The cause is that the block builder never raises its P-chain height to the parent block's height.

flowchart TD
  n1["malicious validator as round leader"]
  n2["verifyPChainHeight verifier"]
  n3["buildBlockOrTransitionEpoch honest builder"]
  n4["honest leaders' rounds and blacklist standing"]
  n5["clamp to parent's PChainHeight"]
  n1 -->|"proposes block at current height, accepted"| n2
  n3 -->|"sends child with lower height, rejected"| n2
  n2 -->|"empty votes, rounds skipped"| n4
  n5 -->|"not applied"| n3
  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 existing_control
  class n3 vulnerable_code
  class n4 asset
  class n5 missing_control
  1. malicious validator proposes a valid block on its leader turn carrying the current P-chain height. The height is the value a quorum of verifiers has reached, so it breaks no rule. (msm/msm.go:713-724)
  2. the verifier verifyPChainHeight accepts the block, which is then notarized. It accepts any height from the parent's PChainHeight up to GetPChainHeightForVerifying(), and in production that upper bound is the current height. (msm/msm.go:713-724)
  3. the next honest leader's builder builds a child block using the lagging proposal-window height. It samples GetPChainHeightForProposing() (PlatformChain.GetMinimumHeight) and never takes the parent's PChainHeight as a floor, so the child's height is lower than its parent's. (msm/build_decision.go:49)
  4. honest verifiers reject the child block with errPChainHeightSmallerThanParent. verifyPChainHeight runs for every non-zero block with the parent's height as the lower bound. (msm/msm.go:498-522)
  5. simplex/epoch.go casts an empty vote immediately and marks the honest leader as timed out. The round ends empty. A suspected node cannot propose, so the blacklist can keep honest leaders from proposing.
  6. malicious validator repeats on each later turn by building on its own block at the then-current height. This pushes the stall further out, until the honest nodes' minimum height passes the attacker's value. Meanwhile its own blocks are the only ones accepted.

Evidence

  1. msm/msm.go:713–724
  2. msm/build_decision.go:49
  3. msm/msm.go:586–632
  4. instance.go:586–587
  5. msm/msm.go:498–522

Impact

While the stall lasts, no honest validator can get a block notarized. The attacker can extend the stall on each of its turns, so its own blocks become the only ones accepted and it decides which transactions get in. Honest leaders can be marked timed out and blacklisted. No data is disclosed or changed, and finalized blocks stay consistent. The limit is set by the host's proposal-window lag and by how often the attacker leads.

Reproduction steps

  1. The attacker is a validator of the current epoch, in the threat model of fewer than a third Byzantine validators. It needs a turn as round leader and proposes an otherwise valid block. The attack works only while the host's GetMinimumHeight trails GetCurrentHeight, which depends on recent P-chain activity. How long the lag lasts was not checked, because avalanchego is not a module dependency. The same mismatch can also happen with no attacker, when one honest node's minimum height is ahead of another's. The collecting-approvals and Telock paths copy the parent's height (msm/msm.go:1074, :1481) and are not affected.

Recommended fix

The honest builder embeds the locally sampled proposal-window height (build_decision.go:49, msm.go:590/626/632) without using the parent's PChainHeight as a floor. The verifier (msm.go:713-724) rejects any height below the parent's. A leader proposing at the verifier's upper bound therefore makes every honest successor unverifiable.

Fix criteria: An honest builder always produces a block that honest verifiers accept, whatever the parent's PChainHeight. The embedded height is at least the parent's, for example max(parent.PChainHeight, sampled). Alternatively, the verifier's accepted range is tied to what honest builders emit. The reproduction test TestByzantinePChainHeightStallsHonestBuilders is the check. After the fix, the honest block built on a parent carrying the current height is accepted by sm3.VerifyBlock.

Status on main

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

The builder still embeds the raw sampled proposing height with no floor at the parent's PChainHeight. That height comes from blockBuildingDecider.getPChainHeight = GetPChainHeightForProposing (msm/build_decision.go:49, msm.go:839), with instance.go:586 wiring PlatformChain.GetMinimumHeight. It is used in wrapBlock at msm/msm.go:590 (empty-block path), :625 and :631. The verifier requires proposed >= parent.PChainHeight and <= GetPChainHeightForVerifying (GetCurrentHeight). See verifyPChainHeight msm.go:713-724, called for every non-zero block at msm.go:510 and again at :1542. So a parent at the current height makes honest children fail with errPChainHeightSmallerThanParent while minimum height < parent height. No matching issue or PR found.


Severity: MEDIUM
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_013C4gA1DRV6hTQiUYfqUSUx

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.