50399 sc low broken access control in particular contract functions due lack of pause unpause functionality
Submitted on Jul 24th 2025 at 08:43:02 UTC by @KKam86 for Attackathon | Plume Network
Report ID: #50399
Report Type: Smart Contract
Report severity: Low
Target: https://github.com/immunefi-team/attackathon-plume-network-nucleus-boring-vault/blob/main/src/base/Roles/TellerWithMultiAssetSupportPredicateProxy.sol
Impacts:
Contract fails to deliver promised returns, but doesn't lose value
Description
Brief/Intro
Contract TellerWithMultiAssetSupportPredicateProxy incorrectly integrates OpenZeppelin Pausable. As a result the contract does not expose pause/unpause functionality that is responsible for stopping particular contract functions in emergency states. This can lead to unwanted situations like risky user deposits during an emergency.
Vulnerability Details
TellerWithMultiAssetSupportPredicateProxy imports and inherits OpenZeppelin Pausable:
import {Pausable} from "@openzeppelin/contracts/utils/Pausable.sol";
contract TellerWithMultiAssetSupportPredicateProxy is
Ownable,
ReentrancyGuard,
PredicateClient,
PausableHowever, Pausable only provides internal functions _pause() and _unpause():
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}No public/external functions are exposed in the parent or this contract to call _pause() / _unpause(). The contract contains checks like:
if (paused()) {
revert TellerWithMultiAssetSupportPredicateProxy__Paused();
}but with no way to change _paused from its initial false value, these checks will never trigger. Pausable initializes _paused to false:
constructor() {
_paused = false;
}
function paused() public view virtual returns (bool) {
return _paused;
}Thus owner cannot activate the pause state and cannot stop functions that are intended to be blocked during emergencies.
Impact Details
Deposits during emergencies
Depositing funds during emergency situations can be risky, especially when the bug is discovered and triggered by bad actors. Users can potentially lose funds. Deposit functions should clearly be not accessible during contract pause:
* @notice Allows users to deposit into the BoringVault, if the teller contract is not pausedReferences
https://github.com/immunefi-team/attackathon-plume-network-nucleus-boring-vault/blob/main/src/base/Roles/TellerWithMultiAssetSupportPredicateProxy.sol?utm_source=immunefi#L20
https://github.com/immunefi-team/attackathon-plume-network-nucleus-boring-vault/blob/main/src/base/Roles/TellerWithMultiAssetSupportPredicateProxy.sol?utm_source=immunefi#L78-L80
https://github.com/immunefi-team/attackathon-plume-network-nucleus-boring-vault/blob/main/src/base/Roles/TellerWithMultiAssetSupportPredicateProxy.sol?utm_source=immunefi#L133-L135
https://github.com/immunefi-team/attackathon-plume-network-nucleus-boring-vault/blob/main/src/base/Roles/TellerWithMultiAssetSupportPredicateProxy.sol?utm_source=immunefi#L57
https://github.com/OpenZeppelin/openzeppelin-contracts/blob/acd4ff74de833399287ed6b31b4debf6b2b35527/contracts/utils/Pausable.sol#L43-L45
https://github.com/OpenZeppelin/openzeppelin-contracts/blob/acd4ff74de833399287ed6b31b4debf6b2b35527/contracts/utils/Pausable.sol#L74-L76
https://github.com/OpenZeppelin/openzeppelin-contracts/blob/acd4ff74de833399287ed6b31b4debf6b2b35527/contracts/utils/Pausable.sol#L103-L106
https://github.com/OpenZeppelin/openzeppelin-contracts/blob/acd4ff74de833399287ed6b31b4debf6b2b35527/contracts/utils/Pausable.sol#L115-L118
Proof of Concept
Was this helpful?