Skip to content

[runtime]: Pin the anchor slot in non-existence proof sibling verification#992

Merged
Wizdave97 merged 2 commits into
mainfrom
fix/pharos-spv-nonexistence-anchor-pin
Jun 25, 2026
Merged

[runtime]: Pin the anchor slot in non-existence proof sibling verification#992
Wizdave97 merged 2 commits into
mainfrom
fix/pharos-spv-nonexistence-anchor-pin

Conversation

@Wizdave97

Copy link
Copy Markdown
Member

verify_non_existence_proof's non-empty-terminal branch set parent_end = proof_nodes.len() - 1, excluding the terminal/anchor from parent_nodes. Each sibling's combined walk (parent_nodes ++ sib.proof_path) therefore reconnected at the terminal's parent and could descend through an unrelated parent slot instead of anchor.slot[idx]. Combined with SkipEmpty internal-node hashing (position-independent over the ordered non-zero slots), this let an attacker relabel the queried slot's child into a free slot and "pin" it with a leaf from a different subtree — forging non-membership of a key that genuinely exists, which on the timeout path refunds an already-delivered cross-chain message.

Include the terminal in parent_nodes (proof_nodes.len()) so every sibling walk is forced through anchor.slot[idx], matching the all-zero-terminal branch. Adds a regression test asserting a divergent (parent-routed) sibling is rejected while the honest sibling still verifies.

…tion

verify_non_existence_proof's non-empty-terminal branch set
parent_end = proof_nodes.len() - 1, excluding the terminal/anchor from
parent_nodes. Each sibling's combined walk (parent_nodes ++ sib.proof_path)
therefore reconnected at the terminal's parent and could descend through an
unrelated parent slot instead of anchor.slot[idx]. Combined with SkipEmpty
internal-node hashing (position-independent over the ordered non-zero slots),
this let an attacker relabel the queried slot's child into a free slot and
"pin" it with a leaf from a different subtree — forging non-membership of a
key that genuinely exists, which on the timeout path refunds an
already-delivered cross-chain message.

Include the terminal in parent_nodes (proof_nodes.len()) so every sibling
walk is forced through anchor.slot[idx], matching the all-zero-terminal
branch. Adds a regression test asserting a divergent (parent-routed) sibling
is rejected while the honest sibling still verifies.

Reported via HackenProof (HYPERBR-1962).
@Wizdave97 Wizdave97 changed the title [pharos]: Pin the anchor slot in non-existence proof sibling verification [runtime]: Pin the anchor slot in non-existence proof sibling verification Jun 25, 2026
@Wizdave97 Wizdave97 requested a review from dharjeezy June 25, 2026 16:55
@Wizdave97 Wizdave97 merged commit 0f78b9f into main Jun 25, 2026
10 checks passed
@Wizdave97 Wizdave97 deleted the fix/pharos-spv-nonexistence-anchor-pin branch June 25, 2026 16:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants