F-2026-0014·silent-truncation

Silent chain truncation at 1000 entries causes getLatestChainEntry to return stale data with no error indication

Fixedbridgecross-chainkey-registrygithub.com/pdxwebdev/yadakeyeventwallet
TL;DR

_buildChainFromHash allocates a fixed 1000-element array and silently breaks the forward traversal when the index reaches the limit, causing getLatestChainEntry to return log[999] as if it were the latest entry.

Severity
LOW
Impact
HIGH
Likelihood
LOW
Method
MManual review
CAT.
Complexity
MEDIUM
Exploitability
LOW
02Section · Description

Description

_buildChainFromHash allocates a fixed-size array of 1000 elements and silently breaks the forward traversal when the index reaches the limit:

solidity
KeyLogEntry[] memory log = new KeyLogEntry[](1000);
// ...
if (logIndex >= log.length) {
break;
}

If a key chain exceeds 1000 entries (~500 pair rotations), the function returns a truncated array. getLatestChainEntry then returns log[999], not the actual latest entry, with no revert and no indication that the data is stale.

Every downstream consumer silently operates on incorrect data:

  • isValidOwnershipTransfer (line 364) validates against the wrong entry, potentially accepting or rejecting ownership transfers incorrectly.
  • rotateToPublicKey in Bridge reads the wrong prerotatedKeyHash, transferring Bridge ownership to the wrong address.
  • transferBalanceToLatestKey in Bridge sends all token balances to an outdated key.
  • registerKeyPairWithTransfer in Bridge routes permits to the wrong prerotatedKeyHash.

The failure is completely silent, no revert, no event, no return flag. The bool return from getLatestChainEntry is true because the array is non-empty, even though the entry is stale.

While 500 pair rotations is unlikely short-term, the protocol provides no guard against reaching this boundary over its deployment lifetime, and the consequences are catastrophic if it does.

03Section · Recommendation

Recommendation

Either revert if the chain exceeds the limit:

solidity
if (logIndex >= log.length) {
revert("Chain exceeds maximum length");
}

…or remove the bounded allocation entirely (preferred, see the O(1) mapping approach in [F-2026-0009]).

04Section · Resolution

Resolution

YadaCoin, Confirmed.

Zealynx, Fixed.

Status
Fixed
F-2026-0014

oog
zealynx

Smart Contract Security Digest

Monthly exploit breakdowns, audit checklists, and DeFi security research — straight to your inbox

© 2026 Zealynx