Summary
The IBlockHashRetain.vyi
interface exposes critical functions without proper access controls, which could lead to unauthorized manipulation of block hash data.
Vulnerability Details
Current implementation exposes unprotected external functions:
@external
def commit() -> uint256:
"""
@notice Commit (and apply) a block hash/state root.
@dev Same as `apply()` but saves committer
"""
...
@external
def apply() -> uint256:
"""
@notice Apply a block hash/state root.
"""
...
Critical issues:
No role-based access control for committers
Missing validation for trusted sources
No whitelist mechanism for authorized callers
Unrestricted access to state-changing functions
No admin oversight for critical operations
Impact
Unauthorized actors can manipulate block hash data
No separation of privileges between different roles
Potential for malicious data injection
Compromise of oracle data integrity
Risk to all dependent protocols relying on block hash data
Tools Used
Recommendations
Implement role-based access control:
# Role definitions
ADMIN_ROLE: constant(bytes32) = keccak256("ADMIN_ROLE")
COMMITTER_ROLE: constant(bytes32) = keccak256("COMMITTER_ROLE")
VALIDATOR_ROLE: constant(bytes32) = keccak256("VALIDATOR_ROLE")
@external
def commit() -> uint256:
"""
@notice Commit a block hash with role check
"""
assert self.has_role(COMMITTER_ROLE, msg.sender), "Not authorized committer"
# ... existing logic
@external
def apply() -> uint256:
"""
@notice Apply with role validation
"""
assert self.has_role(VALIDATOR_ROLE, msg.sender), "Not authorized validator"
# ... existing logic
@external
def add_committer(_address: address):
"""
@notice Add authorized committer
"""
assert self.has_role(ADMIN_ROLE, msg.sender), "Not admin"
self.grant_role(COMMITTER_ROLE, _address)
Add whitelisting mechanism:
whitelisted_sources: public(HashMap[address, bool])
@external
def whitelist_source(_source: address, _status: bool):
"""
@notice Whitelist trusted data sources
"""
assert self.has_role(ADMIN_ROLE, msg.sender), "Not admin"
self.whitelisted_sources[_source] = _status
Implement two-step privilege transfers:
@external
def transfer_role(_role: bytes32, _new_address: address):
"""
@notice Two-step role transfer
"""
assert self.has_role(ADMIN_ROLE, msg.sender), "Not admin"
self.role_transfer_pending[_role] = _new_address
@external
def accept_role(_role: bytes32):
"""
@notice Accept pending role transfer
"""
assert self.role_transfer_pending[_role] == msg.sender, "Not pending recipient"
self.grant_role(_role, msg.sender)
These changes ensure proper access control hierarchy and protect against unauthorized access while maintaining operational flexibility.