F-2026-0002·wrong-variable-used
confirmingPublicKeyHash derived from wrong public key causes all key pair registrations to revert after inception
TL;DR
validateTransaction computes confirmingPublicKeyHash from unconfirmed.publicKey instead of confirming.publicKey, so the subsequent equality check is always false and every key pair registration reverts after the inception key.
Severity
CRITICAL
Impact
HIGH
Likelihood
HIGH
Method
MManual review
CAT.
Complexity
LOW
Exploitability
HIGH
02Section · Description
Description
NOTE: this bug is fixed in
KeyLogRegistryUpgrade.sol, andKeyLogRegistry.solshould not be used in production!
In KeyLogRegistry.sol, validateTransaction computes the confirming
key's hash from the wrong public key:
solidity
// KeyLogRegistry.sol line 183-184address unconfirmedPublicKeyHash =getAddressFromPublicKey(unconfirmed.publicKey);address confirmingPublicKeyHash =getAddressFromPublicKey(unconfirmed.publicKey); // BUG: should be confirming.publicKey
Both hashes are derived from unconfirmed.publicKey. The subsequent check
at line 217:
solidity
require(getAddressFromPublicKey(confirming.publicKey) == confirmingPublicKeyHash, "Invalid confirmingPublicKey");
requires hash(confirming.publicKey) == hash(unconfirmed.publicKey), which
is always false for valid key pairs.
Vulnerable Scenario
- Deploy
KeyLogRegistrybehind a UUPS proxy. - Register key A via
registerKeyLog(inception), succeeds becauseisPair=falsereturns at line 214 before the buggy check at line 217 is reached. - Attempt key rotation by calling
registerKeyLogPair(keyB, keyC)where:- Key B is the next rotation key (
prevPublicKeyHash = hash(A)) - Key C is the confirming key (
prevPublicKeyHash = hash(B))
- Key B is the next rotation key (
validateTransactioncomputes:unconfirmedPublicKeyHash = hash(B)(line 183, correct)confirmingPublicKeyHash = hash(B)(line 184, BUG, should behash(C))
- Line 217 evaluates:
require(hash(C) == hash(B)), always false, reverts with"Invalid confirmingPublicKey". - Key chain is permanently stuck at inception. No rotation, wrap, or unwrap is possible.
03Section · Impact
Impact
- All
registerKeyLogPaircalls revert with"Invalid confirmingPublicKey". - No key rotation pairs can be registered, key chains are permanently stuck after inception.
- All wrap/unwrap operations that require pair registration are blocked.
- Bridge is non-functional for any operation requiring key pair rotation.
04Section · Recommendation
Recommendation
Fixed in KeyLogRegistryUpgrade.sol line 184:
solidity
address confirmingPublicKeyHash =getAddressFromPublicKey(confirming.publicKey); // FIXED
05Section · Resolution
Resolution
YadaCoin, Confirmed.
Zealynx, Fixed.
Status
Fixed