Builder ignores parent's P-chain height, so a leader's maximal height stalls honest proposals
I maintainer di solito rispondono entro 1 giorno
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
- Ambito
- distributed-systems
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
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
- 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) - the verifier
verifyPChainHeightaccepts the block, which is then notarized. It accepts any height from the parent'sPChainHeightup toGetPChainHeightForVerifying(), and in production that upper bound is the current height. (msm/msm.go:713-724) - 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'sPChainHeightas a floor, so the child's height is lower than its parent's. (msm/build_decision.go:49) - honest verifiers reject the child block with
errPChainHeightSmallerThanParent.verifyPChainHeightruns for every non-zero block with the parent's height as the lower bound. (msm/msm.go:498-522) simplex/epoch.gocasts 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.- 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
- msm/msm.go:713–724
- msm/build_decision.go:49
- msm/msm.go:586–632
- instance.go:586–587
- 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
- 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
GetMinimumHeighttrailsGetCurrentHeight, 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
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di ava-labs/Simplex
-
Unverified sealing-block finalization lets a validator redirect a syncing node's replication requestsForse già presa @yacovm l’ha presa oggi. Apertalow security
Difficoltà 4/5 3-5 giorni Idoneità per principianti 45/100
ava-labs/Simplex#666 · 1 assegnatario ·
I maintainer di solito rispondono entro 1 giorno
-
Epoch discovery accepts a sealing block on a head count, letting low-stake validators forge epochsForse già presa @yacovm l’ha presa 1 giorno fa. Apertamedium security
Difficoltà 5/5 Più di una settimana Idoneità per principianti 35/100
I maintainer di solito rispondono entro 1 giorno
-
Failed notarization WAL write lets a node sign both a finalize vote and an empty voteForse già presa @yacovm l’ha presa 3 giorni fa. Apertamedium security
Difficoltà 4/5 3-5 giorni Idoneità per principianti 38/100
I maintainer di solito rispondono entro 1 giorno
-
Honest builders never raise timestamp to parent's, so a leader's future timestamp voids honest proposalsForse già presa @yacovm l’ha presa 3 giorni fa. Apertahigh security
Difficoltà 4/5 3-5 giorni Idoneità per principianti 43/100
I maintainer di solito rispondono entro 1 giorno
-
Auxiliary-info store keeps unbounded data from any unauthenticated peerForse già presa @yacovm l’ha presa 3 giorni fa. Apertahigh security
Difficoltà 4/5 3-5 giorni Idoneità per principianti 56/100
ava-labs/Simplex#652 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di ava-labs/Simplex
Issue simili
-
bug from-studio
Difficoltà 2/5 1-3 ore Idoneità per principianti 65/100
esengine/DeepSeek-Reasonix#14868 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 80/100
project-zot/zot#4636 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
keyxmakerx/Chronicle#1911 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
eugenioenko/ttt#1293 · 1 commento · 1 reazione ·
I maintainer di solito rispondono entro 1 giorno
-
needs/area needs/kind needs/priority
Difficoltà 2/5 1-3 ore Idoneità per principianti 80/100
I maintainer di solito rispondono entro 1 giorno